FIX merge from #108 have lost some changes

This commit is contained in:
Jean-Marc Collin
2023-10-21 10:31:56 +00:00
parent cd0ab3c88d
commit 6dc078871d
2 changed files with 93 additions and 50 deletions

View File

@@ -1,3 +1,6 @@
# pylint: disable=line-too-long
# pylint: disable=too-many-lines
# pylint: disable=invalid-name
""" Implements the VersatileThermostat climate component """ """ Implements the VersatileThermostat climate component """
import math import math
import logging import logging
@@ -1312,7 +1315,9 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
self.recalculate() self.recalculate()
self.send_event(EventType.PRESET_EVENT, {"preset": self._attr_preset_mode}) self.send_event(EventType.PRESET_EVENT, {"preset": self._attr_preset_mode})
def reset_last_change_time(self, old_preset_mode=None): def reset_last_change_time(
self, old_preset_mode=None
): # pylint: disable=unused-argument
"""Reset to now the last change time""" """Reset to now the last change time"""
self._last_change_time = datetime.now(tz=self._current_tz) self._last_change_time = datetime.now(tz=self._current_tz)
_LOGGER.debug("%s - last_change_time is now %s", self, self._last_change_time) _LOGGER.debug("%s - last_change_time is now %s", self, self._last_change_time)
@@ -1546,7 +1551,11 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
# Check delay condition # Check delay condition
async def try_motion_condition(_): async def try_motion_condition(_):
try: try:
delay = self._motion_delay_sec if new_state.state == STATE_ON else self._motion_off_delay_sec delay = (
self._motion_delay_sec
if new_state.state == STATE_ON
else self._motion_off_delay_sec
)
long_enough = condition.state( long_enough = condition.state(
self.hass, self.hass,
self._motion_sensor_entity_id, self._motion_sensor_entity_id,
@@ -1583,13 +1592,17 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
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
delay_running = (self._motion_call_cancel is not None) delay_running = self._motion_call_cancel is not None
event_on = (new_state.state == STATE_ON) event_on = new_state.state == STATE_ON
def arm(): def arm():
""" Arm the timer""" """Arm the timer"""
delay = self._motion_delay_sec if new_state.state == STATE_ON else self._motion_off_delay_sec delay = (
self._motion_delay_sec
if new_state.state == STATE_ON
else self._motion_off_delay_sec
)
self._motion_call_cancel = async_call_later( self._motion_call_cancel = async_call_later(
self.hass, timedelta(seconds=delay), try_motion_condition self.hass, timedelta(seconds=delay), try_motion_condition
) )
@@ -1602,7 +1615,10 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
# if I'm off # if I'm off
if not im_on: if not im_on:
if event_on and not delay_running: if event_on and not delay_running:
_LOGGER.debug("%s - Arm delay cause i'm off and event is on and no delay is running", self) _LOGGER.debug(
"%s - Arm delay cause i'm off and event is on and no delay is running",
self,
)
arm() arm()
return try_motion_condition return try_motion_condition
# Ignore the event # Ignore the event
@@ -1614,7 +1630,10 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
arm() arm()
return try_motion_condition return try_motion_condition
if event_on and delay_running: if event_on and delay_running:
_LOGGER.debug("%s - Desarm off delay cause i'm on and event is on and a delay is running", self) _LOGGER.debug(
"%s - Desarm off delay cause i'm on and event is on and a delay is running",
self,
)
desarm() desarm()
return None return None
# Ignore the event # Ignore the event
@@ -1696,9 +1715,7 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
# Issue 99 - some AC turn hvac_mode=cool and hvac_action=idle when sending a HVACMode_OFF command # Issue 99 - some AC turn hvac_mode=cool and hvac_action=idle when sending a HVACMode_OFF command
# Issue 114 - Remove this because hvac_mode is now managed by local _hvac_mode and use idle action as is # Issue 114 - Remove this because hvac_mode is now managed by local _hvac_mode and use idle action as is
# if self._hvac_mode == HVACMode.OFF and new_hvac_action == HVACAction.IDLE: # if self._hvac_mode == HVACMode.OFF and new_hvac_action == HVACAction.IDLE:
# _LOGGER.debug( # _LOGGER.debug("The underlying switch to idle instead of OFF. We will consider it as OFF")
# "The underlying switch to idle instead of OFF. We will consider it as OFF"
# )
# new_hvac_mode = HVACMode.OFF # new_hvac_mode = HVACMode.OFF
_LOGGER.info( _LOGGER.info(
@@ -1710,17 +1727,15 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
old_hvac_action, old_hvac_action,
) )
if new_hvac_mode in [ _LOGGER.debug(
HVACMode.OFF, "%s - last_change_time=%s old_state_date_changed=%s old_state_date_updated=%s new_state_date_changed=%s new_state_date_updated=%s",
HVACMode.HEAT, self,
HVACMode.COOL, self._last_change_time,
HVACMode.HEAT_COOL, old_state_date_changed,
HVACMode.DRY, old_state_date_updated,
HVACMode.AUTO, new_state_date_changed,
HVACMode.FAN_ONLY, new_state_date_updated,
None, )
]:
self._hvac_mode = new_hvac_mode
# Interpretation of hvac action # Interpretation of hvac action
HVAC_ACTION_ON = [ # pylint: disable=invalid-name HVAC_ACTION_ON = [ # pylint: disable=invalid-name

View File

@@ -1,11 +1,11 @@
""" Test the Multiple switch management """ """ Test the Multiple switch management """
import asyncio import asyncio
from unittest.mock import patch, call, ANY from unittest.mock import patch, call, ANY
from .commons import * # pylint: disable=wildcard-import, unused-wildcard-import
from datetime import datetime, timedelta from datetime import datetime, timedelta
import logging import logging
from .commons import * # pylint: disable=wildcard-import, unused-wildcard-import
logging.getLogger().setLevel(logging.DEBUG) logging.getLogger().setLevel(logging.DEBUG)
@@ -15,7 +15,7 @@ async def test_one_switch_cycle(
hass: HomeAssistant, hass: HomeAssistant,
skip_hass_states_is_state, skip_hass_states_is_state,
skip_send_event, skip_send_event,
): ): # pylint: disable=unused-argument
"""Test that when multiple switch are configured the activation is distributed""" """Test that when multiple switch are configured the activation is distributed"""
tz = get_tz(hass) # pylint: disable=invalid-name tz = get_tz(hass) # pylint: disable=invalid-name
@@ -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 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
@@ -132,7 +132,8 @@ async def test_one_switch_cycle(
assert mock_send_event.call_count == 0 assert mock_send_event.call_count == 0
assert mock_heater_off.call_count == 0 assert mock_heater_off.call_count == 0
# The first heater should be turned on but is already on but because above we mock call_later the heater is not on. But this time it will be really on # The first heater should be turned on but is already on but because above we mock
# call_later the heater is not on. But this time it will be really on
assert mock_heater_on.call_count == 1 assert mock_heater_on.call_count == 1
# Set another temperature at middle level # Set another temperature at middle level
@@ -153,12 +154,15 @@ async def test_one_switch_cycle(
assert mock_send_event.call_count == 0 assert mock_send_event.call_count == 0
assert mock_heater_off.call_count == 0 assert mock_heater_off.call_count == 0
# The heater is already on cycle. So we wait that the cycle ends and no heater action is done # The heater is already on cycle. So we wait that the cycle ends and no heater action
# is done
assert mock_heater_on.call_count == 0 assert mock_heater_on.call_count == 0
# assert entity.underlying_entity(0)._should_relaunch_control_heating is True # assert entity.underlying_entity(0)._should_relaunch_control_heating is True
# Simulate the relaunch # Simulate the relaunch
await entity.underlying_entity(0)._turn_on_later(None) await entity.underlying_entity(0)._turn_on_later( # pylint: disable=protected-access
None
)
# wait restart # wait restart
await asyncio.sleep(0.1) await asyncio.sleep(0.1)
@@ -177,7 +181,9 @@ async def test_one_switch_cycle(
"custom_components.versatile_thermostat.underlyings.UnderlyingSwitch.is_device_active", "custom_components.versatile_thermostat.underlyings.UnderlyingSwitch.is_device_active",
return_value=True, return_value=True,
) as mock_device_active: ) as mock_device_active:
await entity.underlying_entity(0)._turn_off_later(None) await entity.underlying_entity(0)._turn_off_later( # pylint: disable=protected-access
None
)
# No special event # No special event
assert mock_send_event.call_count == 0 assert mock_send_event.call_count == 0
@@ -198,7 +204,9 @@ async def test_one_switch_cycle(
"custom_components.versatile_thermostat.underlyings.UnderlyingSwitch.is_device_active", "custom_components.versatile_thermostat.underlyings.UnderlyingSwitch.is_device_active",
return_value=True, return_value=True,
) as mock_device_active: ) as mock_device_active:
await entity.underlying_entity(0)._turn_on_later(None) await entity.underlying_entity(0)._turn_on_later( # pylint: disable=protected-access
None
)
# No special event # No special event
assert mock_send_event.call_count == 0 assert mock_send_event.call_count == 0
@@ -214,7 +222,7 @@ async def test_multiple_switchs(
hass: HomeAssistant, hass: HomeAssistant,
skip_hass_states_is_state, skip_hass_states_is_state,
skip_send_event, skip_send_event,
): ): # pylint: disable=unused-argument
"""Test that when multiple switch are configured the activation is distributed""" """Test that when multiple switch are configured the activation is distributed"""
tz = get_tz(hass) # pylint: disable=invalid-name tz = get_tz(hass) # pylint: disable=invalid-name
@@ -277,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 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
@@ -342,17 +350,20 @@ async def test_multiple_switchs(
assert mock_send_event.call_count == 0 assert mock_send_event.call_count == 0
assert mock_heater_off.call_count == 0 assert mock_heater_off.call_count == 0
# The first heater should be turned on but is already on but because call_later is mocked, it is only turned on here # The first heater should be turned on but is already on but because call_later
# is mocked, it is only turned on here
assert mock_heater_on.call_count == 1 assert mock_heater_on.call_count == 1
@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_climates( async def test_multiple_climates(
hass: HomeAssistant, hass: HomeAssistant,
skip_hass_states_is_state, skip_hass_states_is_state,
skip_send_event, skip_send_event,
): ): # pylint: disable=unused-argument
"""Test that when multiple climates are configured the activation and deactivation is propagated to all climates""" """Test that when multiple climates are configured the activation and deactivation
is propagated to all climates"""
tz = get_tz(hass) # pylint: disable=invalid-name tz = get_tz(hass) # pylint: disable=invalid-name
now: datetime = datetime.now(tz=tz) now: datetime = datetime.now(tz=tz)
@@ -416,7 +427,7 @@ async def test_multiple_climates(
call.set_hvac_mode(HVACMode.HEAT), call.set_hvac_mode(HVACMode.HEAT),
] ]
) )
assert entity._is_device_active is False 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(
@@ -441,7 +452,8 @@ async def test_multiple_climates(
call.set_hvac_mode(HVACMode.OFF), call.set_hvac_mode(HVACMode.OFF),
] ]
) )
assert entity._is_device_active is False 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])
@pytest.mark.parametrize("expected_lingering_timers", [True]) @pytest.mark.parametrize("expected_lingering_timers", [True])
@@ -449,8 +461,9 @@ async def test_multiple_climates_underlying_changes(
hass: HomeAssistant, hass: HomeAssistant,
skip_hass_states_is_state, skip_hass_states_is_state,
skip_send_event, skip_send_event,
): ): # pylint: disable=unused-argument
"""Test that when multiple switch are configured the activation of one underlying climate activate the others""" """Test that when multiple switch are configured the activation of one underlying
climate activate the others"""
tz = get_tz(hass) # pylint: disable=invalid-name tz = get_tz(hass) # pylint: disable=invalid-name
now: datetime = datetime.now(tz=tz) now: datetime = datetime.now(tz=tz)
@@ -514,7 +527,7 @@ 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 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(
@@ -524,7 +537,14 @@ async def test_multiple_climates_underlying_changes(
) as mock_underlying_set_hvac_mode: ) as mock_underlying_set_hvac_mode:
# 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(entity, HVACMode.OFF, HVACMode.HEAT, HVACAction.OFF, HVACAction.HEATING, event_timestamp) await send_climate_change_event(
entity,
HVACMode.OFF,
HVACMode.HEAT,
HVACAction.OFF,
HVACAction.HEATING,
event_timestamp,
)
# 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
@@ -534,7 +554,7 @@ 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 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(
@@ -542,12 +562,21 @@ async def test_multiple_climates_underlying_changes(
), 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(
# notice that there is no need of return_value=HVACAction.IDLE because this is not a function but a property # notice that there is no need of return_value=HVACAction.IDLE because this is not
"custom_components.versatile_thermostat.underlyings.UnderlyingClimate.hvac_action", HVACAction.IDLE # a function but a property
) as mock_underlying_get_hvac_action: "custom_components.versatile_thermostat.underlyings.UnderlyingClimate.hvac_action",
HVACAction.IDLE,
):
# 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(entity, HVACMode.HEAT, HVACMode.OFF, HVACAction.IDLE, HVACAction.OFF, event_timestamp) await send_climate_change_event(
entity,
HVACMode.HEAT,
HVACMode.OFF,
HVACAction.IDLE,
HVACAction.OFF,
event_timestamp,
)
# 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
@@ -558,5 +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 assert entity._is_device_active is False # pylint: disable=protected-access