mirror of
https://github.com/home-assistant/core.git
synced 2026-05-08 17:49:37 +01:00
Update template vacuum platform to new template entity framework (#162564)
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Generator, Sequence
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
@@ -30,15 +29,9 @@ from homeassistant.const import (
|
||||
CONF_STATE,
|
||||
CONF_UNIQUE_ID,
|
||||
CONF_VALUE_TEMPLATE,
|
||||
STATE_UNKNOWN,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import TemplateError
|
||||
from homeassistant.helpers import (
|
||||
config_validation as cv,
|
||||
issue_registry as ir,
|
||||
template,
|
||||
)
|
||||
from homeassistant.helpers import config_validation as cv, issue_registry as ir
|
||||
from homeassistant.helpers.entity_platform import (
|
||||
AddConfigEntryEntitiesCallback,
|
||||
AddEntitiesCallback,
|
||||
@@ -46,8 +39,8 @@ from homeassistant.helpers.entity_platform import (
|
||||
from homeassistant.helpers.issue_registry import IssueSeverity
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
|
||||
from . import TriggerUpdateCoordinator, validators as template_validators
|
||||
from .const import DOMAIN
|
||||
from .coordinator import TriggerUpdateCoordinator
|
||||
from .entity import AbstractTemplateEntity
|
||||
from .helpers import (
|
||||
async_setup_template_entry,
|
||||
@@ -76,14 +69,6 @@ CONF_FAN_SPEED_TEMPLATE = "fan_speed_template"
|
||||
DEFAULT_NAME = "Template Vacuum"
|
||||
|
||||
ENTITY_ID_FORMAT = VACUUM_DOMAIN + ".{}"
|
||||
_VALID_STATES = [
|
||||
VacuumActivity.CLEANING,
|
||||
VacuumActivity.DOCKED,
|
||||
VacuumActivity.PAUSED,
|
||||
VacuumActivity.IDLE,
|
||||
VacuumActivity.RETURNING,
|
||||
VacuumActivity.ERROR,
|
||||
]
|
||||
|
||||
LEGACY_FIELDS = {
|
||||
CONF_BATTERY_LEVEL_TEMPLATE: CONF_BATTERY_LEVEL,
|
||||
@@ -225,27 +210,36 @@ class AbstractTemplateVacuum(AbstractTemplateEntity, StateVacuumEntity):
|
||||
|
||||
# The super init is not called because TemplateEntity and TriggerEntity will call AbstractTemplateEntity.__init__.
|
||||
# This ensures that the __init__ on AbstractTemplateEntity is not called twice.
|
||||
def __init__(self, config: dict[str, Any]) -> None: # pylint: disable=super-init-not-called
|
||||
def __init__(self, name: str, config: dict[str, Any]) -> None: # pylint: disable=super-init-not-called
|
||||
"""Initialize the features."""
|
||||
self._battery_level_template = config.get(CONF_BATTERY_LEVEL)
|
||||
self._fan_speed_template = config.get(CONF_FAN_SPEED)
|
||||
|
||||
self._battery_level = None
|
||||
self._attr_fan_speed = None
|
||||
|
||||
# List of valid fan speeds
|
||||
self._attr_fan_speed_list = config[CONF_FAN_SPEED_LIST]
|
||||
self.setup_state_template(
|
||||
CONF_STATE,
|
||||
"_attr_activity",
|
||||
template_validators.strenum(self, CONF_STATE, VacuumActivity),
|
||||
)
|
||||
self.setup_template(
|
||||
CONF_FAN_SPEED,
|
||||
"_attr_fan_speed",
|
||||
template_validators.item_in_list(
|
||||
self, CONF_FAN_SPEED, self._attr_fan_speed_list
|
||||
),
|
||||
)
|
||||
self.setup_template(
|
||||
CONF_BATTERY_LEVEL,
|
||||
"_attr_battery_level",
|
||||
template_validators.number(self, CONF_BATTERY_LEVEL, 0.0, 100.0),
|
||||
)
|
||||
|
||||
self._attr_supported_features = (
|
||||
VacuumEntityFeature.START | VacuumEntityFeature.STATE
|
||||
)
|
||||
|
||||
if self._battery_level_template:
|
||||
if CONF_BATTERY_LEVEL in self._templates:
|
||||
self._attr_supported_features |= VacuumEntityFeature.BATTERY
|
||||
|
||||
def _iterate_scripts(
|
||||
self, config: dict[str, Any]
|
||||
) -> Generator[tuple[str, Sequence[dict[str, Any]], VacuumEntityFeature | int]]:
|
||||
for action_id, supported_feature in (
|
||||
(SERVICE_START, 0),
|
||||
(SERVICE_PAUSE, VacuumEntityFeature.PAUSE),
|
||||
@@ -256,22 +250,8 @@ class AbstractTemplateVacuum(AbstractTemplateEntity, StateVacuumEntity):
|
||||
(SERVICE_SET_FAN_SPEED, VacuumEntityFeature.FAN_SPEED),
|
||||
):
|
||||
if (action_config := config.get(action_id)) is not None:
|
||||
yield (action_id, action_config, supported_feature)
|
||||
|
||||
def _handle_state(self, result: Any) -> None:
|
||||
# Validate state
|
||||
if result in _VALID_STATES:
|
||||
self._attr_activity = result
|
||||
elif result == STATE_UNKNOWN:
|
||||
self._attr_activity = None
|
||||
else:
|
||||
_LOGGER.error(
|
||||
"Received invalid vacuum state: %s for entity %s. Expected: %s",
|
||||
result,
|
||||
self.entity_id,
|
||||
", ".join(_VALID_STATES),
|
||||
)
|
||||
self._attr_activity = None
|
||||
self.add_script(action_id, action_config, name, DOMAIN)
|
||||
self._attr_supported_features |= supported_feature
|
||||
|
||||
async def async_start(self) -> None:
|
||||
"""Start or resume the cleaning task."""
|
||||
@@ -335,44 +315,6 @@ class AbstractTemplateVacuum(AbstractTemplateEntity, StateVacuumEntity):
|
||||
script, run_variables={ATTR_FAN_SPEED: fan_speed}, context=self._context
|
||||
)
|
||||
|
||||
@callback
|
||||
def _update_battery_level(self, battery_level):
|
||||
try:
|
||||
battery_level_int = int(battery_level)
|
||||
if not 0 <= battery_level_int <= 100:
|
||||
raise ValueError # noqa: TRY301
|
||||
except ValueError:
|
||||
_LOGGER.error(
|
||||
"Received invalid battery level: %s for entity %s. Expected: 0-100",
|
||||
battery_level,
|
||||
self.entity_id,
|
||||
)
|
||||
self._attr_battery_level = None
|
||||
return
|
||||
|
||||
self._attr_battery_level = battery_level_int
|
||||
|
||||
@callback
|
||||
def _update_fan_speed(self, fan_speed):
|
||||
if isinstance(fan_speed, TemplateError):
|
||||
# This is legacy behavior
|
||||
self._attr_fan_speed = None
|
||||
self._attr_activity = None
|
||||
return
|
||||
|
||||
if fan_speed in self._attr_fan_speed_list:
|
||||
self._attr_fan_speed = fan_speed
|
||||
elif fan_speed == STATE_UNKNOWN:
|
||||
self._attr_fan_speed = None
|
||||
else:
|
||||
_LOGGER.error(
|
||||
"Received invalid fan speed: %s for entity %s. Expected: %s",
|
||||
fan_speed,
|
||||
self.entity_id,
|
||||
self._attr_fan_speed_list,
|
||||
)
|
||||
self._attr_fan_speed = None
|
||||
|
||||
|
||||
class TemplateStateVacuumEntity(TemplateEntity, AbstractTemplateVacuum):
|
||||
"""A template vacuum component."""
|
||||
@@ -387,16 +329,10 @@ class TemplateStateVacuumEntity(TemplateEntity, AbstractTemplateVacuum):
|
||||
) -> None:
|
||||
"""Initialize the vacuum."""
|
||||
TemplateEntity.__init__(self, hass, config, unique_id)
|
||||
AbstractTemplateVacuum.__init__(self, config)
|
||||
name = self._attr_name
|
||||
if TYPE_CHECKING:
|
||||
assert name is not None
|
||||
|
||||
for action_id, action_config, supported_feature in self._iterate_scripts(
|
||||
config
|
||||
):
|
||||
self.add_script(action_id, action_config, name, DOMAIN)
|
||||
self._attr_supported_features |= supported_feature
|
||||
AbstractTemplateVacuum.__init__(self, name, config)
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Run when entity about to be added to hass."""
|
||||
@@ -408,42 +344,6 @@ class TemplateStateVacuumEntity(TemplateEntity, AbstractTemplateVacuum):
|
||||
self.entity_id,
|
||||
)
|
||||
|
||||
@callback
|
||||
def _async_setup_templates(self) -> None:
|
||||
"""Set up templates."""
|
||||
if self._template is not None:
|
||||
self.add_template_attribute(
|
||||
"_attr_activity", self._template, None, self._update_state
|
||||
)
|
||||
if self._fan_speed_template is not None:
|
||||
self.add_template_attribute(
|
||||
"_fan_speed",
|
||||
self._fan_speed_template,
|
||||
None,
|
||||
self._update_fan_speed,
|
||||
)
|
||||
if self._battery_level_template is not None:
|
||||
self.add_template_attribute(
|
||||
"_battery_level",
|
||||
self._battery_level_template,
|
||||
None,
|
||||
self._update_battery_level,
|
||||
none_on_template_error=True,
|
||||
)
|
||||
super()._async_setup_templates()
|
||||
|
||||
@callback
|
||||
def _update_state(self, result):
|
||||
super()._update_state(result)
|
||||
if isinstance(result, TemplateError):
|
||||
# This is legacy behavior
|
||||
self._attr_activity = None
|
||||
if not self._availability_template:
|
||||
self._attr_available = True
|
||||
return
|
||||
|
||||
self._handle_state(result)
|
||||
|
||||
|
||||
class TriggerVacuumEntity(TriggerEntity, AbstractTemplateVacuum):
|
||||
"""Vacuum entity based on trigger data."""
|
||||
@@ -458,20 +358,8 @@ class TriggerVacuumEntity(TriggerEntity, AbstractTemplateVacuum):
|
||||
) -> None:
|
||||
"""Initialize the entity."""
|
||||
TriggerEntity.__init__(self, hass, coordinator, config)
|
||||
AbstractTemplateVacuum.__init__(self, config)
|
||||
|
||||
self._attr_name = name = self._rendered.get(CONF_NAME, DEFAULT_NAME)
|
||||
|
||||
for action_id, action_config, supported_feature in self._iterate_scripts(
|
||||
config
|
||||
):
|
||||
self.add_script(action_id, action_config, name, DOMAIN)
|
||||
self._attr_supported_features |= supported_feature
|
||||
|
||||
for key in (CONF_STATE, CONF_FAN_SPEED, CONF_BATTERY_LEVEL):
|
||||
if isinstance(config.get(key), template.Template):
|
||||
self._to_render_simple.append(key)
|
||||
self._parse_result.add(key)
|
||||
AbstractTemplateVacuum.__init__(self, name, config)
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Run when entity about to be added to hass."""
|
||||
@@ -482,28 +370,3 @@ class TriggerVacuumEntity(TriggerEntity, AbstractTemplateVacuum):
|
||||
self._attr_name or DEFAULT_NAME,
|
||||
self.entity_id,
|
||||
)
|
||||
|
||||
@callback
|
||||
def _handle_coordinator_update(self) -> None:
|
||||
"""Handle update of the data."""
|
||||
self._process_data()
|
||||
|
||||
if not self.available:
|
||||
return
|
||||
|
||||
write_ha_state = False
|
||||
for key, updater in (
|
||||
(CONF_STATE, self._handle_state),
|
||||
(CONF_FAN_SPEED, self._update_fan_speed),
|
||||
(CONF_BATTERY_LEVEL, self._update_battery_level),
|
||||
):
|
||||
if (rendered := self._rendered.get(key)) is not None:
|
||||
updater(rendered)
|
||||
write_ha_state = True
|
||||
|
||||
if len(self._rendered) > 0:
|
||||
# In case any non optimistic template
|
||||
write_ha_state = True
|
||||
|
||||
if write_ha_state:
|
||||
self.async_write_ha_state()
|
||||
|
||||
@@ -312,7 +312,7 @@ async def setup_attributes_state_vacuum(
|
||||
"fan_speed_template": "{{ this_function_does_not_exist() }}",
|
||||
"start": {"service": "script.vacuum_start"},
|
||||
},
|
||||
STATE_UNKNOWN,
|
||||
STATE_UNAVAILABLE,
|
||||
None,
|
||||
),
|
||||
(
|
||||
@@ -323,7 +323,7 @@ async def setup_attributes_state_vacuum(
|
||||
"fan_speed": "{{ this_function_does_not_exist() }}",
|
||||
"start": {"service": "script.vacuum_start"},
|
||||
},
|
||||
STATE_UNKNOWN,
|
||||
STATE_UNAVAILABLE,
|
||||
None,
|
||||
),
|
||||
(
|
||||
|
||||
Reference in New Issue
Block a user