Add valve change tests (ko)
This commit is contained in:
@@ -732,17 +732,17 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
return f"VersatileThermostat-{self.name}"
|
return f"VersatileThermostat-{self.name}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_over_climate(self):
|
def is_over_climate(self) -> bool:
|
||||||
""" True if the Thermostat is over_climate"""
|
""" True if the Thermostat is over_climate"""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_over_switch(self):
|
def is_over_switch(self) -> bool:
|
||||||
""" True if the Thermostat is over_switch"""
|
""" True if the Thermostat is over_switch"""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_over_valve(self):
|
def is_over_valve(self) -> bool:
|
||||||
""" True if the Thermostat is over_valve"""
|
""" True if the Thermostat is over_valve"""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -853,7 +853,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
"""
|
"""
|
||||||
if self._hvac_mode == HVACMode.OFF:
|
if self._hvac_mode == HVACMode.OFF:
|
||||||
return HVACAction.OFF
|
return HVACAction.OFF
|
||||||
if not self._is_device_active:
|
if not self.is_device_active:
|
||||||
return HVACAction.IDLE
|
return HVACAction.IDLE
|
||||||
if self._hvac_mode == HVACMode.COOL:
|
if self._hvac_mode == HVACMode.COOL:
|
||||||
return HVACAction.COOLING
|
return HVACAction.COOLING
|
||||||
@@ -873,7 +873,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
return self._support_flags
|
return self._support_flags
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _is_device_active(self):
|
def is_device_active(self):
|
||||||
"""Returns true if one underlying is active"""
|
"""Returns true if one underlying is active"""
|
||||||
for under in self._underlyings:
|
for under in self._underlyings:
|
||||||
if under.is_device_active:
|
if under.is_device_active:
|
||||||
@@ -1093,7 +1093,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
await self._async_set_preset_mode_internal(self._attr_preset_mode, True)
|
await self._async_set_preset_mode_internal(self._attr_preset_mode, True)
|
||||||
|
|
||||||
if need_control_heating and sub_need_control_heating:
|
if need_control_heating and sub_need_control_heating:
|
||||||
await self._async_control_heating(force=True)
|
await self.async_control_heating(force=True)
|
||||||
|
|
||||||
# Ensure we update the current operation after changing the mode
|
# Ensure we update the current operation after changing the mode
|
||||||
self.reset_last_temperature_time()
|
self.reset_last_temperature_time()
|
||||||
@@ -1107,7 +1107,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
async def async_set_preset_mode(self, preset_mode):
|
async def async_set_preset_mode(self, preset_mode):
|
||||||
"""Set new preset mode."""
|
"""Set new preset mode."""
|
||||||
await self._async_set_preset_mode_internal(preset_mode)
|
await self._async_set_preset_mode_internal(preset_mode)
|
||||||
await self._async_control_heating(force=True)
|
await self.async_control_heating(force=True)
|
||||||
|
|
||||||
async def _async_set_preset_mode_internal(self, preset_mode, force=False):
|
async def _async_set_preset_mode_internal(self, preset_mode, force=False):
|
||||||
"""Set new preset mode."""
|
"""Set new preset mode."""
|
||||||
@@ -1240,7 +1240,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
self._attr_preset_mode = PRESET_NONE
|
self._attr_preset_mode = PRESET_NONE
|
||||||
self.recalculate()
|
self.recalculate()
|
||||||
self.reset_last_change_time()
|
self.reset_last_change_time()
|
||||||
await self._async_control_heating(force=True)
|
await self.async_control_heating(force=True)
|
||||||
|
|
||||||
async def _async_internal_set_temperature(self, temperature):
|
async def _async_internal_set_temperature(self, temperature):
|
||||||
"""Set the target temperature and the target temperature of underlying climate if any"""
|
"""Set the target temperature and the target temperature of underlying climate if any"""
|
||||||
@@ -1290,7 +1290,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
|
|
||||||
await self._async_update_temp(new_state)
|
await self._async_update_temp(new_state)
|
||||||
self.recalculate()
|
self.recalculate()
|
||||||
await self._async_control_heating(force=False)
|
await self.async_control_heating(force=False)
|
||||||
|
|
||||||
async def _async_ext_temperature_changed(self, event: Event):
|
async def _async_ext_temperature_changed(self, event: Event):
|
||||||
"""Handle external temperature opf the sensor changes."""
|
"""Handle external temperature opf the sensor changes."""
|
||||||
@@ -1305,7 +1305,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
|
|
||||||
await self._async_update_ext_temp(new_state)
|
await self._async_update_ext_temp(new_state)
|
||||||
self.recalculate()
|
self.recalculate()
|
||||||
await self._async_control_heating(force=False)
|
await self.async_control_heating(force=False)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
async def _async_windows_changed(self, event):
|
async def _async_windows_changed(self, event):
|
||||||
@@ -1431,7 +1431,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
self.find_preset_temp(new_preset)
|
self.find_preset_temp(new_preset)
|
||||||
)
|
)
|
||||||
self.recalculate()
|
self.recalculate()
|
||||||
await self._async_control_heating(force=True)
|
await self.async_control_heating(force=True)
|
||||||
self._motion_call_cancel = None
|
self._motion_call_cancel = None
|
||||||
|
|
||||||
im_on = self._motion_state == STATE_ON
|
im_on = self._motion_state == STATE_ON
|
||||||
@@ -1519,7 +1519,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
if changes:
|
if changes:
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
self.update_custom_attributes()
|
self.update_custom_attributes()
|
||||||
await self._async_control_heating()
|
await self.async_control_heating()
|
||||||
|
|
||||||
new_state = event.data.get("new_state")
|
new_state = event.data.get("new_state")
|
||||||
_LOGGER.debug("%s - _async_climate_changed new_state is %s", self, new_state)
|
_LOGGER.debug("%s - _async_climate_changed new_state is %s", self, new_state)
|
||||||
@@ -1746,7 +1746,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
self._current_power = current_power
|
self._current_power = current_power
|
||||||
|
|
||||||
if self._attr_preset_mode == PRESET_POWER:
|
if self._attr_preset_mode == PRESET_POWER:
|
||||||
await self._async_control_heating()
|
await self.async_control_heating()
|
||||||
|
|
||||||
except ValueError as ex:
|
except ValueError as ex:
|
||||||
_LOGGER.error("Unable to update current_power from sensor: %s", ex)
|
_LOGGER.error("Unable to update current_power from sensor: %s", ex)
|
||||||
@@ -1771,7 +1771,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
raise ValueError(f"Sensor has illegal state {new_state.state}")
|
raise ValueError(f"Sensor has illegal state {new_state.state}")
|
||||||
self._current_power_max = current_power_max
|
self._current_power_max = current_power_max
|
||||||
if self._attr_preset_mode == PRESET_POWER:
|
if self._attr_preset_mode == PRESET_POWER:
|
||||||
await self._async_control_heating()
|
await self.async_control_heating()
|
||||||
|
|
||||||
except ValueError as ex:
|
except ValueError as ex:
|
||||||
_LOGGER.error("Unable to update current_power from sensor: %s", ex)
|
_LOGGER.error("Unable to update current_power from sensor: %s", ex)
|
||||||
@@ -1791,7 +1791,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
return
|
return
|
||||||
|
|
||||||
await self._async_update_presence(new_state.state)
|
await self._async_update_presence(new_state.state)
|
||||||
await self._async_control_heating(force=True)
|
await self.async_control_heating(force=True)
|
||||||
|
|
||||||
async def _async_update_presence(self, new_state):
|
async def _async_update_presence(self, new_state):
|
||||||
_LOGGER.debug("%s - Updating presence. New state is %s", self, new_state)
|
_LOGGER.debug("%s - Updating presence. New state is %s", self, new_state)
|
||||||
@@ -2237,7 +2237,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
|
|
||||||
return shouldBeInSecurity
|
return shouldBeInSecurity
|
||||||
|
|
||||||
async def _async_control_heating(self, force=False, _=None):
|
async def async_control_heating(self, force=False, _=None):
|
||||||
"""The main function used to run the calculation at each cycle"""
|
"""The main function used to run the calculation at each cycle"""
|
||||||
|
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
@@ -2278,18 +2278,18 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
if self._hvac_mode == HVACMode.OFF:
|
if self._hvac_mode == HVACMode.OFF:
|
||||||
_LOGGER.debug("%s - End of cycle (HVAC_MODE_OFF)", self)
|
_LOGGER.debug("%s - End of cycle (HVAC_MODE_OFF)", self)
|
||||||
# A security to force stop heater if still active
|
# A security to force stop heater if still active
|
||||||
if self._is_device_active:
|
if self.is_device_active:
|
||||||
await self._async_underlying_entity_turn_off()
|
await self._async_underlying_entity_turn_off()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if not self.is_over_climate:
|
for under in self._underlyings:
|
||||||
for under in self._underlyings:
|
await under.start_cycle(
|
||||||
await under.start_cycle(
|
self._hvac_mode,
|
||||||
self._hvac_mode,
|
self._prop_algorithm.on_time_sec if self._prop_algorithm else None,
|
||||||
self._prop_algorithm.on_time_sec,
|
self._prop_algorithm.off_time_sec if self._prop_algorithm else None,
|
||||||
self._prop_algorithm.off_time_sec,
|
self._prop_algorithm.on_percent if self._prop_algorithm else None,
|
||||||
force,
|
force,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.update_custom_attributes()
|
self.update_custom_attributes()
|
||||||
return True
|
return True
|
||||||
@@ -2329,6 +2329,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
self._total_energy,
|
self._total_energy,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# TODO implement this with overrides
|
||||||
def update_custom_attributes(self):
|
def update_custom_attributes(self):
|
||||||
"""Update the custom extra attributes for the entity"""
|
"""Update the custom extra attributes for the entity"""
|
||||||
|
|
||||||
@@ -2459,7 +2460,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
"""
|
"""
|
||||||
_LOGGER.info("%s - Calling service_set_presence, presence: %s", self, presence)
|
_LOGGER.info("%s - Calling service_set_presence, presence: %s", self, presence)
|
||||||
await self._async_update_presence(presence)
|
await self._async_update_presence(presence)
|
||||||
await self._async_control_heating(force=True)
|
await self.async_control_heating(force=True)
|
||||||
|
|
||||||
async def service_set_preset_temperature(
|
async def service_set_preset_temperature(
|
||||||
self, preset, temperature=None, temperature_away=None
|
self, preset, temperature=None, temperature_away=None
|
||||||
@@ -2498,7 +2499,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
await self._async_set_preset_mode_internal(
|
await self._async_set_preset_mode_internal(
|
||||||
preset.rstrip(PRESET_AC_SUFFIX), force=True
|
preset.rstrip(PRESET_AC_SUFFIX), force=True
|
||||||
)
|
)
|
||||||
await self._async_control_heating(force=True)
|
await self.async_control_heating(force=True)
|
||||||
|
|
||||||
async def service_set_security(self, delay_min, min_on_percent, default_on_percent):
|
async def service_set_security(self, delay_min, min_on_percent, default_on_percent):
|
||||||
"""Called by a service call:
|
"""Called by a service call:
|
||||||
@@ -2527,7 +2528,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
if self._prop_algorithm and self._security_state:
|
if self._prop_algorithm and self._security_state:
|
||||||
self._prop_algorithm.set_security(self._security_default_on_percent)
|
self._prop_algorithm.set_security(self._security_default_on_percent)
|
||||||
|
|
||||||
await self._async_control_heating()
|
await self.async_control_heating()
|
||||||
self.update_custom_attributes()
|
self.update_custom_attributes()
|
||||||
|
|
||||||
def send_event(self, event_type: EventType, data: dict):
|
def send_event(self, event_type: EventType, data: dict):
|
||||||
|
|||||||
@@ -227,3 +227,14 @@ class UnknownEntity(HomeAssistantError):
|
|||||||
|
|
||||||
class WindowOpenDetectionMethod(HomeAssistantError):
|
class WindowOpenDetectionMethod(HomeAssistantError):
|
||||||
"""Error to indicate there is an error in the window open detection method given."""
|
"""Error to indicate there is an error in the window open detection method given."""
|
||||||
|
|
||||||
|
class overrides: # pylint: disable=invalid-name
|
||||||
|
""" An annotation to inform overrides """
|
||||||
|
def __init__(self, func):
|
||||||
|
self.func = func
|
||||||
|
|
||||||
|
def __get__(self, instance, owner):
|
||||||
|
return self.func.__get__(instance, owner)
|
||||||
|
|
||||||
|
def __call__(self, *args, **kwargs):
|
||||||
|
raise RuntimeError(f"Method {self.func.__name__} should have been overridden")
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class ThermostatOverClimate(BaseThermostat):
|
|||||||
super().__init__(hass, unique_id, name, entry_infos)
|
super().__init__(hass, unique_id, name, entry_infos)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_over_climate(self):
|
def is_over_climate(self) -> bool:
|
||||||
""" True if the Thermostat is over_climate"""
|
""" True if the Thermostat is over_climate"""
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -93,7 +93,7 @@ class ThermostatOverClimate(BaseThermostat):
|
|||||||
self.async_on_remove(
|
self.async_on_remove(
|
||||||
async_track_time_interval(
|
async_track_time_interval(
|
||||||
self.hass,
|
self.hass,
|
||||||
self._async_control_heating,
|
self.async_control_heating,
|
||||||
interval=timedelta(minutes=self._cycle_min),
|
interval=timedelta(minutes=self._cycle_min),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class ThermostatOverSwitch(BaseThermostat):
|
|||||||
super().__init__(hass, unique_id, name, entry_infos)
|
super().__init__(hass, unique_id, name, entry_infos)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_over_switch(self):
|
def is_over_switch(self) -> bool:
|
||||||
""" True if the Thermostat is over_switch"""
|
""" True if the Thermostat is over_switch"""
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -65,4 +65,4 @@ class ThermostatOverSwitch(BaseThermostat):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
self.hass.create_task(self._async_control_heating())
|
self.hass.create_task(self.async_control_heating())
|
||||||
|
|||||||
@@ -24,10 +24,15 @@ class ThermostatOverValve(BaseThermostat):
|
|||||||
super().__init__(hass, unique_id, name, entry_infos)
|
super().__init__(hass, unique_id, name, entry_infos)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_over_valve(self):
|
def is_over_valve(self) -> bool:
|
||||||
""" True if the Thermostat is over_valve"""
|
""" True if the Thermostat is over_valve"""
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def valve_open_percent(self) -> int:
|
||||||
|
""" Gives the percentage of valve needed"""
|
||||||
|
return round(max(0, min(self.proportional_algorithm.on_percent, 1)) * 100)
|
||||||
|
|
||||||
def post_init(self, entry_infos):
|
def post_init(self, entry_infos):
|
||||||
""" Initialize the Thermostat"""
|
""" Initialize the Thermostat"""
|
||||||
|
|
||||||
@@ -40,7 +45,7 @@ class ThermostatOverValve(BaseThermostat):
|
|||||||
if entry_infos.get(CONF_VALVE_4):
|
if entry_infos.get(CONF_VALVE_4):
|
||||||
lst_valves.append(entry_infos.get(CONF_VALVE_4))
|
lst_valves.append(entry_infos.get(CONF_VALVE_4))
|
||||||
|
|
||||||
for valve in enumerate(lst_valves):
|
for _, valve in enumerate(lst_valves):
|
||||||
self._underlyings.append(
|
self._underlyings.append(
|
||||||
UnderlyingValve(
|
UnderlyingValve(
|
||||||
hass=self._hass,
|
hass=self._hass,
|
||||||
@@ -68,7 +73,7 @@ class ThermostatOverValve(BaseThermostat):
|
|||||||
self.async_on_remove(
|
self.async_on_remove(
|
||||||
async_track_time_interval(
|
async_track_time_interval(
|
||||||
self.hass,
|
self.hass,
|
||||||
self._async_control_heating,
|
self.async_control_heating,
|
||||||
interval=timedelta(minutes=self._cycle_min),
|
interval=timedelta(minutes=self._cycle_min),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -90,7 +95,7 @@ class ThermostatOverValve(BaseThermostat):
|
|||||||
if changes:
|
if changes:
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
self.update_custom_attributes()
|
self.update_custom_attributes()
|
||||||
await self._async_control_heating()
|
await self.async_control_heating()
|
||||||
|
|
||||||
new_state = event.data.get("new_state")
|
new_state = event.data.get("new_state")
|
||||||
_LOGGER.debug("%s - _async_climate_changed new_state is %s", self, new_state)
|
_LOGGER.debug("%s - _async_climate_changed new_state is %s", self, new_state)
|
||||||
|
|||||||
@@ -24,10 +24,13 @@ from homeassistant.components.climate import (
|
|||||||
SERVICE_TURN_ON,
|
SERVICE_TURN_ON,
|
||||||
SERVICE_SET_TEMPERATURE,
|
SERVICE_SET_TEMPERATURE,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from homeassistant.components.number import SERVICE_SET_VALUE
|
||||||
|
|
||||||
from homeassistant.helpers.entity_component import EntityComponent
|
from homeassistant.helpers.entity_component import EntityComponent
|
||||||
from homeassistant.helpers.event import async_call_later
|
from homeassistant.helpers.event import async_call_later
|
||||||
|
|
||||||
from .const import UnknownEntity
|
from .const import UnknownEntity, overrides
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -160,6 +163,19 @@ class UnderlyingEntity:
|
|||||||
"""Call the method after a delay"""
|
"""Call the method after a delay"""
|
||||||
return async_call_later(hass, delay_sec, called_method)
|
return async_call_later(hass, delay_sec, called_method)
|
||||||
|
|
||||||
|
async def start_cycle(
|
||||||
|
self,
|
||||||
|
hvac_mode: HVACMode,
|
||||||
|
on_time_sec: int,
|
||||||
|
off_time_sec: int,
|
||||||
|
on_percent: int,
|
||||||
|
force=False,
|
||||||
|
):
|
||||||
|
"""Starting cycle for switch"""
|
||||||
|
|
||||||
|
def _cancel_cycle(self):
|
||||||
|
""" Stops an eventual cycle """
|
||||||
|
|
||||||
|
|
||||||
class UnderlyingSwitch(UnderlyingEntity):
|
class UnderlyingSwitch(UnderlyingEntity):
|
||||||
"""Represent a underlying switch"""
|
"""Represent a underlying switch"""
|
||||||
@@ -215,11 +231,13 @@ class UnderlyingSwitch(UnderlyingEntity):
|
|||||||
"""If the toggleable device is currently active."""
|
"""If the toggleable device is currently active."""
|
||||||
return self._hass.states.is_state(self._entity_id, STATE_ON)
|
return self._hass.states.is_state(self._entity_id, STATE_ON)
|
||||||
|
|
||||||
|
@overrides
|
||||||
async def start_cycle(
|
async def start_cycle(
|
||||||
self,
|
self,
|
||||||
hvac_mode: HVACMode,
|
hvac_mode: HVACMode,
|
||||||
on_time_sec: int,
|
on_time_sec: int,
|
||||||
off_time_sec: int,
|
off_time_sec: int,
|
||||||
|
on_percent: int,
|
||||||
force=False,
|
force=False,
|
||||||
):
|
):
|
||||||
"""Starting cycle for switch"""
|
"""Starting cycle for switch"""
|
||||||
@@ -270,6 +288,7 @@ class UnderlyingSwitch(UnderlyingEntity):
|
|||||||
else:
|
else:
|
||||||
_LOGGER.debug("%s - nothing to do", self)
|
_LOGGER.debug("%s - nothing to do", self)
|
||||||
|
|
||||||
|
@overrides
|
||||||
def _cancel_cycle(self):
|
def _cancel_cycle(self):
|
||||||
"""Cancel the cycle"""
|
"""Cancel the cycle"""
|
||||||
if self._async_cancel_cycle:
|
if self._async_cancel_cycle:
|
||||||
@@ -303,15 +322,6 @@ class UnderlyingSwitch(UnderlyingEntity):
|
|||||||
time = self._on_time_sec
|
time = self._on_time_sec
|
||||||
|
|
||||||
action_label = "start"
|
action_label = "start"
|
||||||
# if self._should_relaunch_control_heating:
|
|
||||||
# _LOGGER.debug("Don't %s cause a cycle have to be relaunch", action_label)
|
|
||||||
# self._should_relaunch_control_heating = False
|
|
||||||
# # self.hass.create_task(self._async_control_heating())
|
|
||||||
# await self.start_cycle(
|
|
||||||
# self._hvac_mode, self._on_time_sec, self._off_time_sec
|
|
||||||
# )
|
|
||||||
# _LOGGER.debug("%s - End of cycle (3)", self)
|
|
||||||
# return
|
|
||||||
|
|
||||||
if time > 0:
|
if time > 0:
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
@@ -348,16 +358,6 @@ class UnderlyingSwitch(UnderlyingEntity):
|
|||||||
return
|
return
|
||||||
|
|
||||||
action_label = "stop"
|
action_label = "stop"
|
||||||
# if self._should_relaunch_control_heating:
|
|
||||||
# _LOGGER.debug("Don't %s cause a cycle have to be relaunch", action_label)
|
|
||||||
# self._should_relaunch_control_heating = False
|
|
||||||
# # self.hass.create_task(self._async_control_heating())
|
|
||||||
# await self.start_cycle(
|
|
||||||
# self._hvac_mode, self._on_time_sec, self._off_time_sec
|
|
||||||
# )
|
|
||||||
# _LOGGER.debug("%s - End of cycle (3)", self)
|
|
||||||
# return
|
|
||||||
|
|
||||||
time = self._off_time_sec
|
time = self._off_time_sec
|
||||||
|
|
||||||
if time > 0:
|
if time > 0:
|
||||||
@@ -636,7 +636,7 @@ class UnderlyingValve(UnderlyingEntity):
|
|||||||
"""Represent a underlying switch"""
|
"""Represent a underlying switch"""
|
||||||
|
|
||||||
_hvac_mode: HVACMode
|
_hvac_mode: HVACMode
|
||||||
# The percentage of opening the valve
|
# This is the percentage of opening int integer (from 0 to 100)
|
||||||
_percent_open: int
|
_percent_open: int
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@@ -656,7 +656,7 @@ class UnderlyingValve(UnderlyingEntity):
|
|||||||
self._async_cancel_cycle = None
|
self._async_cancel_cycle = None
|
||||||
self._should_relaunch_control_heating = False
|
self._should_relaunch_control_heating = False
|
||||||
self._hvac_mode = None
|
self._hvac_mode = None
|
||||||
self._percent_open = 0
|
self._percent_open = self._thermostat.valve_open_percent
|
||||||
|
|
||||||
async def set_hvac_mode(self, hvac_mode: HVACMode) -> bool:
|
async def set_hvac_mode(self, hvac_mode: HVACMode) -> bool:
|
||||||
"""Set the HVACmode. Returns true if something have change"""
|
"""Set the HVACmode. Returns true if something have change"""
|
||||||
@@ -680,132 +680,35 @@ class UnderlyingValve(UnderlyingEntity):
|
|||||||
except Exception: # pylint: disable=broad-exception-caught
|
except Exception: # pylint: disable=broad-exception-caught
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@overrides
|
||||||
async def start_cycle(
|
async def start_cycle(
|
||||||
self,
|
self,
|
||||||
hvac_mode: HVACMode,
|
hvac_mode: HVACMode,
|
||||||
|
_1,
|
||||||
|
_2,
|
||||||
|
_3,
|
||||||
force=False,
|
force=False,
|
||||||
):
|
):
|
||||||
"""Starting cycle for switch"""
|
"""We use this function to change the on_percent"""
|
||||||
_LOGGER.debug(
|
caped_val = self._thermostat.valve_open_percent
|
||||||
"%s - Starting new cycle hvac_mode=%s percent_open=%d force=%s",
|
if not force and self._percent_open == caped_val:
|
||||||
self,
|
# No changes
|
||||||
hvac_mode,
|
return
|
||||||
self._percent_open,
|
|
||||||
force,
|
|
||||||
)
|
|
||||||
|
|
||||||
self._hvac_mode = hvac_mode
|
self._percent_open = caped_val
|
||||||
|
# Send the new command to valve via a service call
|
||||||
|
|
||||||
# Cancel eventual previous cycle if any
|
try:
|
||||||
if self._async_cancel_cycle is not None:
|
_LOGGER.info("%s - Setting valve ouverture percent to %s", self, self._percent_open)
|
||||||
if force:
|
|
||||||
_LOGGER.debug("%s - we force a new cycle", self)
|
|
||||||
self._cancel_cycle()
|
|
||||||
else:
|
|
||||||
_LOGGER.debug(
|
|
||||||
"%s - A previous cycle is alredy running and no force -> waits for its end",
|
|
||||||
self,
|
|
||||||
)
|
|
||||||
# self._should_relaunch_control_heating = True
|
|
||||||
_LOGGER.debug("%s - End of cycle (2)", self)
|
|
||||||
return
|
|
||||||
|
|
||||||
# If we should heat, starts the cycle with delay
|
data = { "value": self._percent_open }
|
||||||
if self._hvac_mode in [HVACMode.HEAT, HVACMode.COOL] and self._percent_open > 0:
|
await self._hass.services.async_call(
|
||||||
# Starts the cycle after the initial delay
|
HA_DOMAIN,
|
||||||
self._async_cancel_cycle = self.call_later(
|
SERVICE_SET_VALUE,
|
||||||
self._hass, 0, self._turn_on_later
|
data,
|
||||||
)
|
)
|
||||||
_LOGGER.debug("%s - _async_cancel_cycle=%s", self, self._async_cancel_cycle)
|
except ServiceNotFound as err:
|
||||||
|
_LOGGER.error(err)
|
||||||
# if we not heat but device is active
|
|
||||||
elif self.is_device_active:
|
|
||||||
_LOGGER.info(
|
|
||||||
"%s - stop heating (2)",
|
|
||||||
self,
|
|
||||||
)
|
|
||||||
await self.turn_off()
|
|
||||||
else:
|
|
||||||
_LOGGER.debug("%s - nothing to do", self)
|
|
||||||
|
|
||||||
def _cancel_cycle(self):
|
|
||||||
"""Cancel the cycle"""
|
|
||||||
if self._async_cancel_cycle:
|
|
||||||
self._async_cancel_cycle()
|
|
||||||
self._async_cancel_cycle = None
|
|
||||||
_LOGGER.debug("%s - Stopping cycle during calculation", self)
|
|
||||||
|
|
||||||
async def _turn_on_later(self, _):
|
|
||||||
"""Turn the heater on after a delay"""
|
|
||||||
_LOGGER.debug(
|
|
||||||
"%s - calling turn_on_later hvac_mode=%s, should_relaunch_later=%s",
|
|
||||||
self,
|
|
||||||
self._hvac_mode,
|
|
||||||
self._should_relaunch_control_heating,
|
|
||||||
)
|
|
||||||
|
|
||||||
self._cancel_cycle()
|
|
||||||
|
|
||||||
if self._hvac_mode == HVACMode.OFF:
|
|
||||||
_LOGGER.debug("%s - End of cycle (HVAC_MODE_OFF - 2)", self)
|
|
||||||
if self.is_device_active:
|
|
||||||
await self.turn_off()
|
|
||||||
return
|
|
||||||
|
|
||||||
if await self._thermostat.check_overpowering():
|
|
||||||
_LOGGER.debug("%s - End of cycle (3)", self)
|
|
||||||
return
|
|
||||||
# Security mode could have change the on_time percent
|
|
||||||
await self._thermostat.check_security()
|
|
||||||
|
|
||||||
action_label = "start"
|
|
||||||
|
|
||||||
_LOGGER.info(
|
|
||||||
"%s - %s heating",
|
|
||||||
self,
|
|
||||||
action_label,
|
|
||||||
)
|
|
||||||
await self.turn_on()
|
|
||||||
|
|
||||||
self._async_cancel_cycle = self.call_later(
|
|
||||||
self._hass,
|
|
||||||
0,
|
|
||||||
self._turn_off_later,
|
|
||||||
)
|
|
||||||
|
|
||||||
async def _turn_off_later(self, _):
|
|
||||||
"""Turn the heater off and call the next cycle after the delay"""
|
|
||||||
_LOGGER.debug(
|
|
||||||
"%s - calling turn_off_later hvac_mode=%s, should_relaunch_later=%s",
|
|
||||||
self,
|
|
||||||
self._hvac_mode,
|
|
||||||
self._should_relaunch_control_heating,
|
|
||||||
)
|
|
||||||
self._cancel_cycle()
|
|
||||||
|
|
||||||
if self._hvac_mode == HVACMode.OFF:
|
|
||||||
_LOGGER.debug("%s - End of cycle (HVAC_MODE_OFF - 2)", self)
|
|
||||||
if self.is_device_active:
|
|
||||||
await self.turn_off()
|
|
||||||
return
|
|
||||||
|
|
||||||
action_label = "stop"
|
|
||||||
|
|
||||||
_LOGGER.info(
|
|
||||||
"%s - %s heating",
|
|
||||||
self,
|
|
||||||
action_label
|
|
||||||
)
|
|
||||||
await self.turn_off()
|
|
||||||
|
|
||||||
self._async_cancel_cycle = self.call_later(
|
|
||||||
self._hass,
|
|
||||||
0,
|
|
||||||
self._turn_on_later
|
|
||||||
)
|
|
||||||
|
|
||||||
# increment energy at the end of the cycle
|
|
||||||
self._thermostat.incremente_energy()
|
|
||||||
|
|
||||||
def remove_entity(self):
|
def remove_entity(self):
|
||||||
"""Remove the entity after stopping its cycle"""
|
"""Remove the entity after stopping its cycle"""
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ def skip_hass_states_get_fixture():
|
|||||||
def skip_control_heating_fixture():
|
def skip_control_heating_fixture():
|
||||||
"""Skip the control_heating of VersatileThermostat"""
|
"""Skip the control_heating of VersatileThermostat"""
|
||||||
with patch(
|
with patch(
|
||||||
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat._async_control_heating"
|
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.async_control_heating"
|
||||||
):
|
):
|
||||||
yield
|
yield
|
||||||
|
|
||||||
|
|||||||
@@ -62,9 +62,9 @@ async def test_bug_56(
|
|||||||
# Should not failed
|
# Should not failed
|
||||||
entity.update_custom_attributes()
|
entity.update_custom_attributes()
|
||||||
|
|
||||||
# try to call _async_control_heating
|
# try to call async_control_heating
|
||||||
try:
|
try:
|
||||||
ret = await entity._async_control_heating()
|
ret = await entity.async_control_heating()
|
||||||
# an exception should be send
|
# an exception should be send
|
||||||
assert ret is False
|
assert ret is False
|
||||||
except Exception: # pylint: disable=broad-exception-caught
|
except Exception: # pylint: disable=broad-exception-caught
|
||||||
@@ -75,9 +75,9 @@ async def test_bug_56(
|
|||||||
"custom_components.versatile_thermostat.underlyings.UnderlyingClimate.find_underlying_climate",
|
"custom_components.versatile_thermostat.underlyings.UnderlyingClimate.find_underlying_climate",
|
||||||
return_value=the_mock_underlying, # dont find the underlying climate
|
return_value=the_mock_underlying, # dont find the underlying climate
|
||||||
):
|
):
|
||||||
# try to call _async_control_heating
|
# try to call async_control_heating
|
||||||
try:
|
try:
|
||||||
await entity._async_control_heating()
|
await entity.async_control_heating()
|
||||||
except UnknownEntity:
|
except UnknownEntity:
|
||||||
assert False
|
assert False
|
||||||
except Exception: # pylint: disable=broad-exception-caught
|
except Exception: # pylint: disable=broad-exception-caught
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ async def test_movement_management_time_not_enough(
|
|||||||
|
|
||||||
# start heating, in boost mode, when someone is present. We block the control_heating to avoid running a cycle
|
# start heating, in boost mode, when someone is present. We block the control_heating to avoid running a cycle
|
||||||
with patch(
|
with patch(
|
||||||
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat._async_control_heating"
|
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.async_control_heating"
|
||||||
):
|
):
|
||||||
await entity.async_set_hvac_mode(HVACMode.HEAT)
|
await entity.async_set_hvac_mode(HVACMode.HEAT)
|
||||||
await entity.async_set_preset_mode(PRESET_ACTIVITY)
|
await entity.async_set_preset_mode(PRESET_ACTIVITY)
|
||||||
@@ -261,7 +261,7 @@ async def test_movement_management_time_enough_and_presence(
|
|||||||
|
|
||||||
# start heating, in boost mode. We block the control_heating to avoid running a cycle
|
# start heating, in boost mode. We block the control_heating to avoid running a cycle
|
||||||
with patch(
|
with patch(
|
||||||
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat._async_control_heating"
|
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.async_control_heating"
|
||||||
):
|
):
|
||||||
await entity.async_set_hvac_mode(HVACMode.HEAT)
|
await entity.async_set_hvac_mode(HVACMode.HEAT)
|
||||||
await entity.async_set_preset_mode(PRESET_ACTIVITY)
|
await entity.async_set_preset_mode(PRESET_ACTIVITY)
|
||||||
@@ -393,7 +393,7 @@ async def test_movement_management_time_enoughand_not_presence(
|
|||||||
|
|
||||||
# start heating, in boost mode. We block the control_heating to avoid running a cycle
|
# start heating, in boost mode. We block the control_heating to avoid running a cycle
|
||||||
with patch(
|
with patch(
|
||||||
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat._async_control_heating"
|
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.async_control_heating"
|
||||||
):
|
):
|
||||||
await entity.async_set_hvac_mode(HVACMode.HEAT)
|
await entity.async_set_hvac_mode(HVACMode.HEAT)
|
||||||
await entity.async_set_preset_mode(PRESET_ACTIVITY)
|
await entity.async_set_preset_mode(PRESET_ACTIVITY)
|
||||||
@@ -527,7 +527,7 @@ async def test_movement_management_with_stop_during_condition(
|
|||||||
|
|
||||||
# start heating, in boost mode. We block the control_heating to avoid running a cycle
|
# start heating, in boost mode. We block the control_heating to avoid running a cycle
|
||||||
with patch(
|
with patch(
|
||||||
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat._async_control_heating"
|
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.async_control_heating"
|
||||||
):
|
):
|
||||||
await entity.async_set_hvac_mode(HVACMode.HEAT)
|
await entity.async_set_hvac_mode(HVACMode.HEAT)
|
||||||
await entity.async_set_preset_mode(PRESET_ACTIVITY)
|
await entity.async_set_preset_mode(PRESET_ACTIVITY)
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ async def test_one_switch_cycle(
|
|||||||
|
|
||||||
# start heating, in boost mode. We block the control_heating to avoid running a cycle
|
# start heating, in boost mode. We block the control_heating to avoid running a cycle
|
||||||
with patch(
|
with patch(
|
||||||
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat._async_control_heating"
|
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.async_control_heating"
|
||||||
):
|
):
|
||||||
await entity.async_set_hvac_mode(HVACMode.HEAT)
|
await entity.async_set_hvac_mode(HVACMode.HEAT)
|
||||||
await entity.async_set_preset_mode(PRESET_BOOST)
|
await entity.async_set_preset_mode(PRESET_BOOST)
|
||||||
@@ -75,7 +75,7 @@ async def test_one_switch_cycle(
|
|||||||
with patch(
|
with patch(
|
||||||
"homeassistant.core.StateMachine.is_state", return_value=False
|
"homeassistant.core.StateMachine.is_state", return_value=False
|
||||||
) as mock_is_state:
|
) as mock_is_state:
|
||||||
assert entity._is_device_active is False # pylint: disable=protected-access
|
assert entity.is_device_active is False # pylint: disable=protected-access
|
||||||
|
|
||||||
# Should be call for the Switch
|
# Should be call for the Switch
|
||||||
assert mock_is_state.call_count == 1
|
assert mock_is_state.call_count == 1
|
||||||
@@ -269,7 +269,7 @@ async def test_multiple_switchs(
|
|||||||
|
|
||||||
# start heating, in boost mode. We block the control_heating to avoid running a cycle
|
# start heating, in boost mode. We block the control_heating to avoid running a cycle
|
||||||
with patch(
|
with patch(
|
||||||
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat._async_control_heating"
|
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.async_control_heating"
|
||||||
), patch(
|
), patch(
|
||||||
"custom_components.versatile_thermostat.underlyings.UnderlyingSwitch.set_hvac_mode"
|
"custom_components.versatile_thermostat.underlyings.UnderlyingSwitch.set_hvac_mode"
|
||||||
) as mock_underlying_set_hvac_mode:
|
) as mock_underlying_set_hvac_mode:
|
||||||
@@ -285,7 +285,7 @@ async def test_multiple_switchs(
|
|||||||
await send_temperature_change_event(entity, 15, event_timestamp)
|
await send_temperature_change_event(entity, 15, event_timestamp)
|
||||||
|
|
||||||
# Checks that all climates are off
|
# Checks that all climates are off
|
||||||
assert entity._is_device_active is False # pylint: disable=protected-access
|
assert entity.is_device_active is False # pylint: disable=protected-access
|
||||||
|
|
||||||
# Should be call for all Switch
|
# Should be call for all Switch
|
||||||
assert mock_underlying_set_hvac_mode.call_count == 4
|
assert mock_underlying_set_hvac_mode.call_count == 4
|
||||||
@@ -405,7 +405,7 @@ async def test_multiple_climates(
|
|||||||
|
|
||||||
# start heating, in boost mode. We block the control_heating to avoid running a cycle
|
# start heating, in boost mode. We block the control_heating to avoid running a cycle
|
||||||
with patch(
|
with patch(
|
||||||
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat._async_control_heating"
|
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.async_control_heating"
|
||||||
), patch(
|
), patch(
|
||||||
"custom_components.versatile_thermostat.underlyings.UnderlyingClimate.set_hvac_mode"
|
"custom_components.versatile_thermostat.underlyings.UnderlyingClimate.set_hvac_mode"
|
||||||
) as mock_underlying_set_hvac_mode:
|
) as mock_underlying_set_hvac_mode:
|
||||||
@@ -427,11 +427,11 @@ async def test_multiple_climates(
|
|||||||
call.set_hvac_mode(HVACMode.HEAT),
|
call.set_hvac_mode(HVACMode.HEAT),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
assert entity._is_device_active is False # pylint: disable=protected-access
|
assert entity.is_device_active is False # pylint: disable=protected-access
|
||||||
|
|
||||||
# Stop heating, in boost mode. We block the control_heating to avoid running a cycle
|
# Stop heating, in boost mode. We block the control_heating to avoid running a cycle
|
||||||
with patch(
|
with patch(
|
||||||
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat._async_control_heating"
|
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.async_control_heating"
|
||||||
), patch(
|
), patch(
|
||||||
"custom_components.versatile_thermostat.underlyings.UnderlyingClimate.set_hvac_mode"
|
"custom_components.versatile_thermostat.underlyings.UnderlyingClimate.set_hvac_mode"
|
||||||
) as mock_underlying_set_hvac_mode:
|
) as mock_underlying_set_hvac_mode:
|
||||||
@@ -452,7 +452,7 @@ async def test_multiple_climates(
|
|||||||
call.set_hvac_mode(HVACMode.OFF),
|
call.set_hvac_mode(HVACMode.OFF),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
assert entity._is_device_active is False # pylint: disable=protected-access
|
assert entity.is_device_active is False # pylint: disable=protected-access
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||||
@@ -505,7 +505,7 @@ async def test_multiple_climates_underlying_changes(
|
|||||||
|
|
||||||
# start heating, in boost mode. We block the control_heating to avoid running a cycle
|
# start heating, in boost mode. We block the control_heating to avoid running a cycle
|
||||||
with patch(
|
with patch(
|
||||||
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat._async_control_heating"
|
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.async_control_heating"
|
||||||
), patch(
|
), patch(
|
||||||
"custom_components.versatile_thermostat.underlyings.UnderlyingClimate.set_hvac_mode"
|
"custom_components.versatile_thermostat.underlyings.UnderlyingClimate.set_hvac_mode"
|
||||||
) as mock_underlying_set_hvac_mode:
|
) as mock_underlying_set_hvac_mode:
|
||||||
@@ -527,11 +527,11 @@ async def test_multiple_climates_underlying_changes(
|
|||||||
call.set_hvac_mode(HVACMode.HEAT),
|
call.set_hvac_mode(HVACMode.HEAT),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
assert entity._is_device_active is False # pylint: disable=protected-access
|
assert entity.is_device_active is False # pylint: disable=protected-access
|
||||||
|
|
||||||
# Stop heating on one underlying climate
|
# Stop heating on one underlying climate
|
||||||
with patch(
|
with patch(
|
||||||
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat._async_control_heating"
|
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.async_control_heating"
|
||||||
), patch(
|
), patch(
|
||||||
"custom_components.versatile_thermostat.underlyings.UnderlyingClimate.set_hvac_mode"
|
"custom_components.versatile_thermostat.underlyings.UnderlyingClimate.set_hvac_mode"
|
||||||
) as mock_underlying_set_hvac_mode:
|
) as mock_underlying_set_hvac_mode:
|
||||||
@@ -554,11 +554,11 @@ async def test_multiple_climates_underlying_changes(
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
assert entity.hvac_mode == HVACMode.OFF
|
assert entity.hvac_mode == HVACMode.OFF
|
||||||
assert entity._is_device_active is False # pylint: disable=protected-access
|
assert entity.is_device_active is False # pylint: disable=protected-access
|
||||||
|
|
||||||
# Start heating on one underlying climate
|
# Start heating on one underlying climate
|
||||||
with patch(
|
with patch(
|
||||||
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat._async_control_heating"
|
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.async_control_heating"
|
||||||
), patch(
|
), patch(
|
||||||
"custom_components.versatile_thermostat.underlyings.UnderlyingClimate.set_hvac_mode"
|
"custom_components.versatile_thermostat.underlyings.UnderlyingClimate.set_hvac_mode"
|
||||||
) as mock_underlying_set_hvac_mode, patch(
|
) as mock_underlying_set_hvac_mode, patch(
|
||||||
@@ -587,4 +587,4 @@ async def test_multiple_climates_underlying_changes(
|
|||||||
)
|
)
|
||||||
assert entity.hvac_mode == HVACMode.HEAT
|
assert entity.hvac_mode == HVACMode.HEAT
|
||||||
assert entity.hvac_action == HVACAction.IDLE
|
assert entity.hvac_action == HVACAction.IDLE
|
||||||
assert entity._is_device_active is False # pylint: disable=protected-access
|
assert entity.is_device_active is False # pylint: disable=protected-access
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# pylint: disable=line-too-long
|
||||||
|
|
||||||
""" Test the normal start of a Switch AC Thermostat """
|
""" Test the normal start of a Switch AC Thermostat """
|
||||||
from unittest.mock import patch, call
|
from unittest.mock import patch, call
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
@@ -11,7 +13,6 @@ from homeassistant.components.climate import ClimateEntity, DOMAIN as CLIMATE_DO
|
|||||||
|
|
||||||
from pytest_homeassistant_custom_component.common import MockConfigEntry
|
from pytest_homeassistant_custom_component.common import MockConfigEntry
|
||||||
|
|
||||||
from custom_components.versatile_thermostat.base_thermostat import BaseThermostat
|
|
||||||
from custom_components.versatile_thermostat.thermostat_valve import ThermostatOverValve
|
from custom_components.versatile_thermostat.thermostat_valve import ThermostatOverValve
|
||||||
|
|
||||||
from .commons import * # pylint: disable=wildcard-import, unused-wildcard-import
|
from .commons import * # pylint: disable=wildcard-import, unused-wildcard-import
|
||||||
@@ -84,7 +85,7 @@ async def test_over_valve_full_start(hass: HomeAssistant, skip_hass_states_is_st
|
|||||||
return entity
|
return entity
|
||||||
|
|
||||||
# The name is in the CONF and not the title of the entry
|
# The name is in the CONF and not the title of the entry
|
||||||
entity: BaseThermostat = find_my_entity("climate.theovervalvemockname")
|
entity: ThermostatOverValve = find_my_entity("climate.theovervalvemockname")
|
||||||
|
|
||||||
assert entity
|
assert entity
|
||||||
assert isinstance(entity, ThermostatOverValve)
|
assert isinstance(entity, ThermostatOverValve)
|
||||||
@@ -114,7 +115,6 @@ async def test_over_valve_full_start(hass: HomeAssistant, skip_hass_states_is_st
|
|||||||
|
|
||||||
# should have been called with EventType.PRESET_EVENT and EventType.HVAC_MODE_EVENT
|
# should have been called with EventType.PRESET_EVENT and EventType.HVAC_MODE_EVENT
|
||||||
assert mock_send_event.call_count == 2
|
assert mock_send_event.call_count == 2
|
||||||
|
|
||||||
mock_send_event.assert_has_calls(
|
mock_send_event.assert_has_calls(
|
||||||
[
|
[
|
||||||
call.send_event(EventType.PRESET_EVENT, {"preset": PRESET_NONE}),
|
call.send_event(EventType.PRESET_EVENT, {"preset": PRESET_NONE}),
|
||||||
@@ -125,9 +125,73 @@ async def test_over_valve_full_start(hass: HomeAssistant, skip_hass_states_is_st
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Set the HVACMode to HEAT, with manual preset and target_temp to 18 before receiving temperature
|
||||||
|
with patch(
|
||||||
|
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event"
|
||||||
|
) as mock_send_event:
|
||||||
# Select a hvacmode, presence and preset
|
# Select a hvacmode, presence and preset
|
||||||
await entity.async_set_hvac_mode(HVACMode.COOL)
|
await entity.async_set_hvac_mode(HVACMode.HEAT)
|
||||||
assert entity.hvac_mode is HVACMode.COOL
|
#
|
||||||
|
assert entity.hvac_mode is HVACMode.HEAT
|
||||||
|
# No heating now
|
||||||
|
assert entity.valve_open_percent == 0
|
||||||
|
assert entity.hvac_action == HVACAction.IDLE
|
||||||
|
assert mock_send_event.call_count == 1
|
||||||
|
mock_send_event.assert_has_calls(
|
||||||
|
[
|
||||||
|
call.send_event(
|
||||||
|
EventType.HVAC_MODE_EVENT,
|
||||||
|
{"hvac_mode": HVACMode.HEAT},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
# set manual target temp
|
||||||
|
await entity.async_set_temperature(temperature=18)
|
||||||
|
assert entity.preset_mode == PRESET_NONE # Manual mode
|
||||||
|
assert entity.target_temperature == 18
|
||||||
|
# Nothing have changed cause we don't have room and external temperature
|
||||||
|
assert mock_send_event.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
|
# Set temperature and external temperature
|
||||||
|
with patch(
|
||||||
|
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event"
|
||||||
|
) as mock_send_event, patch(
|
||||||
|
"homeassistant.core.ServiceRegistry.async_call"
|
||||||
|
) as mock_service_call, patch(
|
||||||
|
"custom_components.versatile_thermostat.underlyings.UnderlyingValve.is_device_active", return_value=True
|
||||||
|
):
|
||||||
|
# Change temperature
|
||||||
|
event_timestamp = now - timedelta(minutes=10)
|
||||||
|
await send_temperature_change_event(entity, 15, datetime.now())
|
||||||
|
await send_ext_temperature_change_event(entity, 10, datetime.now())
|
||||||
|
# Should heating strongly now
|
||||||
|
assert entity.valve_open_percent == 98
|
||||||
|
assert entity.is_device_active is True
|
||||||
|
assert entity.hvac_action == HVACAction.HEATING
|
||||||
|
|
||||||
|
assert mock_service_call.call_count == 2
|
||||||
|
mock_service_call.assert_has_calls([
|
||||||
|
call.async_call(
|
||||||
|
HA_DOMAIN,
|
||||||
|
SERVICE_SET_VALUE,
|
||||||
|
{
|
||||||
|
"value": 90
|
||||||
|
}
|
||||||
|
),
|
||||||
|
call.async_call(
|
||||||
|
HA_DOMAIN,
|
||||||
|
SERVICE_SET_VALUE,
|
||||||
|
{
|
||||||
|
"value": 98
|
||||||
|
}
|
||||||
|
)
|
||||||
|
])
|
||||||
|
|
||||||
|
assert mock_send_event.call_count == 0
|
||||||
|
|
||||||
|
# ICI
|
||||||
|
|
||||||
event_timestamp = now - timedelta(minutes=4)
|
event_timestamp = now - timedelta(minutes=4)
|
||||||
await send_presence_change_event(entity, True, False, event_timestamp)
|
await send_presence_change_event(entity, True, False, event_timestamp)
|
||||||
|
|||||||
Reference in New Issue
Block a user