mirror of
https://github.com/home-assistant/core.git
synced 2025-07-17 10:17:09 +00:00
Make template entities reloadable (#39075)
* Make template entities reloadable * Address review items
This commit is contained in:
parent
993088d26e
commit
83b9c6188d
@ -1 +1,66 @@
|
|||||||
"""The template component."""
|
"""The template component."""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from homeassistant import config as conf_util
|
||||||
|
from homeassistant.const import SERVICE_RELOAD
|
||||||
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
|
from homeassistant.helpers import config_per_platform, entity_platform
|
||||||
|
from homeassistant.loader import async_get_integration
|
||||||
|
|
||||||
|
from .const import DOMAIN, EVENT_TEMPLATE_RELOADED, PLATFORM_STORAGE_KEY
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
async def _async_setup_reload_service(hass):
|
||||||
|
if hass.services.has_service(DOMAIN, SERVICE_RELOAD):
|
||||||
|
return
|
||||||
|
|
||||||
|
async def _reload_config(call):
|
||||||
|
"""Reload the template platform config."""
|
||||||
|
|
||||||
|
try:
|
||||||
|
unprocessed_conf = await conf_util.async_hass_config_yaml(hass)
|
||||||
|
except HomeAssistantError as err:
|
||||||
|
_LOGGER.error(err)
|
||||||
|
return
|
||||||
|
|
||||||
|
for platform in hass.data[PLATFORM_STORAGE_KEY]:
|
||||||
|
|
||||||
|
integration = await async_get_integration(hass, platform.domain)
|
||||||
|
|
||||||
|
conf = await conf_util.async_process_component_config(
|
||||||
|
hass, unprocessed_conf, integration
|
||||||
|
)
|
||||||
|
|
||||||
|
if not conf:
|
||||||
|
continue
|
||||||
|
|
||||||
|
await platform.async_reset()
|
||||||
|
|
||||||
|
# Extract only the config for template, ignore the rest.
|
||||||
|
for p_type, p_config in config_per_platform(conf, platform.domain):
|
||||||
|
if p_type != DOMAIN:
|
||||||
|
continue
|
||||||
|
|
||||||
|
entities = await platform.platform.async_create_entities(hass, p_config)
|
||||||
|
|
||||||
|
await platform.async_add_entities(entities)
|
||||||
|
|
||||||
|
hass.bus.async_fire(EVENT_TEMPLATE_RELOADED, context=call.context)
|
||||||
|
|
||||||
|
hass.helpers.service.async_register_admin_service(
|
||||||
|
DOMAIN, SERVICE_RELOAD, _reload_config
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_platform_reloadable(hass):
|
||||||
|
"""Template platform with reloadability."""
|
||||||
|
|
||||||
|
await _async_setup_reload_service(hass)
|
||||||
|
|
||||||
|
platform = entity_platform.current_platform.get()
|
||||||
|
|
||||||
|
if platform not in hass.data.setdefault(PLATFORM_STORAGE_KEY, []):
|
||||||
|
hass.data[PLATFORM_STORAGE_KEY].append(platform)
|
||||||
|
@ -33,6 +33,7 @@ import homeassistant.helpers.config_validation as cv
|
|||||||
from homeassistant.helpers.entity import async_generate_entity_id
|
from homeassistant.helpers.entity import async_generate_entity_id
|
||||||
from homeassistant.helpers.script import Script
|
from homeassistant.helpers.script import Script
|
||||||
|
|
||||||
|
from . import async_setup_platform_reloadable
|
||||||
from .template_entity import TemplateEntity
|
from .template_entity import TemplateEntity
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
@ -75,8 +76,9 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
async def async_create_entities(hass, config):
|
||||||
"""Set up the Template Alarm Control Panels."""
|
"""Create Template Alarm Control Panels."""
|
||||||
|
|
||||||
alarm_control_panels = []
|
alarm_control_panels = []
|
||||||
|
|
||||||
for device, device_config in config[CONF_ALARM_CONTROL_PANELS].items():
|
for device, device_config in config[CONF_ALARM_CONTROL_PANELS].items():
|
||||||
@ -104,7 +106,14 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
async_add_entities(alarm_control_panels)
|
return alarm_control_panels
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||||
|
"""Set up the Template Alarm Control Panels."""
|
||||||
|
|
||||||
|
await async_setup_platform_reloadable(hass)
|
||||||
|
async_add_entities(await async_create_entities(hass, config))
|
||||||
|
|
||||||
|
|
||||||
class AlarmControlPanelTemplate(TemplateEntity, AlarmControlPanelEntity):
|
class AlarmControlPanelTemplate(TemplateEntity, AlarmControlPanelEntity):
|
||||||
|
@ -26,6 +26,7 @@ from homeassistant.helpers.entity import async_generate_entity_id
|
|||||||
from homeassistant.helpers.event import async_call_later
|
from homeassistant.helpers.event import async_call_later
|
||||||
from homeassistant.helpers.template import result_as_boolean
|
from homeassistant.helpers.template import result_as_boolean
|
||||||
|
|
||||||
|
from . import async_setup_platform_reloadable
|
||||||
from .const import CONF_AVAILABILITY_TEMPLATE
|
from .const import CONF_AVAILABILITY_TEMPLATE
|
||||||
from .template_entity import TemplateEntity
|
from .template_entity import TemplateEntity
|
||||||
|
|
||||||
@ -56,8 +57,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
async def async_create_entities(hass, config):
|
||||||
"""Set up template binary sensors."""
|
"""Create the template binary sensors."""
|
||||||
sensors = []
|
sensors = []
|
||||||
|
|
||||||
for device, device_config in config[CONF_SENSORS].items():
|
for device, device_config in config[CONF_SENSORS].items():
|
||||||
@ -90,7 +91,14 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
async_add_entities(sensors)
|
return sensors
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||||
|
"""Set up the template binary sensors."""
|
||||||
|
|
||||||
|
await async_setup_platform_reloadable(hass)
|
||||||
|
async_add_entities(await async_create_entities(hass, config))
|
||||||
|
|
||||||
|
|
||||||
class BinarySensorTemplate(TemplateEntity, BinarySensorEntity):
|
class BinarySensorTemplate(TemplateEntity, BinarySensorEntity):
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
"""Constants for the Template Platform Components."""
|
"""Constants for the Template Platform Components."""
|
||||||
|
|
||||||
CONF_AVAILABILITY_TEMPLATE = "availability_template"
|
CONF_AVAILABILITY_TEMPLATE = "availability_template"
|
||||||
|
|
||||||
|
DOMAIN = "template"
|
||||||
|
|
||||||
|
PLATFORM_STORAGE_KEY = "template_platforms"
|
||||||
|
|
||||||
|
EVENT_TEMPLATE_RELOADED = "event_template_reloaded"
|
||||||
|
@ -37,6 +37,7 @@ import homeassistant.helpers.config_validation as cv
|
|||||||
from homeassistant.helpers.entity import async_generate_entity_id
|
from homeassistant.helpers.entity import async_generate_entity_id
|
||||||
from homeassistant.helpers.script import Script
|
from homeassistant.helpers.script import Script
|
||||||
|
|
||||||
|
from . import async_setup_platform_reloadable
|
||||||
from .const import CONF_AVAILABILITY_TEMPLATE
|
from .const import CONF_AVAILABILITY_TEMPLATE
|
||||||
from .template_entity import TemplateEntity
|
from .template_entity import TemplateEntity
|
||||||
|
|
||||||
@ -99,8 +100,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
async def async_create_entities(hass, config):
|
||||||
"""Set up the Template cover."""
|
"""Create the Template cover."""
|
||||||
covers = []
|
covers = []
|
||||||
|
|
||||||
for device, device_config in config[CONF_COVERS].items():
|
for device, device_config in config[CONF_COVERS].items():
|
||||||
@ -145,7 +146,14 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
async_add_entities(covers)
|
return covers
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||||
|
"""Set up the Template cover."""
|
||||||
|
|
||||||
|
await async_setup_platform_reloadable(hass)
|
||||||
|
async_add_entities(await async_create_entities(hass, config))
|
||||||
|
|
||||||
|
|
||||||
class CoverTemplate(TemplateEntity, CoverEntity):
|
class CoverTemplate(TemplateEntity, CoverEntity):
|
||||||
|
@ -34,6 +34,7 @@ import homeassistant.helpers.config_validation as cv
|
|||||||
from homeassistant.helpers.entity import async_generate_entity_id
|
from homeassistant.helpers.entity import async_generate_entity_id
|
||||||
from homeassistant.helpers.script import Script
|
from homeassistant.helpers.script import Script
|
||||||
|
|
||||||
|
from . import async_setup_platform_reloadable
|
||||||
from .const import CONF_AVAILABILITY_TEMPLATE
|
from .const import CONF_AVAILABILITY_TEMPLATE
|
||||||
from .template_entity import TemplateEntity
|
from .template_entity import TemplateEntity
|
||||||
|
|
||||||
@ -80,8 +81,8 @@ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
async def async_create_entities(hass, config):
|
||||||
"""Set up the Template Fans."""
|
"""Create the Template Fans."""
|
||||||
fans = []
|
fans = []
|
||||||
|
|
||||||
for device, device_config in config[CONF_FANS].items():
|
for device, device_config in config[CONF_FANS].items():
|
||||||
@ -122,7 +123,14 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
async_add_entities(fans)
|
return fans
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||||
|
"""Set up the template fans."""
|
||||||
|
|
||||||
|
await async_setup_platform_reloadable(hass)
|
||||||
|
async_add_entities(await async_create_entities(hass, config))
|
||||||
|
|
||||||
|
|
||||||
class TemplateFan(TemplateEntity, FanEntity):
|
class TemplateFan(TemplateEntity, FanEntity):
|
||||||
|
@ -33,6 +33,7 @@ from homeassistant.helpers.config_validation import PLATFORM_SCHEMA
|
|||||||
from homeassistant.helpers.entity import async_generate_entity_id
|
from homeassistant.helpers.entity import async_generate_entity_id
|
||||||
from homeassistant.helpers.script import Script
|
from homeassistant.helpers.script import Script
|
||||||
|
|
||||||
|
from . import async_setup_platform_reloadable
|
||||||
from .const import CONF_AVAILABILITY_TEMPLATE
|
from .const import CONF_AVAILABILITY_TEMPLATE
|
||||||
from .template_entity import TemplateEntity
|
from .template_entity import TemplateEntity
|
||||||
|
|
||||||
@ -77,8 +78,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
async def async_create_entities(hass, config):
|
||||||
"""Set up the Template Lights."""
|
"""Create the Template Lights."""
|
||||||
lights = []
|
lights = []
|
||||||
|
|
||||||
for device, device_config in config[CONF_LIGHTS].items():
|
for device, device_config in config[CONF_LIGHTS].items():
|
||||||
@ -128,7 +129,14 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
async_add_entities(lights)
|
return lights
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||||
|
"""Set up the template lights."""
|
||||||
|
|
||||||
|
await async_setup_platform_reloadable(hass)
|
||||||
|
async_add_entities(await async_create_entities(hass, config))
|
||||||
|
|
||||||
|
|
||||||
class LightTemplate(TemplateEntity, LightEntity):
|
class LightTemplate(TemplateEntity, LightEntity):
|
||||||
|
@ -17,6 +17,7 @@ from homeassistant.exceptions import TemplateError
|
|||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.script import Script
|
from homeassistant.helpers.script import Script
|
||||||
|
|
||||||
|
from . import async_setup_platform_reloadable
|
||||||
from .const import CONF_AVAILABILITY_TEMPLATE
|
from .const import CONF_AVAILABILITY_TEMPLATE
|
||||||
from .template_entity import TemplateEntity
|
from .template_entity import TemplateEntity
|
||||||
|
|
||||||
@ -41,14 +42,13 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
async def async_create_entities(hass, config):
|
||||||
"""Set up the Template lock."""
|
"""Create the Template lock."""
|
||||||
device = config.get(CONF_NAME)
|
device = config.get(CONF_NAME)
|
||||||
value_template = config.get(CONF_VALUE_TEMPLATE)
|
value_template = config.get(CONF_VALUE_TEMPLATE)
|
||||||
availability_template = config.get(CONF_AVAILABILITY_TEMPLATE)
|
availability_template = config.get(CONF_AVAILABILITY_TEMPLATE)
|
||||||
|
|
||||||
async_add_devices(
|
return [
|
||||||
[
|
|
||||||
TemplateLock(
|
TemplateLock(
|
||||||
hass,
|
hass,
|
||||||
device,
|
device,
|
||||||
@ -60,7 +60,13 @@ async def async_setup_platform(hass, config, async_add_devices, discovery_info=N
|
|||||||
config.get(CONF_UNIQUE_ID),
|
config.get(CONF_UNIQUE_ID),
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
)
|
|
||||||
|
|
||||||
|
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||||
|
"""Set up the template lock."""
|
||||||
|
|
||||||
|
await async_setup_platform_reloadable(hass)
|
||||||
|
async_add_entities(await async_create_entities(hass, config))
|
||||||
|
|
||||||
|
|
||||||
class TemplateLock(TemplateEntity, LockEntity):
|
class TemplateLock(TemplateEntity, LockEntity):
|
||||||
|
@ -26,6 +26,7 @@ from homeassistant.exceptions import TemplateError
|
|||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.entity import Entity, async_generate_entity_id
|
from homeassistant.helpers.entity import Entity, async_generate_entity_id
|
||||||
|
|
||||||
|
from . import async_setup_platform_reloadable
|
||||||
from .const import CONF_AVAILABILITY_TEMPLATE
|
from .const import CONF_AVAILABILITY_TEMPLATE
|
||||||
from .template_entity import TemplateEntity
|
from .template_entity import TemplateEntity
|
||||||
|
|
||||||
@ -56,8 +57,9 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
async def async_create_entities(hass, config):
|
||||||
"""Set up the template sensors."""
|
"""Create the template sensors."""
|
||||||
|
|
||||||
sensors = []
|
sensors = []
|
||||||
|
|
||||||
for device, device_config in config[CONF_SENSORS].items():
|
for device, device_config in config[CONF_SENSORS].items():
|
||||||
@ -89,9 +91,14 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
async_add_entities(sensors)
|
return sensors
|
||||||
|
|
||||||
return True
|
|
||||||
|
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||||
|
"""Set up the template sensors."""
|
||||||
|
|
||||||
|
await async_setup_platform_reloadable(hass)
|
||||||
|
async_add_entities(await async_create_entities(hass, config))
|
||||||
|
|
||||||
|
|
||||||
class SensorTemplate(TemplateEntity, Entity):
|
class SensorTemplate(TemplateEntity, Entity):
|
||||||
|
3
homeassistant/components/template/services.yaml
Normal file
3
homeassistant/components/template/services.yaml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
reload:
|
||||||
|
description: Reload all template entities.
|
||||||
|
|
@ -26,6 +26,7 @@ from homeassistant.helpers.entity import async_generate_entity_id
|
|||||||
from homeassistant.helpers.restore_state import RestoreEntity
|
from homeassistant.helpers.restore_state import RestoreEntity
|
||||||
from homeassistant.helpers.script import Script
|
from homeassistant.helpers.script import Script
|
||||||
|
|
||||||
|
from . import async_setup_platform_reloadable
|
||||||
from .const import CONF_AVAILABILITY_TEMPLATE
|
from .const import CONF_AVAILABILITY_TEMPLATE
|
||||||
from .template_entity import TemplateEntity
|
from .template_entity import TemplateEntity
|
||||||
|
|
||||||
@ -54,8 +55,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
async def async_create_entities(hass, config):
|
||||||
"""Set up the Template switch."""
|
"""Create the Template switches."""
|
||||||
switches = []
|
switches = []
|
||||||
|
|
||||||
for device, device_config in config[CONF_SWITCHES].items():
|
for device, device_config in config[CONF_SWITCHES].items():
|
||||||
@ -83,7 +84,14 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
async_add_entities(switches)
|
return switches
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||||
|
"""Set up the template switches."""
|
||||||
|
|
||||||
|
await async_setup_platform_reloadable(hass)
|
||||||
|
async_add_entities(await async_create_entities(hass, config))
|
||||||
|
|
||||||
|
|
||||||
class SwitchTemplate(TemplateEntity, SwitchEntity, RestoreEntity):
|
class SwitchTemplate(TemplateEntity, SwitchEntity, RestoreEntity):
|
||||||
|
@ -5,7 +5,7 @@ from typing import Any, Callable, Optional, Union
|
|||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.core import EVENT_HOMEASSISTANT_START, callback
|
from homeassistant.core import EVENT_HOMEASSISTANT_START, CoreState, callback
|
||||||
from homeassistant.exceptions import TemplateError
|
from homeassistant.exceptions import TemplateError
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
@ -232,7 +232,7 @@ class TemplateEntity(Entity):
|
|||||||
attribute.async_setup()
|
attribute.async_setup()
|
||||||
self._template_attrs.append(attribute)
|
self._template_attrs.append(attribute)
|
||||||
|
|
||||||
async def _async_template_startup(self, _) -> None:
|
async def _async_template_startup(self, *_) -> None:
|
||||||
# async_update will not write state
|
# async_update will not write state
|
||||||
# until "add_complete" is set on the attribute
|
# until "add_complete" is set on the attribute
|
||||||
for attribute in self._template_attrs:
|
for attribute in self._template_attrs:
|
||||||
@ -259,6 +259,9 @@ class TemplateEntity(Entity):
|
|||||||
self.add_template_attribute(
|
self.add_template_attribute(
|
||||||
"_entity_picture", self._entity_picture_template
|
"_entity_picture", self._entity_picture_template
|
||||||
)
|
)
|
||||||
|
if self.hass.state == CoreState.running:
|
||||||
|
await self._async_template_startup()
|
||||||
|
return
|
||||||
|
|
||||||
self.hass.bus.async_listen_once(
|
self.hass.bus.async_listen_once(
|
||||||
EVENT_HOMEASSISTANT_START, self._async_template_startup
|
EVENT_HOMEASSISTANT_START, self._async_template_startup
|
||||||
|
@ -43,6 +43,7 @@ import homeassistant.helpers.config_validation as cv
|
|||||||
from homeassistant.helpers.entity import async_generate_entity_id
|
from homeassistant.helpers.entity import async_generate_entity_id
|
||||||
from homeassistant.helpers.script import Script
|
from homeassistant.helpers.script import Script
|
||||||
|
|
||||||
|
from . import async_setup_platform_reloadable
|
||||||
from .const import CONF_AVAILABILITY_TEMPLATE
|
from .const import CONF_AVAILABILITY_TEMPLATE
|
||||||
from .template_entity import TemplateEntity
|
from .template_entity import TemplateEntity
|
||||||
|
|
||||||
@ -92,8 +93,8 @@ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
async def async_create_entities(hass, config):
|
||||||
"""Set up the Template Vacuums."""
|
"""Create the Template Vacuums."""
|
||||||
vacuums = []
|
vacuums = []
|
||||||
|
|
||||||
for device, device_config in config[CONF_VACUUMS].items():
|
for device, device_config in config[CONF_VACUUMS].items():
|
||||||
@ -138,7 +139,14 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
async_add_entities(vacuums)
|
return vacuums
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||||
|
"""Set up the template vacuums."""
|
||||||
|
|
||||||
|
await async_setup_platform_reloadable(hass)
|
||||||
|
async_add_entities(await async_create_entities(hass, config))
|
||||||
|
|
||||||
|
|
||||||
class TemplateVacuum(TemplateEntity, StateVacuumEntity):
|
class TemplateVacuum(TemplateEntity, StateVacuumEntity):
|
||||||
|
@ -11,6 +11,7 @@ from homeassistant.const import (
|
|||||||
STATE_ON,
|
STATE_ON,
|
||||||
STATE_UNAVAILABLE,
|
STATE_UNAVAILABLE,
|
||||||
)
|
)
|
||||||
|
from homeassistant.core import CoreState
|
||||||
import homeassistant.util.dt as dt_util
|
import homeassistant.util.dt as dt_util
|
||||||
|
|
||||||
from tests.common import (
|
from tests.common import (
|
||||||
@ -505,6 +506,8 @@ async def test_no_update_template_match_all(hass, caplog):
|
|||||||
"""Test that we do not update sensors that match on all."""
|
"""Test that we do not update sensors that match on all."""
|
||||||
hass.states.async_set("binary_sensor.test_sensor", "true")
|
hass.states.async_set("binary_sensor.test_sensor", "true")
|
||||||
|
|
||||||
|
hass.state = CoreState.not_running
|
||||||
|
|
||||||
await setup.async_setup_component(
|
await setup.async_setup_component(
|
||||||
hass,
|
hass,
|
||||||
"binary_sensor",
|
"binary_sensor",
|
||||||
|
232
tests/components/template/test_init.py
Normal file
232
tests/components/template/test_init.py
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
"""The test for the Template sensor platform."""
|
||||||
|
from os import path
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from homeassistant import config
|
||||||
|
from homeassistant.components.template import DOMAIN, SERVICE_RELOAD
|
||||||
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
|
|
||||||
|
async def test_reloadable(hass):
|
||||||
|
"""Test that we can reload."""
|
||||||
|
hass.states.async_set("sensor.test_sensor", "mytest")
|
||||||
|
|
||||||
|
await async_setup_component(
|
||||||
|
hass,
|
||||||
|
"sensor",
|
||||||
|
{
|
||||||
|
"sensor": {
|
||||||
|
"platform": DOMAIN,
|
||||||
|
"sensors": {
|
||||||
|
"state": {
|
||||||
|
"value_template": "{{ states.sensor.test_sensor.state }}"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
await hass.async_start()
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert hass.states.get("sensor.state").state == "mytest"
|
||||||
|
assert len(hass.states.async_all()) == 2
|
||||||
|
|
||||||
|
yaml_path = path.join(
|
||||||
|
_get_fixtures_base_path(), "fixtures", "template/sensor_configuration.yaml",
|
||||||
|
)
|
||||||
|
with patch.object(config, "YAML_CONFIG_FILE", yaml_path):
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN, SERVICE_RELOAD, {}, blocking=True,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert len(hass.states.async_all()) == 3
|
||||||
|
|
||||||
|
assert hass.states.get("sensor.state") is None
|
||||||
|
assert hass.states.get("sensor.watching_tv_in_master_bedroom").state == "off"
|
||||||
|
assert float(hass.states.get("sensor.combined_sensor_energy_usage").state) == 0
|
||||||
|
|
||||||
|
|
||||||
|
async def test_reloadable_can_remove(hass):
|
||||||
|
"""Test that we can reload and remove all template sensors."""
|
||||||
|
hass.states.async_set("sensor.test_sensor", "mytest")
|
||||||
|
|
||||||
|
await async_setup_component(
|
||||||
|
hass,
|
||||||
|
"sensor",
|
||||||
|
{
|
||||||
|
"sensor": {
|
||||||
|
"platform": DOMAIN,
|
||||||
|
"sensors": {
|
||||||
|
"state": {
|
||||||
|
"value_template": "{{ states.sensor.test_sensor.state }}"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
await hass.async_start()
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert hass.states.get("sensor.state").state == "mytest"
|
||||||
|
assert len(hass.states.async_all()) == 2
|
||||||
|
|
||||||
|
yaml_path = path.join(
|
||||||
|
_get_fixtures_base_path(), "fixtures", "template/empty_configuration.yaml",
|
||||||
|
)
|
||||||
|
with patch.object(config, "YAML_CONFIG_FILE", yaml_path):
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN, SERVICE_RELOAD, {}, blocking=True,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert len(hass.states.async_all()) == 1
|
||||||
|
|
||||||
|
|
||||||
|
async def test_reloadable_stops_on_invalid_config(hass):
|
||||||
|
"""Test we stop the reload if configuration.yaml is completely broken."""
|
||||||
|
hass.states.async_set("sensor.test_sensor", "mytest")
|
||||||
|
|
||||||
|
await async_setup_component(
|
||||||
|
hass,
|
||||||
|
"sensor",
|
||||||
|
{
|
||||||
|
"sensor": {
|
||||||
|
"platform": DOMAIN,
|
||||||
|
"sensors": {
|
||||||
|
"state": {
|
||||||
|
"value_template": "{{ states.sensor.test_sensor.state }}"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
await hass.async_start()
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert hass.states.get("sensor.state").state == "mytest"
|
||||||
|
assert len(hass.states.async_all()) == 2
|
||||||
|
|
||||||
|
yaml_path = path.join(
|
||||||
|
_get_fixtures_base_path(), "fixtures", "template/configuration.yaml.corrupt",
|
||||||
|
)
|
||||||
|
with patch.object(config, "YAML_CONFIG_FILE", yaml_path):
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN, SERVICE_RELOAD, {}, blocking=True,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert hass.states.get("sensor.state").state == "mytest"
|
||||||
|
assert len(hass.states.async_all()) == 2
|
||||||
|
|
||||||
|
|
||||||
|
async def test_reloadable_handles_partial_valid_config(hass):
|
||||||
|
"""Test we can still setup valid sensors when configuration.yaml has a broken entry."""
|
||||||
|
hass.states.async_set("sensor.test_sensor", "mytest")
|
||||||
|
|
||||||
|
await async_setup_component(
|
||||||
|
hass,
|
||||||
|
"sensor",
|
||||||
|
{
|
||||||
|
"sensor": {
|
||||||
|
"platform": DOMAIN,
|
||||||
|
"sensors": {
|
||||||
|
"state": {
|
||||||
|
"value_template": "{{ states.sensor.test_sensor.state }}"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
await hass.async_start()
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert hass.states.get("sensor.state").state == "mytest"
|
||||||
|
assert len(hass.states.async_all()) == 2
|
||||||
|
|
||||||
|
yaml_path = path.join(
|
||||||
|
_get_fixtures_base_path(), "fixtures", "template/broken_configuration.yaml",
|
||||||
|
)
|
||||||
|
with patch.object(config, "YAML_CONFIG_FILE", yaml_path):
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN, SERVICE_RELOAD, {}, blocking=True,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert len(hass.states.async_all()) == 3
|
||||||
|
|
||||||
|
assert hass.states.get("sensor.state") is None
|
||||||
|
assert hass.states.get("sensor.watching_tv_in_master_bedroom").state == "off"
|
||||||
|
assert float(hass.states.get("sensor.combined_sensor_energy_usage").state) == 0
|
||||||
|
|
||||||
|
|
||||||
|
async def test_reloadable_multiple_platforms(hass):
|
||||||
|
"""Test that we can reload."""
|
||||||
|
hass.states.async_set("sensor.test_sensor", "mytest")
|
||||||
|
|
||||||
|
await async_setup_component(
|
||||||
|
hass,
|
||||||
|
"sensor",
|
||||||
|
{
|
||||||
|
"sensor": {
|
||||||
|
"platform": DOMAIN,
|
||||||
|
"sensors": {
|
||||||
|
"state": {
|
||||||
|
"value_template": "{{ states.sensor.test_sensor.state }}"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await async_setup_component(
|
||||||
|
hass,
|
||||||
|
"binary_sensor",
|
||||||
|
{
|
||||||
|
"binary_sensor": {
|
||||||
|
"platform": DOMAIN,
|
||||||
|
"sensors": {
|
||||||
|
"state": {
|
||||||
|
"value_template": "{{ states.sensor.test_sensor.state }}"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
await hass.async_start()
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert hass.states.get("sensor.state").state == "mytest"
|
||||||
|
assert hass.states.get("binary_sensor.state").state == "off"
|
||||||
|
|
||||||
|
assert len(hass.states.async_all()) == 3
|
||||||
|
|
||||||
|
yaml_path = path.join(
|
||||||
|
_get_fixtures_base_path(), "fixtures", "template/sensor_configuration.yaml",
|
||||||
|
)
|
||||||
|
with patch.object(config, "YAML_CONFIG_FILE", yaml_path):
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN, SERVICE_RELOAD, {}, blocking=True,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert len(hass.states.async_all()) == 3
|
||||||
|
|
||||||
|
assert hass.states.get("sensor.state") is None
|
||||||
|
assert hass.states.get("sensor.watching_tv_in_master_bedroom").state == "off"
|
||||||
|
assert float(hass.states.get("sensor.combined_sensor_energy_usage").state) == 0
|
||||||
|
|
||||||
|
|
||||||
|
def _get_fixtures_base_path():
|
||||||
|
return path.dirname(path.dirname(path.dirname(__file__)))
|
@ -10,6 +10,7 @@ from homeassistant.const import (
|
|||||||
STATE_ON,
|
STATE_ON,
|
||||||
STATE_UNAVAILABLE,
|
STATE_UNAVAILABLE,
|
||||||
)
|
)
|
||||||
|
from homeassistant.core import CoreState
|
||||||
from homeassistant.setup import ATTR_COMPONENT, async_setup_component, setup_component
|
from homeassistant.setup import ATTR_COMPONENT, async_setup_component, setup_component
|
||||||
|
|
||||||
from tests.common import assert_setup_component, get_test_home_assistant
|
from tests.common import assert_setup_component, get_test_home_assistant
|
||||||
@ -584,6 +585,8 @@ async def test_no_template_match_all(hass, caplog):
|
|||||||
"""Test that we allow static templates."""
|
"""Test that we allow static templates."""
|
||||||
hass.states.async_set("sensor.test_sensor", "startup")
|
hass.states.async_set("sensor.test_sensor", "startup")
|
||||||
|
|
||||||
|
hass.state = CoreState.not_running
|
||||||
|
|
||||||
await async_setup_component(
|
await async_setup_component(
|
||||||
hass,
|
hass,
|
||||||
"sensor",
|
"sensor",
|
||||||
|
16
tests/fixtures/template/broken_configuration.yaml
vendored
Normal file
16
tests/fixtures/template/broken_configuration.yaml
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
sensor:
|
||||||
|
- platform: template
|
||||||
|
broken:
|
||||||
|
- platform: template
|
||||||
|
sensors:
|
||||||
|
combined_sensor_energy_usage:
|
||||||
|
friendly_name: Combined Sense Energy Usage
|
||||||
|
unit_of_measurement: kW
|
||||||
|
value_template: '{{ ((states(''sensor.energy_usage'') | float) + (states(''sensor.energy_usage_2'')
|
||||||
|
| float)) / 1000 }}'
|
||||||
|
watching_tv_in_master_bedroom:
|
||||||
|
friendly_name: Watching TV in Master Bedroom
|
||||||
|
value_template: '{% if state_attr("remote.alexander_master_bedroom","current_activity")
|
||||||
|
== "Watch TV" or state_attr("remote.alexander_master_bedroom","current_activity")
|
||||||
|
== "Watch Apple TV" %}on{% else %}off{% endif %}'
|
||||||
|
|
BIN
tests/fixtures/template/configuration.yaml.corrupt
vendored
Normal file
BIN
tests/fixtures/template/configuration.yaml.corrupt
vendored
Normal file
Binary file not shown.
1
tests/fixtures/template/empty_configuration.yaml
vendored
Normal file
1
tests/fixtures/template/empty_configuration.yaml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
23
tests/fixtures/template/sensor_configuration.yaml
vendored
Normal file
23
tests/fixtures/template/sensor_configuration.yaml
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
sensor:
|
||||||
|
- platform: snmp
|
||||||
|
name: UPS kW
|
||||||
|
unit_of_measurement: kW
|
||||||
|
baseoid: 1.3.6.1.4.1.3808.1.1.1.4.2.5.0
|
||||||
|
host: 192.168.210.25
|
||||||
|
community: public
|
||||||
|
accept_errors: true
|
||||||
|
value_template: '{{ ((value | int) / 1000) | float | round(3) }}'
|
||||||
|
scan_interval: 900
|
||||||
|
- platform: template
|
||||||
|
sensors:
|
||||||
|
combined_sensor_energy_usage:
|
||||||
|
friendly_name: Combined Sense Energy Usage
|
||||||
|
unit_of_measurement: kW
|
||||||
|
value_template: '{{ ((states(''sensor.energy_usage'') | float) + (states(''sensor.energy_usage_2'')
|
||||||
|
| float)) / 1000 }}'
|
||||||
|
watching_tv_in_master_bedroom:
|
||||||
|
friendly_name: Watching TV in Master Bedroom
|
||||||
|
value_template: '{% if state_attr("remote.alexander_master_bedroom","current_activity")
|
||||||
|
== "Watch TV" or state_attr("remote.alexander_master_bedroom","current_activity")
|
||||||
|
== "Watch Apple TV" %}on{% else %}off{% endif %}'
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user