Compare commits
5 Commits
6.8.3
...
6.8.4.beta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f238df4e7 | ||
|
|
6226d26c6d | ||
|
|
9839ed4920 | ||
|
|
02f60770e8 | ||
|
|
23ddff95b3 |
@@ -82,6 +82,10 @@ T = TypeVar("T", bound=UnderlyingEntity)
|
|||||||
class BaseThermostat(ClimateEntity, RestoreEntity, Generic[T]):
|
class BaseThermostat(ClimateEntity, RestoreEntity, Generic[T]):
|
||||||
"""Representation of a base class for all Versatile Thermostat device."""
|
"""Representation of a base class for all Versatile Thermostat device."""
|
||||||
|
|
||||||
|
# breaking change with 2024.12 climate workaround
|
||||||
|
_attr_swing_horizontal_modes = []
|
||||||
|
_attr_swing_horizontal_mode = ""
|
||||||
|
|
||||||
_entity_component_unrecorded_attributes = (
|
_entity_component_unrecorded_attributes = (
|
||||||
ClimateEntity._entity_component_unrecorded_attributes.union(
|
ClimateEntity._entity_component_unrecorded_attributes.union(
|
||||||
frozenset(
|
frozenset(
|
||||||
@@ -127,7 +131,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity, Generic[T]):
|
|||||||
"max_power_sensor_entity_id",
|
"max_power_sensor_entity_id",
|
||||||
"temperature_unit",
|
"temperature_unit",
|
||||||
"is_device_active",
|
"is_device_active",
|
||||||
"nb_device_actives",
|
"device_actives",
|
||||||
"target_temperature_step",
|
"target_temperature_step",
|
||||||
"is_used_by_central_boiler",
|
"is_used_by_central_boiler",
|
||||||
"temperature_slope",
|
"temperature_slope",
|
||||||
@@ -997,14 +1001,19 @@ class BaseThermostat(ClimateEntity, RestoreEntity, Generic[T]):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def nb_device_actives(self) -> int:
|
def device_actives(self) -> int:
|
||||||
"""Calculate the number of active devices"""
|
"""Calculate the active devices"""
|
||||||
ret = 0
|
ret = []
|
||||||
for under in self._underlyings:
|
for under in self._underlyings:
|
||||||
if under.is_device_active:
|
if under.is_device_active:
|
||||||
ret += 1
|
ret.append(under.entity_id)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
@property
|
||||||
|
def nb_device_actives(self) -> int:
|
||||||
|
"""Calculate the number of active devices"""
|
||||||
|
return len(self.device_actives)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def current_temperature(self) -> float | None:
|
def current_temperature(self) -> float | None:
|
||||||
"""Return the sensor temperature."""
|
"""Return the sensor temperature."""
|
||||||
@@ -2676,6 +2685,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity, Generic[T]):
|
|||||||
"timezone": str(self._current_tz),
|
"timezone": str(self._current_tz),
|
||||||
"temperature_unit": self.temperature_unit,
|
"temperature_unit": self.temperature_unit,
|
||||||
"is_device_active": self.is_device_active,
|
"is_device_active": self.is_device_active,
|
||||||
|
"device_actives": self.device_actives,
|
||||||
"nb_device_actives": self.nb_device_actives,
|
"nb_device_actives": self.nb_device_actives,
|
||||||
"ema_temp": self._ema_temp,
|
"ema_temp": self._ema_temp,
|
||||||
"is_used_by_central_boiler": self.is_used_by_central_boiler,
|
"is_used_by_central_boiler": self.is_used_by_central_boiler,
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ async def async_setup_entry(
|
|||||||
SERVICE_SET_AUTO_REGULATION_MODE,
|
SERVICE_SET_AUTO_REGULATION_MODE,
|
||||||
{
|
{
|
||||||
vol.Required("auto_regulation_mode"): vol.In(
|
vol.Required("auto_regulation_mode"): vol.In(
|
||||||
["None", "Light", "Medium", "Strong", "Slow"]
|
["None", "Light", "Medium", "Strong", "Slow", "Expert"]
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
"service_set_auto_regulation_mode",
|
"service_set_auto_regulation_mode",
|
||||||
|
|||||||
@@ -644,6 +644,10 @@ class NbActiveDeviceForBoilerSensor(SensorEntity):
|
|||||||
"""Representation of the threshold of the number of VTherm
|
"""Representation of the threshold of the number of VTherm
|
||||||
which should be active to activate the boiler"""
|
which should be active to activate the boiler"""
|
||||||
|
|
||||||
|
_entity_component_unrecorded_attributes = SensorEntity._entity_component_unrecorded_attributes.union( # pylint: disable=protected-access
|
||||||
|
frozenset({"active_device_ids"})
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, hass: HomeAssistant, unique_id, name, entry_infos) -> None:
|
def __init__(self, hass: HomeAssistant, unique_id, name, entry_infos) -> None:
|
||||||
"""Initialize the energy sensor"""
|
"""Initialize the energy sensor"""
|
||||||
self._hass = hass
|
self._hass = hass
|
||||||
@@ -653,6 +657,14 @@ class NbActiveDeviceForBoilerSensor(SensorEntity):
|
|||||||
self._attr_unique_id = "nb_device_active_boiler"
|
self._attr_unique_id = "nb_device_active_boiler"
|
||||||
self._attr_value = self._attr_native_value = None # default value
|
self._attr_value = self._attr_native_value = None # default value
|
||||||
self._entities = []
|
self._entities = []
|
||||||
|
self._attr_active_device_ids = [] # Holds the entity ids of active devices
|
||||||
|
|
||||||
|
@property
|
||||||
|
def extra_state_attributes(self) -> dict:
|
||||||
|
"""Return additional attributes for the sensor."""
|
||||||
|
return {
|
||||||
|
"active_device_ids": self._attr_active_device_ids,
|
||||||
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def icon(self) -> str | None:
|
def icon(self) -> str | None:
|
||||||
@@ -718,19 +730,19 @@ class NbActiveDeviceForBoilerSensor(SensorEntity):
|
|||||||
self.calculate_nb_active_devices,
|
self.calculate_nb_active_devices,
|
||||||
)
|
)
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
"%s - the underlyings that could controls the central boiler are %s",
|
"%s - the underlyings that could control the central boiler are %s",
|
||||||
self,
|
self,
|
||||||
underlying_entities_id,
|
underlying_entities_id,
|
||||||
)
|
)
|
||||||
self.async_on_remove(listener_cancel)
|
self.async_on_remove(listener_cancel)
|
||||||
else:
|
else:
|
||||||
_LOGGER.debug("%s - no VTherm could controls the central boiler", self)
|
_LOGGER.debug("%s - no VTherm could control the central boiler", self)
|
||||||
|
|
||||||
await self.calculate_nb_active_devices(None)
|
await self.calculate_nb_active_devices(None)
|
||||||
|
|
||||||
async def calculate_nb_active_devices(self, event: Event):
|
async def calculate_nb_active_devices(self, event: Event):
|
||||||
"""Calculate the number of active VTherm that have an
|
"""Calculate the number of active VTherm that have an
|
||||||
influence on central boiler"""
|
influence on the central boiler and update the list of active device names."""
|
||||||
|
|
||||||
# _LOGGER.debug("%s- calculate_nb_active_devices - the event is %s ", self, event)
|
# _LOGGER.debug("%s- calculate_nb_active_devices - the event is %s ", self, event)
|
||||||
|
|
||||||
@@ -757,6 +769,8 @@ class NbActiveDeviceForBoilerSensor(SensorEntity):
|
|||||||
old_state is not None
|
old_state is not None
|
||||||
and new_state.state == old_state.state
|
and new_state.state == old_state.state
|
||||||
and new_hvac_action == old_hvac_action
|
and new_hvac_action == old_hvac_action
|
||||||
|
# issue 698 - force recalculation when underlying climate doesn't have any hvac_action
|
||||||
|
and new_hvac_action is not None
|
||||||
):
|
):
|
||||||
# A false state change
|
# A false state change
|
||||||
return
|
return
|
||||||
@@ -774,20 +788,28 @@ class NbActiveDeviceForBoilerSensor(SensorEntity):
|
|||||||
)
|
)
|
||||||
|
|
||||||
nb_active = 0
|
nb_active = 0
|
||||||
|
active_device_ids = []
|
||||||
|
|
||||||
for entity in self._entities:
|
for entity in self._entities:
|
||||||
nb_active += entity.nb_device_actives
|
device_actives = entity.device_actives
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"After examining the hvac_action of %s, nb_active is %s",
|
"After examining the hvac_action of %s, device_actives is %s",
|
||||||
entity.name,
|
entity.name,
|
||||||
nb_active,
|
device_actives,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
nb_active += len(device_actives)
|
||||||
|
active_device_ids.extend(device_actives)
|
||||||
|
|
||||||
self._attr_native_value = nb_active
|
self._attr_native_value = nb_active
|
||||||
_LOGGER.debug(
|
self._attr_active_device_ids = active_device_ids
|
||||||
"%s - Number of active underlying entities is %s", self, nb_active
|
|
||||||
)
|
|
||||||
|
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def active_device_ids(self) -> list:
|
||||||
|
"""Get the list of active device id"""
|
||||||
|
return self._attr_active_device_ids
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"VersatileThermostat-{self.name}"
|
return f"VersatileThermostat-{self.name}"
|
||||||
|
|||||||
@@ -277,12 +277,15 @@ class ThermostatOverClimateValve(ThermostatOverClimate):
|
|||||||
return self.valve_open_percent > 0
|
return self.valve_open_percent > 0
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def nb_device_actives(self) -> int:
|
def device_actives(self) -> int:
|
||||||
"""Calculate the number of active devices"""
|
"""Calculate the number of active devices"""
|
||||||
if self.is_device_active:
|
if self.is_device_active:
|
||||||
return len(self._underlyings_valve_regulation)
|
return [
|
||||||
|
under.opening_degree_entity_id
|
||||||
|
for under in self._underlyings_valve_regulation
|
||||||
|
]
|
||||||
else:
|
else:
|
||||||
return 0
|
return []
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def activable_underlying_entities(self) -> list | None:
|
def activable_underlying_entities(self) -> list | None:
|
||||||
|
|||||||
@@ -579,6 +579,7 @@ class MockNumber(NumberEntity):
|
|||||||
def set_native_value(self, value: float):
|
def set_native_value(self, value: float):
|
||||||
"""Change the value"""
|
"""Change the value"""
|
||||||
self._attr_native_value = value
|
self._attr_native_value = value
|
||||||
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
|
||||||
async def create_thermostat(
|
async def create_thermostat(
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
""" Test the central_configuration """
|
""" Test the central_configuration """
|
||||||
import asyncio
|
import asyncio
|
||||||
from datetime import datetime
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
from unittest.mock import patch, call
|
from unittest.mock import patch, call
|
||||||
|
|
||||||
@@ -29,6 +29,8 @@ from custom_components.versatile_thermostat.binary_sensor import (
|
|||||||
CentralBoilerBinarySensor,
|
CentralBoilerBinarySensor,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from custom_components.versatile_thermostat.sensor import NbActiveDeviceForBoilerSensor
|
||||||
|
|
||||||
from .commons import * # pylint: disable=wildcard-import, unused-wildcard-import
|
from .commons import * # pylint: disable=wildcard-import, unused-wildcard-import
|
||||||
from .const import * # pylint: disable=wildcard-import, unused-wildcard-import
|
from .const import * # pylint: disable=wildcard-import, unused-wildcard-import
|
||||||
|
|
||||||
@@ -103,7 +105,7 @@ async def test_update_central_boiler_state_simple(
|
|||||||
CONF_USE_MOTION_FEATURE: False,
|
CONF_USE_MOTION_FEATURE: False,
|
||||||
CONF_USE_POWER_FEATURE: False,
|
CONF_USE_POWER_FEATURE: False,
|
||||||
CONF_USE_PRESENCE_FEATURE: False,
|
CONF_USE_PRESENCE_FEATURE: False,
|
||||||
CONF_HEATER: switch1.entity_id,
|
CONF_UNDERLYING_LIST: [switch1.entity_id],
|
||||||
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
|
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
|
||||||
CONF_INVERSE_SWITCH: False,
|
CONF_INVERSE_SWITCH: False,
|
||||||
CONF_TPI_COEF_INT: 0.3,
|
CONF_TPI_COEF_INT: 0.3,
|
||||||
@@ -147,6 +149,13 @@ async def test_update_central_boiler_state_simple(
|
|||||||
assert boiler_binary_sensor is not None
|
assert boiler_binary_sensor is not None
|
||||||
assert boiler_binary_sensor.state == STATE_OFF
|
assert boiler_binary_sensor.state == STATE_OFF
|
||||||
|
|
||||||
|
nb_device_active_sensor: NbActiveDeviceForBoilerSensor = search_entity(
|
||||||
|
hass, "sensor.nb_device_active_for_boiler", "sensor"
|
||||||
|
)
|
||||||
|
assert nb_device_active_sensor is not None
|
||||||
|
assert nb_device_active_sensor.state == 0
|
||||||
|
assert nb_device_active_sensor.active_device_ids == []
|
||||||
|
|
||||||
# 1. start a heater
|
# 1. start a heater
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.core.ServiceRegistry.async_call"
|
"homeassistant.core.ServiceRegistry.async_call"
|
||||||
@@ -195,6 +204,9 @@ async def test_update_central_boiler_state_simple(
|
|||||||
assert api.nb_active_device_for_boiler == 1
|
assert api.nb_active_device_for_boiler == 1
|
||||||
assert boiler_binary_sensor.state == STATE_ON
|
assert boiler_binary_sensor.state == STATE_ON
|
||||||
|
|
||||||
|
assert nb_device_active_sensor.state == 1
|
||||||
|
assert nb_device_active_sensor.active_device_ids == ["switch.switch1"]
|
||||||
|
|
||||||
# 2. stop a heater
|
# 2. stop a heater
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.core.ServiceRegistry.async_call"
|
"homeassistant.core.ServiceRegistry.async_call"
|
||||||
@@ -235,6 +247,9 @@ async def test_update_central_boiler_state_simple(
|
|||||||
assert api.nb_active_device_for_boiler == 0
|
assert api.nb_active_device_for_boiler == 0
|
||||||
assert boiler_binary_sensor.state == STATE_OFF
|
assert boiler_binary_sensor.state == STATE_OFF
|
||||||
|
|
||||||
|
assert nb_device_active_sensor.state == 0
|
||||||
|
assert nb_device_active_sensor.active_device_ids == []
|
||||||
|
|
||||||
entity.remove_thermostat()
|
entity.remove_thermostat()
|
||||||
|
|
||||||
|
|
||||||
@@ -272,10 +287,12 @@ async def test_update_central_boiler_state_multiple(
|
|||||||
CONF_USE_MOTION_FEATURE: False,
|
CONF_USE_MOTION_FEATURE: False,
|
||||||
CONF_USE_POWER_FEATURE: False,
|
CONF_USE_POWER_FEATURE: False,
|
||||||
CONF_USE_PRESENCE_FEATURE: False,
|
CONF_USE_PRESENCE_FEATURE: False,
|
||||||
CONF_HEATER: switch1.entity_id,
|
CONF_UNDERLYING_LIST: [
|
||||||
CONF_HEATER_2: switch2.entity_id,
|
switch1.entity_id,
|
||||||
CONF_HEATER_3: switch3.entity_id,
|
switch2.entity_id,
|
||||||
CONF_HEATER_4: switch4.entity_id,
|
switch3.entity_id,
|
||||||
|
switch4.entity_id,
|
||||||
|
],
|
||||||
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
|
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
|
||||||
CONF_INVERSE_SWITCH: False,
|
CONF_INVERSE_SWITCH: False,
|
||||||
CONF_TPI_COEF_INT: 0.3,
|
CONF_TPI_COEF_INT: 0.3,
|
||||||
@@ -302,10 +319,18 @@ async def test_update_central_boiler_state_multiple(
|
|||||||
assert entity.underlying_entities[1].entity_id == "switch.switch2"
|
assert entity.underlying_entities[1].entity_id == "switch.switch2"
|
||||||
assert entity.underlying_entities[2].entity_id == "switch.switch3"
|
assert entity.underlying_entities[2].entity_id == "switch.switch3"
|
||||||
assert entity.underlying_entities[3].entity_id == "switch.switch4"
|
assert entity.underlying_entities[3].entity_id == "switch.switch4"
|
||||||
assert entity.nb_device_actives == 0
|
assert entity.device_actives == []
|
||||||
|
|
||||||
assert api.nb_active_device_for_boiler_threshold == 1
|
assert api.nb_active_device_for_boiler_threshold == 1
|
||||||
assert api.nb_active_device_for_boiler == 0
|
assert api.nb_active_device_for_boiler == 0
|
||||||
|
|
||||||
|
nb_device_active_sensor: NbActiveDeviceForBoilerSensor = search_entity(
|
||||||
|
hass, "sensor.nb_device_active_for_boiler", "sensor"
|
||||||
|
)
|
||||||
|
assert nb_device_active_sensor is not None
|
||||||
|
assert nb_device_active_sensor.state == 0
|
||||||
|
assert nb_device_active_sensor.active_device_ids == []
|
||||||
|
|
||||||
# Force the VTherm to heat
|
# Force the VTherm to heat
|
||||||
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)
|
||||||
@@ -338,7 +363,7 @@ async def test_update_central_boiler_state_multiple(
|
|||||||
await asyncio.sleep(0.1)
|
await asyncio.sleep(0.1)
|
||||||
|
|
||||||
assert entity.hvac_action == HVACAction.HEATING
|
assert entity.hvac_action == HVACAction.HEATING
|
||||||
assert entity.nb_device_actives == 1
|
assert entity.device_actives == ["switch.switch1"]
|
||||||
|
|
||||||
assert mock_service_call.call_count == 1
|
assert mock_service_call.call_count == 1
|
||||||
# No switch of the boiler
|
# No switch of the boiler
|
||||||
@@ -356,6 +381,9 @@ async def test_update_central_boiler_state_multiple(
|
|||||||
assert api.nb_active_device_for_boiler == 1
|
assert api.nb_active_device_for_boiler == 1
|
||||||
assert boiler_binary_sensor.state == STATE_OFF
|
assert boiler_binary_sensor.state == STATE_OFF
|
||||||
|
|
||||||
|
assert nb_device_active_sensor.state == 1
|
||||||
|
assert nb_device_active_sensor.active_device_ids == ["switch.switch1"]
|
||||||
|
|
||||||
# 2. start a 2nd heater
|
# 2. start a 2nd heater
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.core.ServiceRegistry.async_call"
|
"homeassistant.core.ServiceRegistry.async_call"
|
||||||
@@ -368,7 +396,7 @@ async def test_update_central_boiler_state_multiple(
|
|||||||
await asyncio.sleep(0.1)
|
await asyncio.sleep(0.1)
|
||||||
|
|
||||||
assert entity.hvac_action == HVACAction.HEATING
|
assert entity.hvac_action == HVACAction.HEATING
|
||||||
assert entity.nb_device_actives == 2
|
assert entity.device_actives == ["switch.switch1", "switch.switch2"]
|
||||||
|
|
||||||
# Only the first heater is started by the algo
|
# Only the first heater is started by the algo
|
||||||
assert mock_service_call.call_count == 1
|
assert mock_service_call.call_count == 1
|
||||||
@@ -388,6 +416,12 @@ async def test_update_central_boiler_state_multiple(
|
|||||||
assert api.nb_active_device_for_boiler == 2
|
assert api.nb_active_device_for_boiler == 2
|
||||||
assert boiler_binary_sensor.state == STATE_OFF
|
assert boiler_binary_sensor.state == STATE_OFF
|
||||||
|
|
||||||
|
assert nb_device_active_sensor.state == 2
|
||||||
|
assert nb_device_active_sensor.active_device_ids == [
|
||||||
|
"switch.switch1",
|
||||||
|
"switch.switch2",
|
||||||
|
]
|
||||||
|
|
||||||
# 3. start a 3rd heater
|
# 3. start a 3rd heater
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.core.ServiceRegistry.async_call"
|
"homeassistant.core.ServiceRegistry.async_call"
|
||||||
@@ -436,6 +470,13 @@ async def test_update_central_boiler_state_multiple(
|
|||||||
assert api.nb_active_device_for_boiler == 3
|
assert api.nb_active_device_for_boiler == 3
|
||||||
assert boiler_binary_sensor.state == STATE_ON
|
assert boiler_binary_sensor.state == STATE_ON
|
||||||
|
|
||||||
|
assert nb_device_active_sensor.state == 3
|
||||||
|
assert nb_device_active_sensor.active_device_ids == [
|
||||||
|
"switch.switch1",
|
||||||
|
"switch.switch2",
|
||||||
|
"switch.switch3",
|
||||||
|
]
|
||||||
|
|
||||||
# 4. start a 4th heater
|
# 4. start a 4th heater
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.core.ServiceRegistry.async_call"
|
"homeassistant.core.ServiceRegistry.async_call"
|
||||||
@@ -466,6 +507,14 @@ async def test_update_central_boiler_state_multiple(
|
|||||||
assert api.nb_active_device_for_boiler == 4
|
assert api.nb_active_device_for_boiler == 4
|
||||||
assert boiler_binary_sensor.state == STATE_ON
|
assert boiler_binary_sensor.state == STATE_ON
|
||||||
|
|
||||||
|
assert nb_device_active_sensor.state == 4
|
||||||
|
assert nb_device_active_sensor.active_device_ids == [
|
||||||
|
"switch.switch1",
|
||||||
|
"switch.switch2",
|
||||||
|
"switch.switch3",
|
||||||
|
"switch.switch4",
|
||||||
|
]
|
||||||
|
|
||||||
# 5. stop a heater
|
# 5. stop a heater
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.core.ServiceRegistry.async_call"
|
"homeassistant.core.ServiceRegistry.async_call"
|
||||||
@@ -484,6 +533,13 @@ async def test_update_central_boiler_state_multiple(
|
|||||||
assert api.nb_active_device_for_boiler == 3
|
assert api.nb_active_device_for_boiler == 3
|
||||||
assert boiler_binary_sensor.state == STATE_ON
|
assert boiler_binary_sensor.state == STATE_ON
|
||||||
|
|
||||||
|
assert nb_device_active_sensor.state == 3
|
||||||
|
assert nb_device_active_sensor.active_device_ids == [
|
||||||
|
"switch.switch2",
|
||||||
|
"switch.switch3",
|
||||||
|
"switch.switch4",
|
||||||
|
]
|
||||||
|
|
||||||
# 6. stop a 2nd heater
|
# 6. stop a 2nd heater
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.core.ServiceRegistry.async_call"
|
"homeassistant.core.ServiceRegistry.async_call"
|
||||||
@@ -524,6 +580,12 @@ async def test_update_central_boiler_state_multiple(
|
|||||||
assert api.nb_active_device_for_boiler == 2
|
assert api.nb_active_device_for_boiler == 2
|
||||||
assert boiler_binary_sensor.state == STATE_OFF
|
assert boiler_binary_sensor.state == STATE_OFF
|
||||||
|
|
||||||
|
assert nb_device_active_sensor.state == 2
|
||||||
|
assert nb_device_active_sensor.active_device_ids == [
|
||||||
|
"switch.switch2",
|
||||||
|
"switch.switch3",
|
||||||
|
]
|
||||||
|
|
||||||
entity.remove_thermostat()
|
entity.remove_thermostat()
|
||||||
|
|
||||||
|
|
||||||
@@ -558,7 +620,7 @@ async def test_update_central_boiler_state_simple_valve(
|
|||||||
CONF_USE_MOTION_FEATURE: False,
|
CONF_USE_MOTION_FEATURE: False,
|
||||||
CONF_USE_POWER_FEATURE: False,
|
CONF_USE_POWER_FEATURE: False,
|
||||||
CONF_USE_PRESENCE_FEATURE: False,
|
CONF_USE_PRESENCE_FEATURE: False,
|
||||||
CONF_VALVE: valve1.entity_id,
|
CONF_UNDERLYING_LIST: [valve1.entity_id],
|
||||||
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
|
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
|
||||||
CONF_INVERSE_SWITCH: False,
|
CONF_INVERSE_SWITCH: False,
|
||||||
CONF_TPI_COEF_INT: 0.3,
|
CONF_TPI_COEF_INT: 0.3,
|
||||||
@@ -594,7 +656,7 @@ async def test_update_central_boiler_state_simple_valve(
|
|||||||
now: datetime = datetime.now(tz=tz)
|
now: datetime = datetime.now(tz=tz)
|
||||||
|
|
||||||
assert entity.hvac_mode == HVACMode.HEAT
|
assert entity.hvac_mode == HVACMode.HEAT
|
||||||
assert entity.nb_device_actives == 0
|
assert entity.device_actives == []
|
||||||
|
|
||||||
boiler_binary_sensor: CentralBoilerBinarySensor = search_entity(
|
boiler_binary_sensor: CentralBoilerBinarySensor = search_entity(
|
||||||
hass, "binary_sensor.central_boiler", "binary_sensor"
|
hass, "binary_sensor.central_boiler", "binary_sensor"
|
||||||
@@ -602,6 +664,13 @@ async def test_update_central_boiler_state_simple_valve(
|
|||||||
assert boiler_binary_sensor is not None
|
assert boiler_binary_sensor is not None
|
||||||
assert boiler_binary_sensor.state == STATE_OFF
|
assert boiler_binary_sensor.state == STATE_OFF
|
||||||
|
|
||||||
|
nb_device_active_sensor: NbActiveDeviceForBoilerSensor = search_entity(
|
||||||
|
hass, "sensor.nb_device_active_for_boiler", "sensor"
|
||||||
|
)
|
||||||
|
assert nb_device_active_sensor is not None
|
||||||
|
assert nb_device_active_sensor.state == 0
|
||||||
|
assert nb_device_active_sensor.active_device_ids == []
|
||||||
|
|
||||||
# 1. start a valve
|
# 1. start a valve
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.core.ServiceRegistry.async_call"
|
"homeassistant.core.ServiceRegistry.async_call"
|
||||||
@@ -616,7 +685,7 @@ async def test_update_central_boiler_state_simple_valve(
|
|||||||
await asyncio.sleep(0.1)
|
await asyncio.sleep(0.1)
|
||||||
|
|
||||||
assert entity.hvac_action == HVACAction.HEATING
|
assert entity.hvac_action == HVACAction.HEATING
|
||||||
assert entity.nb_device_actives == 1
|
assert entity.device_actives == ["number.valve1"]
|
||||||
|
|
||||||
assert mock_service_call.call_count >= 1
|
assert mock_service_call.call_count >= 1
|
||||||
mock_service_call.assert_has_calls(
|
mock_service_call.assert_has_calls(
|
||||||
@@ -644,6 +713,11 @@ async def test_update_central_boiler_state_simple_valve(
|
|||||||
assert api.nb_active_device_for_boiler == 1
|
assert api.nb_active_device_for_boiler == 1
|
||||||
assert boiler_binary_sensor.state == STATE_ON
|
assert boiler_binary_sensor.state == STATE_ON
|
||||||
|
|
||||||
|
assert nb_device_active_sensor.state == 1
|
||||||
|
assert nb_device_active_sensor.active_device_ids == [
|
||||||
|
"number.valve1",
|
||||||
|
]
|
||||||
|
|
||||||
# 2. stop a heater
|
# 2. stop a heater
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.core.ServiceRegistry.async_call"
|
"homeassistant.core.ServiceRegistry.async_call"
|
||||||
@@ -658,7 +732,7 @@ async def test_update_central_boiler_state_simple_valve(
|
|||||||
await asyncio.sleep(0.1)
|
await asyncio.sleep(0.1)
|
||||||
|
|
||||||
assert entity.hvac_action == HVACAction.IDLE
|
assert entity.hvac_action == HVACAction.IDLE
|
||||||
assert entity.nb_device_actives == 0
|
assert entity.device_actives == []
|
||||||
|
|
||||||
assert mock_service_call.call_count >= 1
|
assert mock_service_call.call_count >= 1
|
||||||
mock_service_call.assert_has_calls(
|
mock_service_call.assert_has_calls(
|
||||||
@@ -687,6 +761,9 @@ async def test_update_central_boiler_state_simple_valve(
|
|||||||
assert api.nb_active_device_for_boiler == 0
|
assert api.nb_active_device_for_boiler == 0
|
||||||
assert boiler_binary_sensor.state == STATE_OFF
|
assert boiler_binary_sensor.state == STATE_OFF
|
||||||
|
|
||||||
|
assert nb_device_active_sensor.state == 0
|
||||||
|
assert nb_device_active_sensor.active_device_ids == []
|
||||||
|
|
||||||
entity.remove_thermostat()
|
entity.remove_thermostat()
|
||||||
|
|
||||||
|
|
||||||
@@ -721,7 +798,7 @@ async def test_update_central_boiler_state_simple_climate(
|
|||||||
CONF_USE_MOTION_FEATURE: False,
|
CONF_USE_MOTION_FEATURE: False,
|
||||||
CONF_USE_POWER_FEATURE: False,
|
CONF_USE_POWER_FEATURE: False,
|
||||||
CONF_USE_PRESENCE_FEATURE: False,
|
CONF_USE_PRESENCE_FEATURE: False,
|
||||||
CONF_CLIMATE: climate1.entity_id,
|
CONF_UNDERLYING_LIST: [climate1.entity_id],
|
||||||
CONF_MINIMAL_ACTIVATION_DELAY: 30,
|
CONF_MINIMAL_ACTIVATION_DELAY: 30,
|
||||||
CONF_SECURITY_DELAY_MIN: 5,
|
CONF_SECURITY_DELAY_MIN: 5,
|
||||||
CONF_SECURITY_MIN_ON_PERCENT: 0.3,
|
CONF_SECURITY_MIN_ON_PERCENT: 0.3,
|
||||||
@@ -748,6 +825,13 @@ async def test_update_central_boiler_state_simple_climate(
|
|||||||
assert api.nb_active_device_for_boiler_threshold == 1
|
assert api.nb_active_device_for_boiler_threshold == 1
|
||||||
assert api.nb_active_device_for_boiler == 0
|
assert api.nb_active_device_for_boiler == 0
|
||||||
|
|
||||||
|
nb_device_active_sensor: NbActiveDeviceForBoilerSensor = search_entity(
|
||||||
|
hass, "sensor.nb_device_active_for_boiler", "sensor"
|
||||||
|
)
|
||||||
|
assert nb_device_active_sensor is not None
|
||||||
|
assert nb_device_active_sensor.state == 0
|
||||||
|
assert nb_device_active_sensor.active_device_ids == []
|
||||||
|
|
||||||
# Force the VTherm to heat
|
# Force the VTherm to heat
|
||||||
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)
|
||||||
@@ -756,7 +840,7 @@ async def test_update_central_boiler_state_simple_climate(
|
|||||||
now: datetime = datetime.now(tz=tz)
|
now: datetime = datetime.now(tz=tz)
|
||||||
|
|
||||||
assert entity.hvac_mode == HVACMode.HEAT
|
assert entity.hvac_mode == HVACMode.HEAT
|
||||||
assert entity.nb_device_actives == 0
|
assert entity.device_actives == []
|
||||||
|
|
||||||
boiler_binary_sensor: CentralBoilerBinarySensor = search_entity(
|
boiler_binary_sensor: CentralBoilerBinarySensor = search_entity(
|
||||||
hass, "binary_sensor.central_boiler", "binary_sensor"
|
hass, "binary_sensor.central_boiler", "binary_sensor"
|
||||||
@@ -779,7 +863,7 @@ async def test_update_central_boiler_state_simple_climate(
|
|||||||
await asyncio.sleep(0.5)
|
await asyncio.sleep(0.5)
|
||||||
|
|
||||||
assert entity.hvac_action == HVACAction.HEATING
|
assert entity.hvac_action == HVACAction.HEATING
|
||||||
assert entity.nb_device_actives == 1
|
assert entity.device_actives == ["climate.climate1"]
|
||||||
|
|
||||||
assert mock_service_call.call_count >= 1
|
assert mock_service_call.call_count >= 1
|
||||||
mock_service_call.assert_has_calls(
|
mock_service_call.assert_has_calls(
|
||||||
@@ -807,6 +891,11 @@ async def test_update_central_boiler_state_simple_climate(
|
|||||||
assert api.nb_active_device_for_boiler == 1
|
assert api.nb_active_device_for_boiler == 1
|
||||||
assert boiler_binary_sensor.state == STATE_ON
|
assert boiler_binary_sensor.state == STATE_ON
|
||||||
|
|
||||||
|
assert nb_device_active_sensor.state == 1
|
||||||
|
assert nb_device_active_sensor.active_device_ids == [
|
||||||
|
"climate.climate1",
|
||||||
|
]
|
||||||
|
|
||||||
# 2. stop a climate
|
# 2. stop a climate
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.core.ServiceRegistry.async_call"
|
"homeassistant.core.ServiceRegistry.async_call"
|
||||||
@@ -821,7 +910,7 @@ async def test_update_central_boiler_state_simple_climate(
|
|||||||
await asyncio.sleep(0.5)
|
await asyncio.sleep(0.5)
|
||||||
|
|
||||||
assert entity.hvac_action == HVACAction.IDLE
|
assert entity.hvac_action == HVACAction.IDLE
|
||||||
assert entity.nb_device_actives == 0
|
assert entity.device_actives == []
|
||||||
|
|
||||||
assert mock_service_call.call_count >= 1
|
assert mock_service_call.call_count >= 1
|
||||||
mock_service_call.assert_has_calls(
|
mock_service_call.assert_has_calls(
|
||||||
@@ -850,6 +939,277 @@ async def test_update_central_boiler_state_simple_climate(
|
|||||||
assert api.nb_active_device_for_boiler == 0
|
assert api.nb_active_device_for_boiler == 0
|
||||||
assert boiler_binary_sensor.state == STATE_OFF
|
assert boiler_binary_sensor.state == STATE_OFF
|
||||||
|
|
||||||
|
assert nb_device_active_sensor.state == 0
|
||||||
|
assert nb_device_active_sensor.active_device_ids == []
|
||||||
|
|
||||||
|
entity.remove_thermostat()
|
||||||
|
|
||||||
|
|
||||||
|
async def test_update_central_boiler_state_simple_climate_valve_regulation(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
# skip_hass_states_is_state,
|
||||||
|
# skip_hass_states_get,
|
||||||
|
init_central_config_with_boiler_fixture,
|
||||||
|
):
|
||||||
|
"""Test that the central boiler state behavior with a climate with valve regulation"""
|
||||||
|
|
||||||
|
api = VersatileThermostatAPI.get_vtherm_api(hass)
|
||||||
|
|
||||||
|
climate1 = MockClimate(hass, "climate1", "theClimate1")
|
||||||
|
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
title="TheOverClimateMockName",
|
||||||
|
unique_id="uniqueId",
|
||||||
|
data={
|
||||||
|
CONF_NAME: "TheOverClimateMockName",
|
||||||
|
CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_CLIMATE,
|
||||||
|
CONF_TEMP_SENSOR: "sensor.mock_temp_sensor",
|
||||||
|
CONF_EXTERNAL_TEMP_SENSOR: "sensor.mock_ext_temp_sensor",
|
||||||
|
CONF_CYCLE_MIN: 5,
|
||||||
|
CONF_TEMP_MIN: 8,
|
||||||
|
CONF_TEMP_MAX: 18,
|
||||||
|
"frost_temp": 10,
|
||||||
|
"eco_temp": 17,
|
||||||
|
"comfort_temp": 18,
|
||||||
|
"boost_temp": 21,
|
||||||
|
CONF_USE_WINDOW_FEATURE: False,
|
||||||
|
CONF_USE_MOTION_FEATURE: False,
|
||||||
|
CONF_USE_POWER_FEATURE: False,
|
||||||
|
CONF_USE_PRESENCE_FEATURE: False,
|
||||||
|
CONF_UNDERLYING_LIST: [climate1.entity_id],
|
||||||
|
CONF_OPENING_DEGREE_LIST: ["number.mock_opening_degree"],
|
||||||
|
CONF_CLOSING_DEGREE_LIST: [],
|
||||||
|
CONF_OFFSET_CALIBRATION_LIST: [],
|
||||||
|
CONF_AUTO_REGULATION_MODE: CONF_AUTO_REGULATION_VALVE,
|
||||||
|
CONF_AUTO_REGULATION_DTEMP: 0,
|
||||||
|
CONF_AUTO_REGULATION_PERIOD_MIN: 0,
|
||||||
|
CONF_TPI_COEF_INT: 0.3,
|
||||||
|
CONF_TPI_COEF_EXT: 0.1,
|
||||||
|
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
|
||||||
|
CONF_AUTO_FAN_MODE: CONF_AUTO_FAN_HIGH,
|
||||||
|
CONF_AUTO_REGULATION_USE_DEVICE_TEMP: False,
|
||||||
|
CONF_MINIMAL_ACTIVATION_DELAY: 30,
|
||||||
|
CONF_SECURITY_DELAY_MIN: 5,
|
||||||
|
CONF_SECURITY_MIN_ON_PERCENT: 0.3,
|
||||||
|
CONF_SECURITY_DEFAULT_ON_PERCENT: 0.1,
|
||||||
|
CONF_USE_MAIN_CENTRAL_CONFIG: True,
|
||||||
|
CONF_USE_PRESETS_CENTRAL_CONFIG: True,
|
||||||
|
CONF_USE_ADVANCED_CENTRAL_CONFIG: True,
|
||||||
|
CONF_USED_BY_CENTRAL_BOILER: True,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
open_degree_entity = MockNumber(hass, "mock_opening_degree", "Opening degree")
|
||||||
|
open_degree_entity.set_native_value(0)
|
||||||
|
|
||||||
|
# mock_get_state will be called for each OPENING/CLOSING/OFFSET_CALIBRATION list
|
||||||
|
mock_get_state_side_effect = SideEffects(
|
||||||
|
{
|
||||||
|
open_degree_entity.entity_id: State(
|
||||||
|
open_degree_entity.entity_id,
|
||||||
|
open_degree_entity.state,
|
||||||
|
{"min": 0, "max": 100},
|
||||||
|
),
|
||||||
|
"number.mock_closing_degree": State(
|
||||||
|
"number.mock_closing_degree", "0", {"min": 0, "max": 100}
|
||||||
|
),
|
||||||
|
"number.mock_offset_calibration": State(
|
||||||
|
"number.mock_offset_calibration", "0", {"min": -12, "max": 12}
|
||||||
|
),
|
||||||
|
},
|
||||||
|
State("unknown.entity_id", "unknown"),
|
||||||
|
)
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"custom_components.versatile_thermostat.underlyings.UnderlyingClimate.find_underlying_climate",
|
||||||
|
return_value=climate1,
|
||||||
|
), patch(
|
||||||
|
"homeassistant.core.StateMachine.get",
|
||||||
|
side_effect=mock_get_state_side_effect.get_side_effects(),
|
||||||
|
):
|
||||||
|
entity: ThermostatOverClimate = await create_thermostat(
|
||||||
|
hass, entry, "climate.theoverclimatemockname"
|
||||||
|
)
|
||||||
|
assert entity
|
||||||
|
assert entity.name == "TheOverClimateMockName"
|
||||||
|
assert entity.is_over_climate
|
||||||
|
assert entity.underlying_entities[0].entity_id == "climate.climate1"
|
||||||
|
|
||||||
|
assert api.nb_active_device_for_boiler_threshold == 1
|
||||||
|
assert api.nb_active_device_for_boiler == 0
|
||||||
|
|
||||||
|
nb_device_active_sensor: NbActiveDeviceForBoilerSensor = search_entity(
|
||||||
|
hass, "sensor.nb_device_active_for_boiler", "sensor"
|
||||||
|
)
|
||||||
|
assert nb_device_active_sensor is not None
|
||||||
|
assert nb_device_active_sensor.state == 0
|
||||||
|
assert nb_device_active_sensor.active_device_ids == []
|
||||||
|
|
||||||
|
# Force the VTherm to heat
|
||||||
|
tz = get_tz(hass) # pylint: disable=invalid-name
|
||||||
|
now: datetime = datetime.now(tz=tz)
|
||||||
|
entity._set_now(now)
|
||||||
|
|
||||||
|
await send_temperature_change_event(entity, 30, now)
|
||||||
|
await send_ext_temperature_change_event(entity, 30, now)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
await entity.async_set_hvac_mode(HVACMode.HEAT)
|
||||||
|
await entity.async_set_preset_mode(PRESET_BOOST)
|
||||||
|
|
||||||
|
# the VTherm should not heat now
|
||||||
|
assert entity.hvac_mode == HVACMode.HEAT
|
||||||
|
assert entity.hvac_action == HVACAction.OFF
|
||||||
|
assert entity.activable_underlying_entities[0]._percent_open == 0
|
||||||
|
assert entity.device_actives == []
|
||||||
|
|
||||||
|
boiler_binary_sensor: CentralBoilerBinarySensor = search_entity(
|
||||||
|
hass, "binary_sensor.central_boiler", "binary_sensor"
|
||||||
|
)
|
||||||
|
assert boiler_binary_sensor is not None
|
||||||
|
assert boiler_binary_sensor.state == STATE_OFF
|
||||||
|
|
||||||
|
# 1. start a climate
|
||||||
|
open_degree_entity.set_native_value(100)
|
||||||
|
mock_get_state_side_effect = SideEffects(
|
||||||
|
{
|
||||||
|
open_degree_entity.entity_id: State(
|
||||||
|
open_degree_entity.entity_id,
|
||||||
|
open_degree_entity.state,
|
||||||
|
{"min": 0, "max": 100},
|
||||||
|
),
|
||||||
|
"number.mock_closing_degree": State(
|
||||||
|
"number.mock_closing_degree", "0", {"min": 0, "max": 100}
|
||||||
|
),
|
||||||
|
"number.mock_offset_calibration": State(
|
||||||
|
"number.mock_offset_calibration", "0", {"min": -12, "max": 12}
|
||||||
|
),
|
||||||
|
},
|
||||||
|
State("unknown.entity_id", "unknown"),
|
||||||
|
)
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.core.ServiceRegistry.async_call"
|
||||||
|
) as mock_service_call, patch(
|
||||||
|
"custom_components.versatile_thermostat.binary_sensor.send_vtherm_event"
|
||||||
|
) as mock_send_event, patch(
|
||||||
|
"homeassistant.core.StateMachine.get",
|
||||||
|
side_effect=mock_get_state_side_effect.get_side_effects(),
|
||||||
|
):
|
||||||
|
now = now + timedelta(minutes=1)
|
||||||
|
entity._set_now(now)
|
||||||
|
|
||||||
|
await send_temperature_change_event(entity, 10, now)
|
||||||
|
# we have to simulate the climate also else the test don't work
|
||||||
|
climate1.set_hvac_mode(HVACMode.HEAT)
|
||||||
|
climate1.set_hvac_action(HVACAction.HEATING)
|
||||||
|
climate1.async_write_ha_state()
|
||||||
|
open_degree_entity.set_native_value(100)
|
||||||
|
# Wait for state event propagation
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert entity.hvac_action == HVACAction.HEATING
|
||||||
|
assert entity.device_actives == ["number.mock_opening_degree"]
|
||||||
|
|
||||||
|
assert api.nb_active_device_for_boiler == 1
|
||||||
|
assert boiler_binary_sensor.state == STATE_ON
|
||||||
|
|
||||||
|
assert nb_device_active_sensor.state == 1
|
||||||
|
assert nb_device_active_sensor.active_device_ids == [
|
||||||
|
"number.mock_opening_degree",
|
||||||
|
]
|
||||||
|
|
||||||
|
assert mock_service_call.call_count >= 1
|
||||||
|
mock_service_call.assert_has_calls(
|
||||||
|
[
|
||||||
|
call.service_call(
|
||||||
|
"switch",
|
||||||
|
"turn_on",
|
||||||
|
service_data={},
|
||||||
|
target={"entity_id": "switch.pompe_chaudiere"},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
assert mock_send_event.call_count >= 1
|
||||||
|
mock_send_event.assert_has_calls(
|
||||||
|
[
|
||||||
|
call.send_vtherm_event(
|
||||||
|
hass=hass,
|
||||||
|
event_type=EventType.CENTRAL_BOILER_EVENT,
|
||||||
|
entity=api.central_boiler_entity,
|
||||||
|
data={"central_boiler": True},
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
# 2. stop a climate
|
||||||
|
open_degree_entity.set_native_value(0)
|
||||||
|
mock_get_state_side_effect = SideEffects(
|
||||||
|
{
|
||||||
|
open_degree_entity.entity_id: State(
|
||||||
|
open_degree_entity.entity_id,
|
||||||
|
open_degree_entity.state,
|
||||||
|
{"min": 0, "max": 100},
|
||||||
|
),
|
||||||
|
"number.mock_closing_degree": State(
|
||||||
|
"number.mock_closing_degree", "0", {"min": 0, "max": 100}
|
||||||
|
),
|
||||||
|
"number.mock_offset_calibration": State(
|
||||||
|
"number.mock_offset_calibration", "0", {"min": -12, "max": 12}
|
||||||
|
),
|
||||||
|
},
|
||||||
|
State("unknown.entity_id", "unknown"),
|
||||||
|
)
|
||||||
|
with patch(
|
||||||
|
"homeassistant.core.ServiceRegistry.async_call"
|
||||||
|
) as mock_service_call, patch(
|
||||||
|
"custom_components.versatile_thermostat.binary_sensor.send_vtherm_event"
|
||||||
|
) as mock_send_event, patch(
|
||||||
|
"homeassistant.core.StateMachine.get",
|
||||||
|
side_effect=mock_get_state_side_effect.get_side_effects(),
|
||||||
|
):
|
||||||
|
await send_temperature_change_event(entity, 25, now)
|
||||||
|
climate1.set_hvac_mode(HVACMode.HEAT)
|
||||||
|
climate1.set_hvac_action(HVACAction.IDLE)
|
||||||
|
climate1.async_write_ha_state()
|
||||||
|
open_degree_entity.set_native_value(0)
|
||||||
|
# Wait for state event propagation
|
||||||
|
await asyncio.sleep(0.5)
|
||||||
|
|
||||||
|
assert entity.hvac_action == HVACAction.OFF
|
||||||
|
assert entity.device_actives == []
|
||||||
|
|
||||||
|
assert mock_service_call.call_count >= 1
|
||||||
|
mock_service_call.assert_has_calls(
|
||||||
|
[
|
||||||
|
call(
|
||||||
|
"switch",
|
||||||
|
"turn_off",
|
||||||
|
service_data={},
|
||||||
|
target={"entity_id": "switch.pompe_chaudiere"},
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
assert mock_send_event.call_count >= 1
|
||||||
|
mock_send_event.assert_has_calls(
|
||||||
|
[
|
||||||
|
call.send_vtherm_event(
|
||||||
|
hass=hass,
|
||||||
|
event_type=EventType.CENTRAL_BOILER_EVENT,
|
||||||
|
entity=api.central_boiler_entity,
|
||||||
|
data={"central_boiler": False},
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
assert api.nb_active_device_for_boiler == 0
|
||||||
|
assert boiler_binary_sensor.state == STATE_OFF
|
||||||
|
|
||||||
|
assert nb_device_active_sensor.state == 0
|
||||||
|
assert nb_device_active_sensor.active_device_ids == []
|
||||||
|
|
||||||
entity.remove_thermostat()
|
entity.remove_thermostat()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -18,10 +18,10 @@ from .const import *
|
|||||||
logging.getLogger().setLevel(logging.DEBUG)
|
logging.getLogger().setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
|
||||||
# @pytest.mark.parametrize("expected_lingering_tasks", [True])
|
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||||
# @pytest.mark.parametrize("expected_lingering_timers", [True])
|
@pytest.mark.parametrize("expected_lingering_timers", [True])
|
||||||
# this test fails if run in // with the next because the underlying_valve_regulation is mixed. Don't know why
|
# this test fails if run in // with the next because the underlying_valve_regulation is mixed. Don't know why
|
||||||
@pytest.mark.skip
|
# @pytest.mark.skip
|
||||||
async def test_over_climate_valve_mono(hass: HomeAssistant, skip_hass_states_get):
|
async def test_over_climate_valve_mono(hass: HomeAssistant, skip_hass_states_get):
|
||||||
"""Test the normal full start of a thermostat in thermostat_over_climate type"""
|
"""Test the normal full start of a thermostat in thermostat_over_climate type"""
|
||||||
|
|
||||||
@@ -138,13 +138,13 @@ async def test_over_climate_valve_mono(hass: HomeAssistant, skip_hass_states_get
|
|||||||
assert mock_service_call.call_count == 3
|
assert mock_service_call.call_count == 3
|
||||||
mock_service_call.assert_has_calls(
|
mock_service_call.assert_has_calls(
|
||||||
[
|
[
|
||||||
|
call(domain='number', service='set_value', service_data={'value': 0}, target={'entity_id': 'number.mock_opening_degree'}),
|
||||||
|
call(domain='number', service='set_value', service_data={'value': 100}, target={'entity_id': 'number.mock_closing_degree'}),
|
||||||
call("climate","set_temperature",{
|
call("climate","set_temperature",{
|
||||||
"entity_id": "climate.mock_climate",
|
"entity_id": "climate.mock_climate",
|
||||||
"temperature": 15, # temp-min
|
"temperature": 15, # temp-min
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
call(domain='number', service='set_value', service_data={'value': 0}, target={'entity_id': 'number.mock_opening_degree'}),
|
|
||||||
call(domain='number', service='set_value', service_data={'value': 100}, target={'entity_id': 'number.mock_closing_degree'}),
|
|
||||||
# we have no current_temperature yet
|
# we have no current_temperature yet
|
||||||
# call(domain='number', service='set_value', service_data={'value': 12}, target={'entity_id': 'number.mock_offset_calibration'}),
|
# call(domain='number', service='set_value', service_data={'value': 12}, target={'entity_id': 'number.mock_offset_calibration'}),
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user