Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add availability_template option to all template platforms #25891

Closed
wants to merge 12 commits into from
24 changes: 24 additions & 0 deletions homeassistant/components/template/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from homeassistant.const import (
ATTR_FRIENDLY_NAME,
ATTR_ENTITY_ID,
CONF_AVAILABILITY_TEMPLATE,
CONF_VALUE_TEMPLATE,
CONF_ICON_TEMPLATE,
CONF_ENTITY_PICTURE_TEMPLATE,
Expand All @@ -36,6 +37,7 @@
vol.Required(CONF_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_ICON_TEMPLATE): cv.template,
vol.Optional(CONF_ENTITY_PICTURE_TEMPLATE): cv.template,
vol.Optional(CONF_AVAILABILITY_TEMPLATE): cv.template,
vol.Optional(ATTR_FRIENDLY_NAME): cv.string,
vol.Optional(ATTR_ENTITY_ID): cv.entity_ids,
vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA,
Expand All @@ -57,6 +59,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
value_template = device_config[CONF_VALUE_TEMPLATE]
icon_template = device_config.get(CONF_ICON_TEMPLATE)
entity_picture_template = device_config.get(CONF_ENTITY_PICTURE_TEMPLATE)
availability_template = device_config.get(CONF_AVAILABILITY_TEMPLATE)
entity_ids = set()
manual_entity_ids = device_config.get(ATTR_ENTITY_ID)

Expand All @@ -66,6 +69,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
(CONF_VALUE_TEMPLATE, value_template),
(CONF_ICON_TEMPLATE, icon_template),
(CONF_ENTITY_PICTURE_TEMPLATE, entity_picture_template),
(CONF_AVAILABILITY_TEMPLATE, availability_template),
):
if template is None:
continue
Expand Down Expand Up @@ -111,6 +115,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
value_template,
icon_template,
entity_picture_template,
availability_template,
entity_ids,
delay_on,
delay_off,
Expand All @@ -136,6 +141,7 @@ def __init__(
value_template,
icon_template,
entity_picture_template,
availability_template,
entity_ids,
delay_on,
delay_off,
Expand All @@ -148,12 +154,14 @@ def __init__(
self._template = value_template
self._state = None
self._icon_template = icon_template
self._availability_template = availability_template
self._entity_picture_template = entity_picture_template
self._icon = None
self._entity_picture = None
self._entities = entity_ids
self._delay_on = delay_on
self._delay_off = delay_off
self._available = True

async def async_added_to_hass(self):
"""Register callbacks."""
Expand Down Expand Up @@ -208,6 +216,11 @@ def should_poll(self):
"""No polling needed."""
return False

@property
def available(self):
"""Availability indicator."""
return self._available

@callback
def _async_render(self):
"""Get the state of template."""
Expand All @@ -225,6 +238,17 @@ def _async_render(self):
return
_LOGGER.error("Could not render template %s: %s", self._name, ex)

if self._availability_template is not None:
try:
result = self._availability_template.async_render()
self._available = result == "true"
except TemplateError as ex:
_LOGGER.error(ex)
self._available = True
except ValueError as ex:
_LOGGER.error(ex)
self._available = True
grillp marked this conversation as resolved.
Show resolved Hide resolved

for property_name, template in (
("_icon", self._icon_template),
("_entity_picture", self._entity_picture_template),
Expand Down
29 changes: 29 additions & 0 deletions homeassistant/components/template/cover.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
CONF_ENTITY_ID,
EVENT_HOMEASSISTANT_START,
MATCH_ALL,
CONF_AVAILABILITY_TEMPLATE,
CONF_VALUE_TEMPLATE,
CONF_ICON_TEMPLATE,
CONF_DEVICE_CLASS,
Expand Down Expand Up @@ -74,6 +75,7 @@
vol.Exclusive(
CONF_VALUE_TEMPLATE, CONF_VALUE_OR_POSITION_TEMPLATE
): cv.template,
vol.Optional(CONF_AVAILABILITY_TEMPLATE): cv.template,
vol.Optional(CONF_POSITION_TEMPLATE): cv.template,
vol.Optional(CONF_TILT_TEMPLATE): cv.template,
vol.Optional(CONF_ICON_TEMPLATE): cv.template,
Expand Down Expand Up @@ -103,6 +105,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
position_template = device_config.get(CONF_POSITION_TEMPLATE)
tilt_template = device_config.get(CONF_TILT_TEMPLATE)
icon_template = device_config.get(CONF_ICON_TEMPLATE)
availability_template = device_config.get(CONF_AVAILABILITY_TEMPLATE)
entity_picture_template = device_config.get(CONF_ENTITY_PICTURE_TEMPLATE)
device_class = device_config.get(CONF_DEVICE_CLASS)
open_action = device_config.get(OPEN_ACTION)
Expand Down Expand Up @@ -144,6 +147,11 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
if str(temp_ids) != MATCH_ALL:
template_entity_ids |= set(temp_ids)

if availability_template is not None:
temp_ids = availability_template.extract_entities()
if str(temp_ids) != MATCH_ALL:
template_entity_ids |= set(temp_ids)

if not template_entity_ids:
template_entity_ids = MATCH_ALL

Expand All @@ -160,6 +168,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
tilt_template,
icon_template,
entity_picture_template,
availability_template,
open_action,
close_action,
stop_action,
Expand Down Expand Up @@ -192,6 +201,7 @@ def __init__(
tilt_template,
icon_template,
entity_picture_template,
availability_template,
open_action,
close_action,
stop_action,
Expand All @@ -213,6 +223,7 @@ def __init__(
self._icon_template = icon_template
self._device_class = device_class
self._entity_picture_template = entity_picture_template
self._availability_template = availability_template
self._open_script = None
if open_action is not None:
self._open_script = Script(hass, open_action)
Expand All @@ -235,6 +246,7 @@ def __init__(
self._position = None
self._tilt_value = None
self._entities = entity_ids
self._available = True

if self._template is not None:
self._template.hass = self.hass
Expand All @@ -246,6 +258,8 @@ def __init__(
self._icon_template.hass = self.hass
if self._entity_picture_template is not None:
self._entity_picture_template.hass = self.hass
if self._availability_template is not None:
self._availability_template.hass = self.hass

async def async_added_to_hass(self):
"""Register callbacks."""
Expand Down Expand Up @@ -332,6 +346,11 @@ def should_poll(self):
"""Return the polling state."""
return False

@property
def available(self) -> bool:
"""Return if the device is available."""
return self._available

async def async_open_cover(self, **kwargs):
"""Move the cover up."""
if self._open_script:
Expand Down Expand Up @@ -453,6 +472,16 @@ async def async_update(self):
except ValueError as ex:
_LOGGER.error(ex)
self._tilt_value = None
if self._availability_template is not None:
try:
result = self._availability_template.async_render()
self._available = result == "true"
except TemplateError as ex:
_LOGGER.error(ex)
self._available = True
except ValueError as ex:
_LOGGER.error(ex)
self._available = True

for property_name, template in (
("_icon", self._icon_template),
Expand Down
27 changes: 27 additions & 0 deletions homeassistant/components/template/fan.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
)
from homeassistant.const import (
CONF_FRIENDLY_NAME,
CONF_AVAILABILITY_TEMPLATE,
CONF_VALUE_TEMPLATE,
CONF_ENTITY_ID,
STATE_ON,
Expand Down Expand Up @@ -58,6 +59,7 @@
vol.Optional(CONF_SPEED_TEMPLATE): cv.template,
vol.Optional(CONF_OSCILLATING_TEMPLATE): cv.template,
vol.Optional(CONF_DIRECTION_TEMPLATE): cv.template,
vol.Optional(CONF_AVAILABILITY_TEMPLATE): cv.template,
vol.Required(CONF_ON_ACTION): cv.SCRIPT_SCHEMA,
vol.Required(CONF_OFF_ACTION): cv.SCRIPT_SCHEMA,
vol.Optional(CONF_SET_SPEED_ACTION): cv.SCRIPT_SCHEMA,
Expand Down Expand Up @@ -86,6 +88,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
speed_template = device_config.get(CONF_SPEED_TEMPLATE)
oscillating_template = device_config.get(CONF_OSCILLATING_TEMPLATE)
direction_template = device_config.get(CONF_DIRECTION_TEMPLATE)
availability_template = device_config.get(CONF_AVAILABILITY_TEMPLATE)

on_action = device_config[CONF_ON_ACTION]
off_action = device_config[CONF_OFF_ACTION]
Expand All @@ -103,6 +106,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
speed_template,
oscillating_template,
direction_template,
availability_template,
):
if template is None:
continue
Expand Down Expand Up @@ -131,6 +135,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
speed_template,
oscillating_template,
direction_template,
availability_template,
on_action,
off_action,
set_speed_action,
Expand All @@ -156,6 +161,7 @@ def __init__(
speed_template,
oscillating_template,
direction_template,
availability_template,
on_action,
off_action,
set_speed_action,
Expand All @@ -175,6 +181,8 @@ def __init__(
self._speed_template = speed_template
self._oscillating_template = oscillating_template
self._direction_template = direction_template
self._availability_template = availability_template
self._available = True
self._supported_features = 0

self._on_script = Script(hass, on_action)
Expand Down Expand Up @@ -207,6 +215,8 @@ def __init__(
if self._direction_template:
self._direction_template.hass = self.hass
self._supported_features |= SUPPORT_DIRECTION
if self._availability_template:
self._availability_template.hass = self.hass

self._entities = entity_ids
# List of valid speeds
Expand Down Expand Up @@ -252,6 +262,11 @@ def should_poll(self):
"""Return the polling state."""
return False

@property
def available(self):
"""Return availability of Device."""
return self._available

# pylint: disable=arguments-differ
async def async_turn_on(self, speed: str = None) -> None:
"""Turn on the fan."""
Expand Down Expand Up @@ -422,3 +437,15 @@ async def async_update(self):
", ".join(_VALID_DIRECTIONS),
)
self._direction = None

# Update Availability if 'availability_template' is defined
if self._availability_template is not None:
try:
result = self._availability_template.async_render()
self._available = result == "true"
except TemplateError as ex:
_LOGGER.error(ex)
self._available = True
except ValueError as ex:
_LOGGER.error(ex)
self._available = True