This commit is contained in:
Jean-Marc Collin
2025-01-28 06:39:17 +01:00
parent 8cfeb58608
commit ae94c21e8e
2 changed files with 37 additions and 11 deletions

View File

@@ -20,6 +20,10 @@ from homeassistant.components.select import (
DOMAIN as SELECT_DOMAIN, DOMAIN as SELECT_DOMAIN,
) )
from homeassistant.components.input_select import (
DOMAIN as INPUT_SELECT_DOMAIN,
)
from homeassistant.components.input_datetime import ( from homeassistant.components.input_datetime import (
DOMAIN as INPUT_DATETIME_DOMAIN, DOMAIN as INPUT_DATETIME_DOMAIN,
) )
@@ -124,7 +128,7 @@ STEP_CENTRAL_BOILER_SCHEMA = vol.Schema(
STEP_THERMOSTAT_SWITCH = vol.Schema( # pylint: disable=invalid-name STEP_THERMOSTAT_SWITCH = vol.Schema( # pylint: disable=invalid-name
{ {
vol.Required(CONF_UNDERLYING_LIST): selector.EntitySelector( vol.Required(CONF_UNDERLYING_LIST): selector.EntitySelector(
selector.EntitySelectorConfig(domain=[SWITCH_DOMAIN, INPUT_BOOLEAN_DOMAIN, SELECT_DOMAIN, CLIMATE_DOMAIN], multiple=True), selector.EntitySelectorConfig(domain=[SWITCH_DOMAIN, INPUT_BOOLEAN_DOMAIN, SELECT_DOMAIN, INPUT_SELECT_DOMAIN, CLIMATE_DOMAIN], multiple=True),
), ),
vol.Optional(CONF_HEATER_KEEP_ALIVE): cv.positive_int, vol.Optional(CONF_HEATER_KEEP_ALIVE): cv.positive_int,
vol.Required(CONF_PROP_FUNCTION, default=PROPORTIONAL_FUNCTION_TPI): vol.In( vol.Required(CONF_PROP_FUNCTION, default=PROPORTIONAL_FUNCTION_TPI): vol.In(

View File

@@ -2,7 +2,9 @@
""" Underlying entities classes """ """ Underlying entities classes """
import logging import logging
from typing import Any import re
from typing import Any, Dict, Tuple
from enum import StrEnum from enum import StrEnum
from homeassistant.const import ATTR_ENTITY_ID, STATE_ON, STATE_UNAVAILABLE from homeassistant.const import ATTR_ENTITY_ID, STATE_ON, STATE_UNAVAILABLE
@@ -228,6 +230,7 @@ class UnderlyingSwitch(UnderlyingEntity):
self._keep_alive = IntervalCaller(hass, keep_alive_sec) self._keep_alive = IntervalCaller(hass, keep_alive_sec)
self._vswitch_on = vswitch_on self._vswitch_on = vswitch_on
self._vswitch_off = vswitch_off self._vswitch_off = vswitch_off
self._domain = self._entity_id.split(".")[0]
@property @property
def initial_delay_sec(self): def initial_delay_sec(self):
@@ -298,18 +301,39 @@ class UnderlyingSwitch(UnderlyingEntity):
) )
await (self.turn_on() if self.is_device_active else self.turn_off()) await (self.turn_on() if self.is_device_active else self.turn_off())
# @overrides this breaks some unit tests TypeError: object MagicMock can't be used in 'await' expression def build_command(self, use_on: bool) -> Tuple[str, Dict[str, str]]:
"""Build a command and returns a command and a dict as data"""
data = {ATTR_ENTITY_ID: self._entity_id}
vswitch = self._vswitch_on if use_on and not self.is_inversed else self._vswitch_off
if vswitch:
pattern = r"^(?P<command>[^/]+)(?:/(?P<argument>[^:]+)(?::(?P<value>.*))?)?$"
match = re.match(pattern, vswitch)
if match:
# Extraire les groupes nommés
command = match.group("command")
argument = match.group("argument")
value = match.group("value")
data.update({argument: value})
else:
raise ValueError(f"Invalid input format: {vswitch}")
else:
command = SERVICE_TURN_ON if use_on and not self.is_inversed else SERVICE_TURN_OFF
return command, data
async def turn_off(self): async def turn_off(self):
"""Turn heater toggleable device off.""" """Turn heater toggleable device off."""
self._keep_alive.cancel() # Cancel early to avoid a turn_on/turn_off race condition self._keep_alive.cancel() # Cancel early to avoid a turn_on/turn_off race condition
_LOGGER.debug("%s - Stopping underlying entity %s", self, self._entity_id) _LOGGER.debug("%s - Stopping underlying entity %s", self, self._entity_id)
command = SERVICE_TURN_OFF if not self.is_inversed else SERVICE_TURN_ON
domain = self._entity_id.split(".")[0] command, data = self.build_command(use_on=False)
# This may fails if called after shutdown # This may fails if called after shutdown
try: try:
try: try:
data = {ATTR_ENTITY_ID: self._entity_id} await self._hass.services.async_call(self._domain, command, data)
await self._hass.services.async_call(domain, command, data)
self._keep_alive.set_async_action(self._keep_alive_callback) self._keep_alive.set_async_action(self._keep_alive_callback)
except Exception: except Exception:
self._keep_alive.cancel() self._keep_alive.cancel()
@@ -325,12 +349,10 @@ class UnderlyingSwitch(UnderlyingEntity):
if not await self.check_overpowering(): if not await self.check_overpowering():
return False return False
command = SERVICE_TURN_ON if not self.is_inversed else SERVICE_TURN_OFF command, data = self.build_command(use_on=True)
domain = self._entity_id.split(".")[0]
try: try:
try: try:
data = {ATTR_ENTITY_ID: self._entity_id} await self._hass.services.async_call(self._domain, command, data)
await self._hass.services.async_call(domain, command, data)
self._keep_alive.set_async_action(self._keep_alive_callback) self._keep_alive.set_async_action(self._keep_alive_callback)
return True return True
except Exception: except Exception: