Try to fix issue #334 - loop when underlying is late to update
This commit is contained in:
@@ -1406,9 +1406,10 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
if new_state is None or new_state.state in (STATE_UNAVAILABLE, STATE_UNKNOWN):
|
if new_state is None or new_state.state in (STATE_UNAVAILABLE, STATE_UNKNOWN):
|
||||||
return
|
return
|
||||||
|
|
||||||
await self._async_update_temp(new_state)
|
dearm_window_auto = 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)
|
||||||
|
return dearm_window_auto
|
||||||
|
|
||||||
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."""
|
||||||
@@ -1646,7 +1647,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
await self.check_security()
|
await self.check_security()
|
||||||
|
|
||||||
# check window_auto
|
# check window_auto
|
||||||
await self._async_manage_window_auto()
|
return await self._async_manage_window_auto()
|
||||||
|
|
||||||
except ValueError as ex:
|
except ValueError as ex:
|
||||||
_LOGGER.error("Unable to update temperature from sensor: %s", ex)
|
_LOGGER.error("Unable to update temperature from sensor: %s", ex)
|
||||||
|
|||||||
@@ -601,8 +601,9 @@ class ThermostatOverClimate(BaseThermostat):
|
|||||||
# new_hvac_mode = HVACMode.OFF
|
# new_hvac_mode = HVACMode.OFF
|
||||||
|
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
"%s - Underlying climate changed. Event.new_hvac_mode is %s, current_hvac_mode=%s, new_hvac_action=%s, old_hvac_action=%s",
|
"%s - Underlying climate %s changed. Event.new_hvac_mode is %s, current_hvac_mode=%s, new_hvac_action=%s, old_hvac_action=%s",
|
||||||
self,
|
self,
|
||||||
|
new_state.entity_id,
|
||||||
new_hvac_mode,
|
new_hvac_mode,
|
||||||
self._hvac_mode,
|
self._hvac_mode,
|
||||||
new_hvac_action,
|
new_hvac_action,
|
||||||
@@ -658,7 +659,7 @@ class ThermostatOverClimate(BaseThermostat):
|
|||||||
)
|
)
|
||||||
changes = True
|
changes = True
|
||||||
|
|
||||||
# Issue #120 - Some TRV are chaning target temperature a very long time (6 sec) after the change.
|
# Issue #120 - Some TRV are changing target temperature a very long time (6 sec) after the change.
|
||||||
# In that case a loop is possible if a user change multiple times during this 6 sec.
|
# In that case a loop is possible if a user change multiple times during this 6 sec.
|
||||||
if new_state_date_updated and self._last_change_time:
|
if new_state_date_updated and self._last_change_time:
|
||||||
delta = (new_state_date_updated - self._last_change_time).total_seconds()
|
delta = (new_state_date_updated - self._last_change_time).total_seconds()
|
||||||
@@ -684,12 +685,31 @@ class ThermostatOverClimate(BaseThermostat):
|
|||||||
]
|
]
|
||||||
and self._hvac_mode != new_hvac_mode
|
and self._hvac_mode != new_hvac_mode
|
||||||
):
|
):
|
||||||
changes = True
|
|
||||||
self._hvac_mode = new_hvac_mode
|
|
||||||
# Update all underlyings state
|
# Update all underlyings state
|
||||||
|
# Issue #334 - if all underlyings are not aligned with the same hvac_mode don't change the underlying and wait they are aligned
|
||||||
if self.is_over_climate:
|
if self.is_over_climate:
|
||||||
|
for under in self._underlyings:
|
||||||
|
if (
|
||||||
|
under.entity_id != new_state.entity_id
|
||||||
|
and under.hvac_mode != self._hvac_mode
|
||||||
|
):
|
||||||
|
_LOGGER.info(
|
||||||
|
"%s - the underlying's hvac_mode %s is not aligned with VTherm hvac_mode %s. So we don't diffuse the change to all other underlyings to avoid loops",
|
||||||
|
under,
|
||||||
|
under.hvac_mode,
|
||||||
|
self._hvac_mode,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
_LOGGER.debug(
|
||||||
|
"%s - All underlyings have the same hvac_mode, so VTherm will send the new hvac mode %s",
|
||||||
|
self,
|
||||||
|
new_hvac_mode,
|
||||||
|
)
|
||||||
for under in self._underlyings:
|
for under in self._underlyings:
|
||||||
await under.set_hvac_mode(new_hvac_mode)
|
await under.set_hvac_mode(new_hvac_mode)
|
||||||
|
changes = True
|
||||||
|
self._hvac_mode = new_hvac_mode
|
||||||
|
|
||||||
# A quick win to known if it has change by using the self._attr_fan_mode and not only underlying[0].fan_mode
|
# A quick win to known if it has change by using the self._attr_fan_mode and not only underlying[0].fan_mode
|
||||||
if new_fan_mode != self._attr_fan_mode:
|
if new_fan_mode != self._attr_fan_mode:
|
||||||
|
|||||||
@@ -484,6 +484,14 @@ class UnderlyingClimate(UnderlyingEntity):
|
|||||||
if not self.is_initialized:
|
if not self.is_initialized:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
if self._underlying_climate.hvac_mode == hvac_mode:
|
||||||
|
_LOGGER.debug(
|
||||||
|
"%s - hvac_mode is already is requested state %s. Do not send any command",
|
||||||
|
self,
|
||||||
|
self._underlying_climate.hvac_mode,
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
data = {ATTR_ENTITY_ID: self._entity_id, "hvac_mode": hvac_mode}
|
data = {ATTR_ENTITY_ID: self._entity_id, "hvac_mode": hvac_mode}
|
||||||
await self._hass.services.async_call(
|
await self._hass.services.async_call(
|
||||||
CLIMATE_DOMAIN,
|
CLIMATE_DOMAIN,
|
||||||
|
|||||||
@@ -428,10 +428,12 @@ async def send_temperature_change_event(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
await entity._async_temperature_changed(temp_event)
|
dearm_window_auto = await entity._async_temperature_changed(temp_event)
|
||||||
if sleep:
|
if sleep:
|
||||||
await asyncio.sleep(0.1)
|
await asyncio.sleep(0.1)
|
||||||
|
|
||||||
|
return dearm_window_auto
|
||||||
|
|
||||||
|
|
||||||
async def send_ext_temperature_change_event(
|
async def send_ext_temperature_change_event(
|
||||||
entity: BaseThermostat, new_temp, date, sleep=True
|
entity: BaseThermostat, new_temp, date, sleep=True
|
||||||
@@ -619,6 +621,7 @@ async def send_climate_change_event(
|
|||||||
old_hvac_action: HVACAction,
|
old_hvac_action: HVACAction,
|
||||||
date,
|
date,
|
||||||
sleep=True,
|
sleep=True,
|
||||||
|
underlying_entity_id: str = None,
|
||||||
):
|
):
|
||||||
"""Sending a new climate event simulating a change on the underlying climate state"""
|
"""Sending a new climate event simulating a change on the underlying climate state"""
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
@@ -630,18 +633,23 @@ async def send_climate_change_event(
|
|||||||
date,
|
date,
|
||||||
entity,
|
entity,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
send_from_entity_id = (
|
||||||
|
underlying_entity_id if underlying_entity_id is not None else entity.entity_id
|
||||||
|
)
|
||||||
|
|
||||||
climate_event = Event(
|
climate_event = Event(
|
||||||
EVENT_STATE_CHANGED,
|
EVENT_STATE_CHANGED,
|
||||||
{
|
{
|
||||||
"new_state": State(
|
"new_state": State(
|
||||||
entity_id=entity.entity_id,
|
entity_id=send_from_entity_id,
|
||||||
state=new_hvac_mode,
|
state=new_hvac_mode,
|
||||||
attributes={"hvac_action": new_hvac_action},
|
attributes={"hvac_action": new_hvac_action},
|
||||||
last_changed=date,
|
last_changed=date,
|
||||||
last_updated=date,
|
last_updated=date,
|
||||||
),
|
),
|
||||||
"old_state": State(
|
"old_state": State(
|
||||||
entity_id=entity.entity_id,
|
entity_id=send_from_entity_id,
|
||||||
state=old_hvac_mode,
|
state=old_hvac_mode,
|
||||||
attributes={"hvac_action": old_hvac_action},
|
attributes={"hvac_action": old_hvac_action},
|
||||||
last_changed=date,
|
last_changed=date,
|
||||||
|
|||||||
@@ -633,14 +633,16 @@ async def test_bug_272(
|
|||||||
|
|
||||||
# In the accepted interval
|
# In the accepted interval
|
||||||
await entity.async_set_temperature(temperature=17.5)
|
await entity.async_set_temperature(temperature=17.5)
|
||||||
assert mock_service_call.call_count == 2
|
|
||||||
|
# MagicMock climate is already HEAT by default. So there is no SET_HAVC_MODE call
|
||||||
|
assert mock_service_call.call_count == 1
|
||||||
mock_service_call.assert_has_calls(
|
mock_service_call.assert_has_calls(
|
||||||
[
|
[
|
||||||
call.async_call(
|
# call.async_call(
|
||||||
"climate",
|
# "climate",
|
||||||
SERVICE_SET_HVAC_MODE,
|
# SERVICE_SET_HVAC_MODE,
|
||||||
{"entity_id": "climate.mock_climate", "hvac_mode": HVACMode.HEAT},
|
# {"entity_id": "climate.mock_climate", "hvac_mode": HVACMode.HEAT},
|
||||||
),
|
# ),
|
||||||
call.async_call(
|
call.async_call(
|
||||||
"climate",
|
"climate",
|
||||||
SERVICE_SET_TEMPERATURE,
|
SERVICE_SET_TEMPERATURE,
|
||||||
|
|||||||
@@ -268,7 +268,7 @@ async def test_full_over_switch_wo_central_config(
|
|||||||
assert entity._security_default_on_percent == 0.1
|
assert entity._security_default_on_percent == 0.1
|
||||||
assert entity.is_inversed is False
|
assert entity.is_inversed is False
|
||||||
|
|
||||||
assert entity.is_window_auto_enabled is True
|
assert entity.is_window_auto_enabled is False # we have an entity_id
|
||||||
assert entity._window_sensor_entity_id == "binary_sensor.mock_window_sensor"
|
assert entity._window_sensor_entity_id == "binary_sensor.mock_window_sensor"
|
||||||
assert entity._window_delay_sec == 30
|
assert entity._window_delay_sec == 30
|
||||||
assert entity._window_auto_close_threshold == 0.1
|
assert entity._window_auto_close_threshold == 0.1
|
||||||
@@ -377,7 +377,8 @@ async def test_full_over_switch_with_central_config(
|
|||||||
assert entity._security_default_on_percent == 0.2
|
assert entity._security_default_on_percent == 0.2
|
||||||
assert entity.is_inversed is False
|
assert entity.is_inversed is False
|
||||||
|
|
||||||
assert entity.is_window_auto_enabled is True
|
# We have an entity so window auto is not enabled
|
||||||
|
assert entity.is_window_auto_enabled is False
|
||||||
assert entity._window_sensor_entity_id == "binary_sensor.mock_window_sensor"
|
assert entity._window_sensor_entity_id == "binary_sensor.mock_window_sensor"
|
||||||
assert entity._window_delay_sec == 15
|
assert entity._window_delay_sec == 15
|
||||||
assert entity._window_auto_close_threshold == 1
|
assert entity._window_auto_close_threshold == 1
|
||||||
|
|||||||
@@ -472,7 +472,7 @@ async def test_multiple_climates_underlying_changes(
|
|||||||
skip_hass_states_is_state,
|
skip_hass_states_is_state,
|
||||||
skip_send_event,
|
skip_send_event,
|
||||||
): # pylint: disable=unused-argument
|
): # pylint: disable=unused-argument
|
||||||
"""Test that when multiple switch are configured the activation of one underlying
|
"""Test that when multiple climate are configured the activation of one underlying
|
||||||
climate activate the others"""
|
climate activate the others"""
|
||||||
|
|
||||||
tz = get_tz(hass) # pylint: disable=invalid-name
|
tz = get_tz(hass) # pylint: disable=invalid-name
|
||||||
@@ -541,11 +541,15 @@ async def test_multiple_climates_underlying_changes(
|
|||||||
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
|
||||||
|
# All underlying supposed to be aligned with the hvac_mode now
|
||||||
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, patch(
|
||||||
|
"custom_components.versatile_thermostat.underlyings.UnderlyingClimate.hvac_mode",
|
||||||
|
HVACMode.HEAT,
|
||||||
|
):
|
||||||
# Wait 11 sec so that the event will not be discarded
|
# Wait 11 sec so that the event will not be discarded
|
||||||
event_timestamp = now + timedelta(seconds=11)
|
event_timestamp = now + timedelta(seconds=11)
|
||||||
await send_climate_change_event(
|
await send_climate_change_event(
|
||||||
@@ -555,6 +559,7 @@ async def test_multiple_climates_underlying_changes(
|
|||||||
HVACAction.OFF,
|
HVACAction.OFF,
|
||||||
HVACAction.HEATING,
|
HVACAction.HEATING,
|
||||||
event_timestamp,
|
event_timestamp,
|
||||||
|
underlying_entity_id="switch.mock_climate3",
|
||||||
)
|
)
|
||||||
|
|
||||||
# Should be call for all Switch
|
# Should be call for all Switch
|
||||||
@@ -577,6 +582,9 @@ async def test_multiple_climates_underlying_changes(
|
|||||||
# a function but a property
|
# a function but a property
|
||||||
"custom_components.versatile_thermostat.underlyings.UnderlyingClimate.hvac_action",
|
"custom_components.versatile_thermostat.underlyings.UnderlyingClimate.hvac_action",
|
||||||
HVACAction.IDLE,
|
HVACAction.IDLE,
|
||||||
|
), patch(
|
||||||
|
"custom_components.versatile_thermostat.underlyings.UnderlyingClimate.hvac_mode",
|
||||||
|
HVACMode.OFF,
|
||||||
):
|
):
|
||||||
# Wait 11 sec so that the event will not be discarded
|
# Wait 11 sec so that the event will not be discarded
|
||||||
event_timestamp = now + timedelta(seconds=11)
|
event_timestamp = now + timedelta(seconds=11)
|
||||||
@@ -601,6 +609,113 @@ async def test_multiple_climates_underlying_changes(
|
|||||||
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_timers", [True])
|
||||||
|
async def test_multiple_climates_underlying_changes_not_aligned(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
skip_hass_states_is_state,
|
||||||
|
skip_send_event,
|
||||||
|
): # pylint: disable=unused-argument
|
||||||
|
"""Test that when multiple climate are configured the activation of one underlying
|
||||||
|
climate don't activate the others if their havc_mode are not aligned"""
|
||||||
|
|
||||||
|
tz = get_tz(hass) # pylint: disable=invalid-name
|
||||||
|
now: datetime = datetime.now(tz=tz)
|
||||||
|
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
title="TheOver4ClimateMockName",
|
||||||
|
unique_id="uniqueId",
|
||||||
|
data={
|
||||||
|
CONF_NAME: "TheOver4ClimateMockName",
|
||||||
|
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: 8,
|
||||||
|
CONF_TEMP_MIN: 15,
|
||||||
|
CONF_TEMP_MAX: 30,
|
||||||
|
"eco_temp": 17,
|
||||||
|
"comfort_temp": 18,
|
||||||
|
"boost_temp": 19,
|
||||||
|
CONF_USE_WINDOW_FEATURE: False,
|
||||||
|
CONF_USE_MOTION_FEATURE: False,
|
||||||
|
CONF_USE_POWER_FEATURE: False,
|
||||||
|
CONF_USE_PRESENCE_FEATURE: False,
|
||||||
|
CONF_CLIMATE: "switch.mock_climate1",
|
||||||
|
CONF_CLIMATE_2: "switch.mock_climate2",
|
||||||
|
CONF_CLIMATE_3: "switch.mock_climate3",
|
||||||
|
CONF_CLIMATE_4: "switch.mock_climate4",
|
||||||
|
CONF_MINIMAL_ACTIVATION_DELAY: 30,
|
||||||
|
CONF_SECURITY_DELAY_MIN: 5,
|
||||||
|
CONF_SECURITY_MIN_ON_PERCENT: 0.3,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
entity: BaseThermostat = await create_thermostat(
|
||||||
|
hass, entry, "climate.theover4climatemockname"
|
||||||
|
)
|
||||||
|
assert entity
|
||||||
|
assert entity.is_over_climate is True
|
||||||
|
assert entity.nb_underlying_entities == 4
|
||||||
|
|
||||||
|
# start heating, in boost mode. We block the control_heating to avoid running a cycle
|
||||||
|
with patch(
|
||||||
|
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.async_control_heating"
|
||||||
|
), patch(
|
||||||
|
"custom_components.versatile_thermostat.underlyings.UnderlyingClimate.set_hvac_mode"
|
||||||
|
) as mock_underlying_set_hvac_mode:
|
||||||
|
await entity.async_set_hvac_mode(HVACMode.HEAT)
|
||||||
|
await entity.async_set_preset_mode(PRESET_BOOST)
|
||||||
|
|
||||||
|
assert entity.hvac_mode is HVACMode.HEAT
|
||||||
|
assert entity.preset_mode is PRESET_BOOST
|
||||||
|
assert entity.target_temperature == 19
|
||||||
|
assert entity.window_state is STATE_OFF
|
||||||
|
|
||||||
|
event_timestamp = now - timedelta(minutes=4)
|
||||||
|
await send_temperature_change_event(entity, 15, event_timestamp)
|
||||||
|
|
||||||
|
# Should be call for all Switch
|
||||||
|
assert mock_underlying_set_hvac_mode.call_count == 4
|
||||||
|
mock_underlying_set_hvac_mode.assert_has_calls(
|
||||||
|
[
|
||||||
|
call.set_hvac_mode(HVACMode.HEAT),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Stop heating on one underlying climate
|
||||||
|
# All underlying supposed to be aligned with the hvac_mode now
|
||||||
|
with patch(
|
||||||
|
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.async_control_heating"
|
||||||
|
), patch(
|
||||||
|
"custom_components.versatile_thermostat.underlyings.UnderlyingClimate.set_hvac_mode"
|
||||||
|
) as mock_underlying_set_hvac_mode, patch(
|
||||||
|
"custom_components.versatile_thermostat.underlyings.UnderlyingClimate.hvac_mode",
|
||||||
|
HVACMode.COOL,
|
||||||
|
):
|
||||||
|
# Wait 11 sec so that the event will not be discarded
|
||||||
|
event_timestamp = now + timedelta(seconds=11)
|
||||||
|
await send_climate_change_event(
|
||||||
|
entity,
|
||||||
|
HVACMode.OFF,
|
||||||
|
HVACMode.HEAT,
|
||||||
|
HVACAction.OFF,
|
||||||
|
HVACAction.HEATING,
|
||||||
|
event_timestamp,
|
||||||
|
underlying_entity_id="switch.mock_climate3",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Should be call for all Switch
|
||||||
|
assert mock_underlying_set_hvac_mode.call_count == 0
|
||||||
|
# mock_underlying_set_hvac_mode.assert_has_calls(
|
||||||
|
# [
|
||||||
|
# call.set_hvac_mode(HVACMode.OFF),
|
||||||
|
# ]
|
||||||
|
# )
|
||||||
|
# No change
|
||||||
|
assert entity.hvac_mode == HVACMode.HEAT
|
||||||
|
|
||||||
|
|
||||||
@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])
|
||||||
async def test_multiple_switch_power_management(
|
async def test_multiple_switch_power_management(
|
||||||
|
|||||||
@@ -581,7 +581,7 @@ async def test_window_auto_auto_stop(hass: HomeAssistant, skip_hass_states_is_st
|
|||||||
CONF_SECURITY_MIN_ON_PERCENT: 0.3,
|
CONF_SECURITY_MIN_ON_PERCENT: 0.3,
|
||||||
CONF_WINDOW_AUTO_OPEN_THRESHOLD: 6,
|
CONF_WINDOW_AUTO_OPEN_THRESHOLD: 6,
|
||||||
CONF_WINDOW_AUTO_CLOSE_THRESHOLD: 6,
|
CONF_WINDOW_AUTO_CLOSE_THRESHOLD: 6,
|
||||||
CONF_WINDOW_AUTO_MAX_DURATION: 0, # 0 will deactivate window auto detection
|
CONF_WINDOW_AUTO_MAX_DURATION: 1, # 0 will deactivate window auto detection
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -604,9 +604,9 @@ async def test_window_auto_auto_stop(hass: HomeAssistant, skip_hass_states_is_st
|
|||||||
assert entity.target_temperature == 21
|
assert entity.target_temperature == 21
|
||||||
|
|
||||||
assert entity.window_state is STATE_OFF
|
assert entity.window_state is STATE_OFF
|
||||||
assert entity.is_window_auto_enabled is False
|
assert entity.is_window_auto_enabled is True
|
||||||
|
|
||||||
# Initialize the slope algo with 2 measurements
|
# 1. Initialize the slope algo with 2 measurements
|
||||||
event_timestamp = now + timedelta(minutes=1)
|
event_timestamp = now + timedelta(minutes=1)
|
||||||
await send_temperature_change_event(entity, 19, event_timestamp)
|
await send_temperature_change_event(entity, 19, event_timestamp)
|
||||||
event_timestamp = event_timestamp + timedelta(minutes=1)
|
event_timestamp = event_timestamp + timedelta(minutes=1)
|
||||||
@@ -614,7 +614,7 @@ async def test_window_auto_auto_stop(hass: HomeAssistant, skip_hass_states_is_st
|
|||||||
event_timestamp = event_timestamp + timedelta(minutes=1)
|
event_timestamp = event_timestamp + timedelta(minutes=1)
|
||||||
await send_temperature_change_event(entity, 19, event_timestamp)
|
await send_temperature_change_event(entity, 19, event_timestamp)
|
||||||
|
|
||||||
# Make the temperature down
|
# 2. Make the temperature down
|
||||||
with patch(
|
with patch(
|
||||||
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event"
|
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event"
|
||||||
) as mock_send_event, patch(
|
) as mock_send_event, patch(
|
||||||
@@ -634,7 +634,7 @@ async def test_window_auto_auto_stop(hass: HomeAssistant, skip_hass_states_is_st
|
|||||||
assert entity._window_auto_algo.is_window_close_detected() is False
|
assert entity._window_auto_algo.is_window_close_detected() is False
|
||||||
assert entity.hvac_mode is HVACMode.HEAT
|
assert entity.hvac_mode is HVACMode.HEAT
|
||||||
|
|
||||||
# send one degre down in one minute
|
# 3. send one degre down in one minute
|
||||||
with patch(
|
with patch(
|
||||||
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event"
|
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event"
|
||||||
) as mock_send_event, patch(
|
) as mock_send_event, patch(
|
||||||
@@ -670,12 +670,14 @@ async def test_window_auto_auto_stop(hass: HomeAssistant, skip_hass_states_is_st
|
|||||||
assert entity.window_auto_state == STATE_ON
|
assert entity.window_auto_state == STATE_ON
|
||||||
assert entity.hvac_mode is HVACMode.OFF
|
assert entity.hvac_mode is HVACMode.OFF
|
||||||
|
|
||||||
# This is to avoid that the slope stayx under 6, else we will reactivate the window immediatly
|
# 4. This is to avoid that the slope stay under 6, else we will reactivate the window immediatly
|
||||||
event_timestamp = event_timestamp + timedelta(minutes=1)
|
event_timestamp = event_timestamp + timedelta(minutes=1)
|
||||||
await send_temperature_change_event(entity, 19, event_timestamp, sleep=False)
|
dearm_window_auto = await send_temperature_change_event(
|
||||||
|
entity, 19, event_timestamp, sleep=False
|
||||||
|
)
|
||||||
assert entity.last_temperature_slope > -6.0
|
assert entity.last_temperature_slope > -6.0
|
||||||
|
|
||||||
# Waits for automatic disable
|
# 5. Waits for automatic disable
|
||||||
with patch(
|
with patch(
|
||||||
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event"
|
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event"
|
||||||
) as mock_send_event, patch(
|
) as mock_send_event, patch(
|
||||||
@@ -684,7 +686,8 @@ async def test_window_auto_auto_stop(hass: HomeAssistant, skip_hass_states_is_st
|
|||||||
"custom_components.versatile_thermostat.underlyings.UnderlyingSwitch.is_device_active",
|
"custom_components.versatile_thermostat.underlyings.UnderlyingSwitch.is_device_active",
|
||||||
return_value=False,
|
return_value=False,
|
||||||
):
|
):
|
||||||
await asyncio.sleep(0.3)
|
# simulate the expiration of the delay
|
||||||
|
await dearm_window_auto(None)
|
||||||
|
|
||||||
assert entity.hvac_mode is HVACMode.HEAT
|
assert entity.hvac_mode is HVACMode.HEAT
|
||||||
assert entity.preset_mode is PRESET_BOOST
|
assert entity.preset_mode is PRESET_BOOST
|
||||||
|
|||||||
Reference in New Issue
Block a user