Compare commits

..

1 Commits

Author SHA1 Message Date
Jean-Marc Collin
d4a719a660 Issue #903 - Modify "follow underlying changes" behavior - Transform 'Auto' hvac_mode to 'Heating' 2025-02-10 17:30:05 +00:00
5 changed files with 40 additions and 25 deletions

View File

@@ -130,10 +130,10 @@ class FeatureWindowManager(BaseFeatureManager):
async def start_listening(self): async def start_listening(self):
"""Start listening the underlying entity""" """Start listening the underlying entity"""
#Try to get last window bypass state # Try to get last window bypass state
old_state = await self._vtherm.async_get_last_state() old_state = await self._vtherm.async_get_last_state()
self._is_window_bypass = True if old_state and old_state.attributes and old_state.attributes.get("is_window_bypass") == True else False self._is_window_bypass = True if old_state and old_state.attributes and old_state.attributes.get("is_window_bypass") is True else False
if self._is_configured: if self._is_configured:
self.stop_listening() self.stop_listening()
if self._window_sensor_entity_id: if self._window_sensor_entity_id:
@@ -453,7 +453,7 @@ class FeatureWindowManager(BaseFeatureManager):
"""Set the window bypass flag """Set the window bypass flag
Return True if state have been changed""" Return True if state have been changed"""
self._is_window_bypass = window_bypass self._is_window_bypass = window_bypass
if self._window_state == STATE_ON: if self._window_state == STATE_ON:
if not self._is_window_bypass: if not self._is_window_bypass:
_LOGGER.info( _LOGGER.info(

View File

@@ -14,6 +14,6 @@
"quality_scale": "silver", "quality_scale": "silver",
"requirements": [], "requirements": [],
"ssdp": [], "ssdp": [],
"version": "7.2.2", "version": "7.2.1",
"zeroconf": [] "zeroconf": []
} }

View File

@@ -625,6 +625,10 @@ class ThermostatOverClimate(BaseThermostat[UnderlyingClimate]):
changes = False changes = False
new_hvac_mode = new_state.state new_hvac_mode = new_state.state
# Issue #903 - patch AUTO mode
if new_hvac_mode == HVACMode.AUTO:
new_hvac_mode = HVACMode.HEAT if not self.ac_mode else HVACMode.COOL
old_state = event.data.get("old_state") old_state = event.data.get("old_state")
# Issue #829 - refresh underlying command if it comes back to life # Issue #829 - refresh underlying command if it comes back to life

View File

@@ -1158,8 +1158,7 @@ class UnderlyingValveRegulation(UnderlyingValve):
if self.have_closing_degree_entity: if self.have_closing_degree_entity:
await self._send_value_to_number( await self._send_value_to_number(
self._closing_degree_entity_id, self._closing_degree_entity_id,
# Patch to fix the hvac_action always Idle issue (issue #902) closing_degree := self._max_opening_degree - self._percent_open,
closing_degree := max(self._max_opening_degree - 1 - self._percent_open, 0),
) )
# send offset_calibration to the difference between target temp and local temp # send offset_calibration to the difference between target temp and local temp

View File

@@ -139,7 +139,7 @@ async def test_over_climate_valve_mono(hass: HomeAssistant, skip_hass_states_get
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': 0}, target={'entity_id': 'number.mock_opening_degree'}),
call(domain='number', service='set_value', service_data={'value': 99}, target={'entity_id': 'number.mock_closing_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
@@ -188,7 +188,7 @@ async def test_over_climate_valve_mono(hass: HomeAssistant, skip_hass_states_get
[ [
call('climate', 'set_temperature', {'entity_id': 'climate.mock_climate', 'temperature': 19.0}), call('climate', 'set_temperature', {'entity_id': 'climate.mock_climate', 'temperature': 19.0}),
call(domain='number', service='set_value', service_data={'value': 40}, target={'entity_id': 'number.mock_opening_degree'}), call(domain='number', service='set_value', service_data={'value': 40}, target={'entity_id': 'number.mock_opening_degree'}),
call(domain='number', service='set_value', service_data={'value': 59}, target={'entity_id': 'number.mock_closing_degree'}), call(domain='number', service='set_value', service_data={'value': 60}, target={'entity_id': 'number.mock_closing_degree'}),
# 3 = 18 (room) - 15 (current of underlying) + 0 (current offset) # 3 = 18 (room) - 15 (current of underlying) + 0 (current offset)
call(domain='number', service='set_value', service_data={'value': 3.0}, target={'entity_id': 'number.mock_offset_calibration'}) call(domain='number', service='set_value', service_data={'value': 3.0}, target={'entity_id': 'number.mock_offset_calibration'})
] ]
@@ -234,7 +234,7 @@ async def test_over_climate_valve_mono(hass: HomeAssistant, skip_hass_states_get
mock_service_call.assert_has_calls( mock_service_call.assert_has_calls(
[ [
call(domain='number', service='set_value', service_data={'value': 13}, target={'entity_id': 'number.mock_opening_degree'}), call(domain='number', service='set_value', service_data={'value': 13}, target={'entity_id': 'number.mock_opening_degree'}),
call(domain='number', service='set_value', service_data={'value': 86}, target={'entity_id': 'number.mock_closing_degree'}), call(domain='number', service='set_value', service_data={'value': 87}, target={'entity_id': 'number.mock_closing_degree'}),
# 6 = 18 (room) - 15 (current of underlying) + 3 (current offset) # 6 = 18 (room) - 15 (current of underlying) + 3 (current offset)
call(domain='number', service='set_value', service_data={'value': 6.899999999999999}, target={'entity_id': 'number.mock_offset_calibration'}) call(domain='number', service='set_value', service_data={'value': 6.899999999999999}, target={'entity_id': 'number.mock_offset_calibration'})
] ]
@@ -280,7 +280,7 @@ async def test_over_climate_valve_mono(hass: HomeAssistant, skip_hass_states_get
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': 0}, target={'entity_id': 'number.mock_opening_degree'}),
call(domain='number', service='set_value', service_data={'value': 99}, target={'entity_id': 'number.mock_closing_degree'}), call(domain='number', service='set_value', service_data={'value': 100}, target={'entity_id': 'number.mock_closing_degree'}),
# 6 = 18 (room) - 15 (current of underlying) + 3 (current offset) # 6 = 18 (room) - 15 (current of underlying) + 3 (current offset)
call(domain='number', service='set_value', service_data={'value': 9.0}, target={'entity_id': 'number.mock_offset_calibration'}) call(domain='number', service='set_value', service_data={'value': 9.0}, target={'entity_id': 'number.mock_offset_calibration'})
] ]
@@ -365,13 +365,25 @@ async def test_over_climate_valve_multi_presence(
mock_get_state_side_effect = SideEffects( mock_get_state_side_effect = SideEffects(
{ {
# Valve 1 is open # Valve 1 is open
"number.mock_opening_degree1": State("number.mock_opening_degree1", "10", {"min": 0, "max": 100}), "number.mock_opening_degree1": State(
"number.mock_closing_degree1": State("number.mock_closing_degree1", "89", {"min": 0, "max": 100}), "number.mock_opening_degree1", "10", {"min": 0, "max": 100}
"number.mock_offset_calibration1": State("number.mock_offset_calibration1", "0", {"min": -12, "max": 12}), ),
"number.mock_closing_degree1": State(
"number.mock_closing_degree1", "90", {"min": 0, "max": 100}
),
"number.mock_offset_calibration1": State(
"number.mock_offset_calibration1", "0", {"min": -12, "max": 12}
),
# Valve 2 is closed # Valve 2 is closed
"number.mock_opening_degree2": State("number.mock_opening_degree2", "0", {"min": 0, "max": 100}), "number.mock_opening_degree2": State(
"number.mock_closing_degree2": State("number.mock_closing_degree2", "99", {"min": 0, "max": 100}), "number.mock_opening_degree2", "0", {"min": 0, "max": 100}
"number.mock_offset_calibration2": State("number.mock_offset_calibration2", "10", {"min": -12, "max": 12}), ),
"number.mock_closing_degree2": State(
"number.mock_closing_degree2", "100", {"min": 0, "max": 100}
),
"number.mock_offset_calibration2": State(
"number.mock_offset_calibration2", "10", {"min": -12, "max": 12}
),
}, },
State("unknown.entity_id", "unknown"), State("unknown.entity_id", "unknown"),
) )
@@ -431,10 +443,10 @@ async def test_over_climate_valve_multi_presence(
call('climate', 'set_temperature', {'entity_id': 'climate.mock_climate1', 'temperature': 19.0}), call('climate', 'set_temperature', {'entity_id': 'climate.mock_climate1', 'temperature': 19.0}),
call('climate', 'set_temperature', {'entity_id': 'climate.mock_climate2', 'temperature': 19.0}), call('climate', 'set_temperature', {'entity_id': 'climate.mock_climate2', 'temperature': 19.0}),
call(domain='number', service='set_value', service_data={'value': 40}, target={'entity_id': 'number.mock_opening_degree1'}), call(domain='number', service='set_value', service_data={'value': 40}, target={'entity_id': 'number.mock_opening_degree1'}),
call(domain='number', service='set_value', service_data={'value': 59}, target={'entity_id': 'number.mock_closing_degree1'}), call(domain='number', service='set_value', service_data={'value': 60}, target={'entity_id': 'number.mock_closing_degree1'}),
call(domain='number', service='set_value', service_data={'value': 3.0}, target={'entity_id': 'number.mock_offset_calibration1'}), call(domain='number', service='set_value', service_data={'value': 3.0}, target={'entity_id': 'number.mock_offset_calibration1'}),
call(domain='number', service='set_value', service_data={'value': 40}, target={'entity_id': 'number.mock_opening_degree2'}), call(domain='number', service='set_value', service_data={'value': 40}, target={'entity_id': 'number.mock_opening_degree2'}),
call(domain='number', service='set_value', service_data={'value': 59}, target={'entity_id': 'number.mock_closing_degree2'}), call(domain='number', service='set_value', service_data={'value': 60}, target={'entity_id': 'number.mock_closing_degree2'}),
call(domain='number', service='set_value', service_data={'value': 12}, target={'entity_id': 'number.mock_offset_calibration2'}) call(domain='number', service='set_value', service_data={'value': 12}, target={'entity_id': 'number.mock_offset_calibration2'})
] ]
) )
@@ -462,10 +474,10 @@ async def test_over_climate_valve_multi_presence(
call('climate', 'set_temperature', {'entity_id': 'climate.mock_climate1', 'temperature': 17.2}), call('climate', 'set_temperature', {'entity_id': 'climate.mock_climate1', 'temperature': 17.2}),
call('climate', 'set_temperature', {'entity_id': 'climate.mock_climate2', 'temperature': 17.2}), call('climate', 'set_temperature', {'entity_id': 'climate.mock_climate2', 'temperature': 17.2}),
call(domain='number', service='set_value', service_data={'value': 0}, target={'entity_id': 'number.mock_opening_degree1'}), call(domain='number', service='set_value', service_data={'value': 0}, target={'entity_id': 'number.mock_opening_degree1'}),
call(domain='number', service='set_value', service_data={'value': 99}, target={'entity_id': 'number.mock_closing_degree1'}), call(domain='number', service='set_value', service_data={'value': 100}, target={'entity_id': 'number.mock_closing_degree1'}),
call(domain='number', service='set_value', service_data={'value': 3.0}, target={'entity_id': 'number.mock_offset_calibration1'}), call(domain='number', service='set_value', service_data={'value': 3.0}, target={'entity_id': 'number.mock_offset_calibration1'}),
call(domain='number', service='set_value', service_data={'value': 0}, target={'entity_id': 'number.mock_opening_degree2'}), call(domain='number', service='set_value', service_data={'value': 0}, target={'entity_id': 'number.mock_opening_degree2'}),
call(domain='number', service='set_value', service_data={'value': 99}, target={'entity_id': 'number.mock_closing_degree2'}), call(domain='number', service='set_value', service_data={'value': 100}, target={'entity_id': 'number.mock_closing_degree2'}),
call(domain='number', service='set_value', service_data={'value': 12}, target={'entity_id': 'number.mock_offset_calibration2'}) call(domain='number', service='set_value', service_data={'value': 12}, target={'entity_id': 'number.mock_offset_calibration2'})
] ]
) )
@@ -616,10 +628,10 @@ async def test_over_climate_valve_multi_min_opening_degrees(
mock_service_call.assert_has_calls([ mock_service_call.assert_has_calls([
# min is 60 # min is 60
call(domain='number', service='set_value', service_data={'value': 68}, target={'entity_id': 'number.mock_opening_degree1'}), call(domain='number', service='set_value', service_data={'value': 68}, target={'entity_id': 'number.mock_opening_degree1'}),
call(domain='number', service='set_value', service_data={'value': 31}, target={'entity_id': 'number.mock_closing_degree1'}), call(domain='number', service='set_value', service_data={'value': 32}, target={'entity_id': 'number.mock_closing_degree1'}),
call(domain='number', service='set_value', service_data={'value': 3.0}, target={'entity_id': 'number.mock_offset_calibration1'}), call(domain='number', service='set_value', service_data={'value': 3.0}, target={'entity_id': 'number.mock_offset_calibration1'}),
call(domain='number', service='set_value', service_data={'value': 76}, target={'entity_id': 'number.mock_opening_degree2'}), call(domain='number', service='set_value', service_data={'value': 76}, target={'entity_id': 'number.mock_opening_degree2'}),
call(domain='number', service='set_value', service_data={'value': 23}, target={'entity_id': 'number.mock_closing_degree2'}), call(domain='number', service='set_value', service_data={'value': 24}, target={'entity_id': 'number.mock_closing_degree2'}),
call(domain='number', service='set_value', service_data={'value': 12}, target={'entity_id': 'number.mock_offset_calibration2'}) call(domain='number', service='set_value', service_data={'value': 12}, target={'entity_id': 'number.mock_offset_calibration2'})
] ]
) )
@@ -645,10 +657,10 @@ async def test_over_climate_valve_multi_min_opening_degrees(
assert mock_service_call.call_count == 6 assert mock_service_call.call_count == 6
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_degree1'}), call(domain='number', service='set_value', service_data={'value': 0}, target={'entity_id': 'number.mock_opening_degree1'}),
call(domain='number', service='set_value', service_data={'value': 99}, target={'entity_id': 'number.mock_closing_degree1'}), call(domain='number', service='set_value', service_data={'value': 100}, target={'entity_id': 'number.mock_closing_degree1'}),
call(domain='number', service='set_value', service_data={'value': 7.0}, target={'entity_id': 'number.mock_offset_calibration1'}), call(domain='number', service='set_value', service_data={'value': 7.0}, target={'entity_id': 'number.mock_offset_calibration1'}),
call(domain='number', service='set_value', service_data={'value': 0}, target={'entity_id': 'number.mock_opening_degree2'}), call(domain='number', service='set_value', service_data={'value': 0}, target={'entity_id': 'number.mock_opening_degree2'}),
call(domain='number', service='set_value', service_data={'value': 99}, target={'entity_id': 'number.mock_closing_degree2'}), call(domain='number', service='set_value', service_data={'value': 100}, target={'entity_id': 'number.mock_closing_degree2'}),
call(domain='number', service='set_value', service_data={'value': 12}, target={'entity_id': 'number.mock_offset_calibration2'}) call(domain='number', service='set_value', service_data={'value': 12}, target={'entity_id': 'number.mock_offset_calibration2'})
] ]
) )