Compare commits
14 Commits
7.2.0
...
jmcollin78
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36fe361ad0 | ||
|
|
b8e5275cf9 | ||
|
|
35270f1394 | ||
|
|
ce4acab908 | ||
|
|
ea0d66f0c6 | ||
|
|
641801084d | ||
|
|
1576e9c189 | ||
|
|
313fa26160 | ||
|
|
832ea78a12 | ||
|
|
5f167af331 | ||
|
|
c20e641ac1 | ||
|
|
87064882a3 | ||
|
|
1c0a7cb4e8 | ||
|
|
b1f2fcd66d |
@@ -191,6 +191,9 @@ input_boolean:
|
||||
fake_valve_sonoff_trvzb2:
|
||||
name: Valve Sonoff TRVZB2
|
||||
icon: mdi:valve
|
||||
fake_inversed_heater:
|
||||
name: Inversed Heater
|
||||
icon: mdi:radiator-off
|
||||
|
||||
climate:
|
||||
- platform: generic_thermostat
|
||||
@@ -314,6 +317,21 @@ switch:
|
||||
option: comfort-2
|
||||
target:
|
||||
entity_id: select.seche_serviettes_sdb_rdc_cable_outlet_mode
|
||||
- platform: template
|
||||
switches:
|
||||
fake_inversed_switch:
|
||||
friendly_name: "A fake inversed switch"
|
||||
value_template: "{{ is_state('input_boolean.fake_inversed_heater', 'on') }}"
|
||||
turn_on:
|
||||
action: input_boolean.turn_on
|
||||
data: {}
|
||||
target:
|
||||
entity_id: input_boolean.fake_inversed_heater
|
||||
turn_off:
|
||||
action: input_boolean.turn_off
|
||||
data: {}
|
||||
target:
|
||||
entity_id: input_boolean.fake_inversed_heater
|
||||
|
||||
frontend:
|
||||
extra_module_url:
|
||||
|
||||
@@ -44,7 +44,6 @@ class FeatureWindowManager(BaseFeatureManager):
|
||||
{
|
||||
"window_sensor_entity_id",
|
||||
"is_window_configured",
|
||||
"is_window_bypass",
|
||||
"window_delay_sec",
|
||||
"window_off_delay_sec",
|
||||
"window_auto_configured",
|
||||
@@ -130,6 +129,11 @@ class FeatureWindowManager(BaseFeatureManager):
|
||||
@overrides
|
||||
async def start_listening(self):
|
||||
"""Start listening the underlying entity"""
|
||||
|
||||
#Try to get last window bypass 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
|
||||
|
||||
if self._is_configured:
|
||||
self.stop_listening()
|
||||
if self._window_sensor_entity_id:
|
||||
@@ -449,22 +453,23 @@ class FeatureWindowManager(BaseFeatureManager):
|
||||
"""Set the window bypass flag
|
||||
Return True if state have been changed"""
|
||||
self._is_window_bypass = window_bypass
|
||||
if not self._is_window_bypass and self._window_state:
|
||||
_LOGGER.info(
|
||||
"%s - Last window state was open & ByPass is now off. Set hvac_mode to '%s'",
|
||||
self,
|
||||
HVACMode.OFF,
|
||||
)
|
||||
self._vtherm.save_hvac_mode()
|
||||
await self._vtherm.async_set_hvac_mode(HVACMode.OFF)
|
||||
return True
|
||||
|
||||
if self._window_state == STATE_ON:
|
||||
if not self._is_window_bypass:
|
||||
_LOGGER.info(
|
||||
"%s - Last window state was open & ByPass is now off. Set hvac_mode to '%s'",
|
||||
self,
|
||||
HVACMode.OFF,
|
||||
)
|
||||
self._vtherm.save_hvac_mode()
|
||||
await self._vtherm.async_set_hvac_mode(HVACMode.OFF)
|
||||
|
||||
if self._is_window_bypass and self._window_state:
|
||||
_LOGGER.info(
|
||||
"%s - Last window state was open & ByPass is now on. Set hvac_mode to last available mode",
|
||||
self,
|
||||
)
|
||||
await self._vtherm.restore_hvac_mode(True)
|
||||
if self._is_window_bypass:
|
||||
_LOGGER.info(
|
||||
"%s - Last window state was open & ByPass is now on. Set hvac_mode to last available mode",
|
||||
self,
|
||||
)
|
||||
await self._vtherm.restore_hvac_mode(True)
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -504,10 +509,10 @@ class FeatureWindowManager(BaseFeatureManager):
|
||||
|
||||
@property
|
||||
def is_window_detected(self) -> bool:
|
||||
"""Return true if the presence is configured and presence sensor is OFF"""
|
||||
"""Return true if the window is configured and open and bypass is not ON"""
|
||||
return self._is_configured and (
|
||||
self._window_state == STATE_ON or self._window_auto_state == STATE_ON
|
||||
)
|
||||
) and not self._is_window_bypass
|
||||
|
||||
@property
|
||||
def window_sensor_entity_id(self) -> bool:
|
||||
|
||||
@@ -14,6 +14,6 @@
|
||||
"quality_scale": "silver",
|
||||
"requirements": [],
|
||||
"ssdp": [],
|
||||
"version": "7.2.0",
|
||||
"version": "7.2.2",
|
||||
"zeroconf": []
|
||||
}
|
||||
@@ -281,8 +281,8 @@ class UnderlyingSwitch(UnderlyingEntity):
|
||||
# not self.is_inversed and real_state
|
||||
# )
|
||||
is_on = self._hass.states.is_state(self._entity_id, self._on_command.get("state"))
|
||||
if self.is_inversed:
|
||||
return not is_on
|
||||
# if self.is_inversed:
|
||||
# return not is_on
|
||||
|
||||
return is_on
|
||||
|
||||
@@ -968,10 +968,10 @@ class UnderlyingValve(UnderlyingEntity):
|
||||
# This could happens in unit test if input_number domain is not yet loaded
|
||||
# raise err
|
||||
|
||||
async def send_percent_open(self):
|
||||
async def send_percent_open(self, fixed_value: float = None):
|
||||
"""Send the percent open to the underlying valve"""
|
||||
# This may fails if called after shutdown
|
||||
return await self._send_value_to_number(self._entity_id, self._percent_open)
|
||||
return await self._send_value_to_number(self._entity_id, self._percent_open if fixed_value is None else fixed_value)
|
||||
|
||||
async def turn_off(self):
|
||||
"""Turn heater toggleable device off."""
|
||||
@@ -1108,7 +1108,15 @@ class UnderlyingValveRegulation(UnderlyingValve):
|
||||
self._max_offset_calibration: float = None
|
||||
self._min_opening_degree: int = min_opening_degree
|
||||
|
||||
async def send_percent_open(self):
|
||||
def _normalize_opening_closing_degree(self, opening: float) -> float:
|
||||
"""Issue #902 - Normalize the opening and closing degree"""
|
||||
|
||||
new_opening = max(opening - 1, 0)
|
||||
new_closing = max(self._max_opening_degree - 1 - new_opening, 0)
|
||||
|
||||
return new_opening, new_closing
|
||||
|
||||
async def send_percent_open(self, _: float = None):
|
||||
"""Send the percent open to the underlying valve"""
|
||||
if not self._is_min_max_initialized:
|
||||
_LOGGER.debug(
|
||||
@@ -1150,16 +1158,16 @@ class UnderlyingValveRegulation(UnderlyingValve):
|
||||
else:
|
||||
self._percent_open = 0
|
||||
|
||||
# Send opening_degree
|
||||
await super().send_percent_open()
|
||||
|
||||
# Send closing_degree if set
|
||||
closing_degree = None
|
||||
opening_degree, closing_degree = self._normalize_opening_closing_degree(self._percent_open)
|
||||
# We should not change the _percent_open because it is used to check if value has bchanged
|
||||
# self._percent_open = opening_degree
|
||||
|
||||
# Send opening_degree
|
||||
await super().send_percent_open(opening_degree)
|
||||
|
||||
if self.have_closing_degree_entity:
|
||||
await self._send_value_to_number(
|
||||
self._closing_degree_entity_id,
|
||||
closing_degree := self._max_opening_degree - self._percent_open,
|
||||
)
|
||||
await self._send_value_to_number(self._closing_degree_entity_id, closing_degree)
|
||||
|
||||
# send offset_calibration to the difference between target temp and local temp
|
||||
offset = None
|
||||
|
||||
@@ -71,12 +71,12 @@ To customize the commands, click on `Add` at the bottom of the page for both the
|
||||
Then, specify the on and off commands using the format `command[/attribute[:value]]`.
|
||||
The available commands depend on the type of underlying device:
|
||||
|
||||
| Underlying Device Type | Possible On Commands | Possible Off Commands | Applies To |
|
||||
| --------------------------- | ------------------------------------- | ----------------------------------- | ----------------------------- |
|
||||
| `switch` or `input_boolean` | `turn_on` | `turn_off` | All switches |
|
||||
| `select` or `input_select` | `select_option/option:comfort` | `set_option/option:frost` | Nodon SIN-4-FP-21 and similar |
|
||||
| `climate` (hvac_mode) | `set_hvac_mode/hvac_mode:heat` | `set_hvac_mode/hvac_mode:off` | eCosy (via Tuya Local) |
|
||||
| `climate` (preset) | `set_preset_mode/preset_mode:comfort` | `set_preset_mode/preset_mode:frost` | Heatzy |
|
||||
| Underlying Device Type | Possible On Commands | Possible Off Commands | Applies To |
|
||||
| --------------------------- | ------------------------------------- | ---------------------------------------------- | ----------------------------- |
|
||||
| `switch` or `input_boolean` | `turn_on` | `turn_off` | All switches |
|
||||
| `select` or `input_select` | `select_option/option:comfort` | `select_option/option:frost_protection` | Nodon SIN-4-FP-21 and similar |
|
||||
| `climate` (hvac_mode) | `set_hvac_mode/hvac_mode:heat` | `set_hvac_mode/hvac_mode:off` | eCosy (via Tuya Local) |
|
||||
| `climate` (preset) | `set_preset_mode/preset_mode:comfort` | `set_preset_mode/preset_mode:frost_protection` | Heatzy |
|
||||
|
||||
Of course, these examples can be adapted to your specific case.
|
||||
|
||||
|
||||
@@ -69,12 +69,12 @@ Pour personnaliser les commande, cliquez sur `Ajouter` en bas de page sur les co
|
||||
et donner la commande d'allumage et d'exinction avec le format `commande[/attribut[:valeur]]`.
|
||||
Les commandes possibles dépendent du type de sous-jacents :
|
||||
|
||||
| type de sous-jacent | commandes d'allumage possibles | commandes d'extinction possibles | S'applique à |
|
||||
| --------------------------- | ------------------------------------- | ----------------------------------- | ------------------------------ |
|
||||
| `switch` ou `input_boolean` | `turn_on` | `turn_off` | tous les switchs |
|
||||
| `select` ou `input_select` | `select_option/option:comfort` | `set_option/option:frost` | Nodon SIN-4-FP-21 et assimilés |
|
||||
| `climate` (hvac_mode) | `set_hvac_mode/hvac_mode:heat` | `set_hvac_mode/hvac_mode:off` | eCosy (via Tuya Local) |
|
||||
| `climate` (preset) | `set_preset_mode/preset_mode:comfort` | `set_preset_mode/preset_mode:frost` | Heatzy |
|
||||
| type de sous-jacent | commandes d'allumage possibles | commandes d'extinction possibles | S'applique à |
|
||||
| --------------------------- | ------------------------------------- | ---------------------------------------------- | ------------------------------ |
|
||||
| `switch` ou `input_boolean` | `turn_on` | `turn_off` | tous les switchs |
|
||||
| `select` ou `input_select` | `select_option/option:comfort` | `select_option/option:frost_protection` | Nodon SIN-4-FP-21 et assimilés |
|
||||
| `climate` (hvac_mode) | `set_hvac_mode/hvac_mode:heat` | `set_hvac_mode/hvac_mode:off` | eCosy (via Tuya Local) |
|
||||
| `climate` (preset) | `set_preset_mode/preset_mode:comfort` | `set_preset_mode/preset_mode:frost_protection` | Heatzy |
|
||||
|
||||
Evidemment, tous ces exemples peuvent être adaptés à votre cas.
|
||||
|
||||
@@ -90,4 +90,4 @@ Si l'erreur suivante se produit :
|
||||
Cela signifie que une des commandes saisies est invalide. Les règles à respecter sont les suivantes :
|
||||
1. chaque commande doit avoir le format `commande[/attribut[:valeur]]` (ex: `select_option/option:comfort` ou `turn_on`) sans blanc et sans caractères spéciaux sauf '_',
|
||||
2. il doit y avoir autant de commandes qu'il y a de sous-jacents déclarés sauf si tous les sous-jacents sont des `switchs` auquel cas il n'est pas nécessaire de paramétrer les commandes,
|
||||
3. si plusieurs sous-jacents sont configurés, les commandes doivent être dans le même ordre. Le nombre de commandes d'allumage doit être égal au nombre de commandes d'extinction et de sous-jacents (dans l'ordre donc). Il est possible de mettre des sous-jacents de type différent. À partir du moment où un sous-jacent n'est pas un `switch`, il faut paramétrer toutes les commandes de tous les sous-jacents y compris des éventuels switchs.
|
||||
3. si plusieurs sous-jacents sont configurés, les commandes doivent être dans le même ordre. Le nombre de commandes d'allumage doit être égal au nombre de commandes d'extinction et de sous-jacents (dans l'ordre donc). Il est possible de mettre des sous-jacents de type différent. À partir du moment où un sous-jacent n'est pas un `switch`, il faut paramétrer toutes les commandes de tous les sous-jacents y compris des éventuels switchs.
|
||||
|
||||
@@ -1 +1 @@
|
||||
homeassistant==2025.1.2
|
||||
homeassistant==2025.1.4
|
||||
|
||||
@@ -18,6 +18,12 @@ logging.getLogger().setLevel(logging.DEBUG)
|
||||
async def test_inverted_switch(hass: HomeAssistant, skip_hass_states_is_state):
|
||||
"""Test the Window auto management"""
|
||||
|
||||
temps = {
|
||||
"eco": 17,
|
||||
"comfort": 18,
|
||||
"boost": 21,
|
||||
}
|
||||
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
title="TheOverSwitchMockName",
|
||||
@@ -30,14 +36,11 @@ async def test_inverted_switch(hass: HomeAssistant, skip_hass_states_is_state):
|
||||
CONF_CYCLE_MIN: 5,
|
||||
CONF_TEMP_MIN: 15,
|
||||
CONF_TEMP_MAX: 30,
|
||||
"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_HEATER: "switch.mock_switch",
|
||||
CONF_UNDERLYING_LIST: ["switch.mock_switch"],
|
||||
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
|
||||
CONF_TPI_COEF_INT: 0.3,
|
||||
CONF_TPI_COEF_EXT: 0.01,
|
||||
@@ -51,14 +54,12 @@ async def test_inverted_switch(hass: HomeAssistant, skip_hass_states_is_state):
|
||||
},
|
||||
)
|
||||
|
||||
with patch(
|
||||
"homeassistant.core.ServiceRegistry.async_call"
|
||||
) as mock_service_call, patch(
|
||||
"homeassistant.core.StateMachine.is_state", return_value=True # switch is On
|
||||
# 0. Create the entity
|
||||
|
||||
with patch("homeassistant.core.ServiceRegistry.async_call") as mock_service_call, patch(
|
||||
"homeassistant.core.StateMachine.is_state", return_value=False # switch is On so is_state(switch, 'off') is False
|
||||
):
|
||||
entity: ThermostatOverSwitch = await create_thermostat(
|
||||
hass, entry, "climate.theoverswitchmockname"
|
||||
)
|
||||
entity: ThermostatOverSwitch = await create_thermostat(hass, entry, "climate.theoverswitchmockname", temps)
|
||||
assert entity
|
||||
assert entity.is_inversed
|
||||
|
||||
@@ -78,12 +79,10 @@ async def test_inverted_switch(hass: HomeAssistant, skip_hass_states_is_state):
|
||||
assert mock_service_call.call_count == 0
|
||||
|
||||
# 1. Make the temperature down to activate the switch
|
||||
with patch(
|
||||
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event"
|
||||
), patch(
|
||||
with patch("custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event"), patch(
|
||||
"homeassistant.core.ServiceRegistry.async_call"
|
||||
) as mock_service_call, patch(
|
||||
"homeassistant.core.StateMachine.is_state", return_value=True # switch is Off
|
||||
"homeassistant.core.StateMachine.is_state", return_value=True # switch is Off so is_state(switch, 'off') is True
|
||||
):
|
||||
event_timestamp = now - timedelta(minutes=4)
|
||||
await send_temperature_change_event(entity, 19, event_timestamp)
|
||||
|
||||
@@ -139,7 +139,7 @@ async def test_over_climate_valve_mono(hass: HomeAssistant, skip_hass_states_get
|
||||
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(domain='number', service='set_value', service_data={'value': 99}, target={'entity_id': 'number.mock_closing_degree'}),
|
||||
call("climate","set_temperature",{
|
||||
"entity_id": "climate.mock_climate",
|
||||
"temperature": 15, # temp-min
|
||||
@@ -187,7 +187,7 @@ async def test_over_climate_valve_mono(hass: HomeAssistant, skip_hass_states_get
|
||||
mock_service_call.assert_has_calls(
|
||||
[
|
||||
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': 39}, target={'entity_id': 'number.mock_opening_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)
|
||||
call(domain='number', service='set_value', service_data={'value': 3.0}, target={'entity_id': 'number.mock_offset_calibration'})
|
||||
@@ -233,7 +233,7 @@ async def test_over_climate_valve_mono(hass: HomeAssistant, skip_hass_states_get
|
||||
assert mock_service_call.call_count == 3
|
||||
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': 12}, target={'entity_id': 'number.mock_opening_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)
|
||||
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(
|
||||
[
|
||||
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(domain='number', service='set_value', service_data={'value': 99}, target={'entity_id': 'number.mock_closing_degree'}),
|
||||
# 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'})
|
||||
]
|
||||
@@ -365,25 +365,13 @@ async def test_over_climate_valve_multi_presence(
|
||||
mock_get_state_side_effect = SideEffects(
|
||||
{
|
||||
# Valve 1 is open
|
||||
"number.mock_opening_degree1": State(
|
||||
"number.mock_opening_degree1", "10", {"min": 0, "max": 100}
|
||||
),
|
||||
"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}
|
||||
),
|
||||
"number.mock_opening_degree1": State("number.mock_opening_degree1", "10", {"min": 0, "max": 100}),
|
||||
"number.mock_closing_degree1": State("number.mock_closing_degree1", "89", {"min": 0, "max": 100}),
|
||||
"number.mock_offset_calibration1": State("number.mock_offset_calibration1", "0", {"min": -12, "max": 12}),
|
||||
# Valve 2 is closed
|
||||
"number.mock_opening_degree2": State(
|
||||
"number.mock_opening_degree2", "0", {"min": 0, "max": 100}
|
||||
),
|
||||
"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}
|
||||
),
|
||||
"number.mock_opening_degree2": State("number.mock_opening_degree2", "0", {"min": 0, "max": 100}),
|
||||
"number.mock_closing_degree2": State("number.mock_closing_degree2", "99", {"min": 0, "max": 100}),
|
||||
"number.mock_offset_calibration2": State("number.mock_offset_calibration2", "10", {"min": -12, "max": 12}),
|
||||
},
|
||||
State("unknown.entity_id", "unknown"),
|
||||
)
|
||||
@@ -442,10 +430,10 @@ async def test_over_climate_valve_multi_presence(
|
||||
mock_service_call.assert_has_calls([
|
||||
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(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': 39}, target={'entity_id': 'number.mock_opening_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': 40}, target={'entity_id': 'number.mock_opening_degree2'}),
|
||||
call(domain='number', service='set_value', service_data={'value': 39}, target={'entity_id': 'number.mock_opening_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'})
|
||||
]
|
||||
@@ -469,15 +457,15 @@ async def test_over_climate_valve_multi_presence(
|
||||
assert vtherm.valve_open_percent == 0
|
||||
|
||||
# the underlying set temperature call and the call to the valve
|
||||
assert mock_service_call.call_count == 8
|
||||
# assert mock_service_call.call_count == 8
|
||||
mock_service_call.assert_has_calls([
|
||||
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(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': 100}, target={'entity_id': 'number.mock_closing_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': 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': 100}, target={'entity_id': 'number.mock_closing_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': 12}, target={'entity_id': 'number.mock_offset_calibration2'})
|
||||
]
|
||||
)
|
||||
@@ -627,10 +615,10 @@ async def test_over_climate_valve_multi_min_opening_degrees(
|
||||
assert mock_service_call.call_count == 6
|
||||
mock_service_call.assert_has_calls([
|
||||
# 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': 67}, target={'entity_id': 'number.mock_opening_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': 76}, target={'entity_id': 'number.mock_opening_degree2'}),
|
||||
call(domain='number', service='set_value', service_data={'value': 75}, target={'entity_id': 'number.mock_opening_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'})
|
||||
]
|
||||
@@ -657,10 +645,10 @@ async def test_over_climate_valve_multi_min_opening_degrees(
|
||||
assert mock_service_call.call_count == 6
|
||||
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': 100}, target={'entity_id': 'number.mock_closing_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': 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': 100}, target={'entity_id': 'number.mock_closing_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': 12}, target={'entity_id': 'number.mock_offset_calibration2'})
|
||||
]
|
||||
)
|
||||
|
||||
@@ -700,7 +700,7 @@ async def test_add_number_for_over_switch_use_central_presets_and_restore(
|
||||
assert vtherm.use_central_config_temperature is True
|
||||
|
||||
# We should try to restore all 4 temp entities and the VTherm itself
|
||||
assert mock_restore_state.call_count == 4 + 1
|
||||
assert mock_restore_state.call_count == 4 + 2
|
||||
|
||||
# 1. We search for NumberEntities
|
||||
for preset_name, value in temps.items():
|
||||
|
||||
@@ -71,6 +71,19 @@ from .commons import *
|
||||
HVACMode.HEAT,
|
||||
True,
|
||||
),
|
||||
# Inversed switch without command personnalisations
|
||||
(
|
||||
True,
|
||||
None,
|
||||
None,
|
||||
"turn_off",
|
||||
{"entity_id": "switch.test"},
|
||||
STATE_OFF,
|
||||
"turn_on",
|
||||
{"entity_id": "switch.test"},
|
||||
STATE_ON,
|
||||
True,
|
||||
),
|
||||
# Error cases invalid command
|
||||
(
|
||||
False,
|
||||
|
||||
@@ -300,7 +300,7 @@ async def test_window_feature_manager_refresh_sensor_action_frost_only(
|
||||
with patch("homeassistant.core.StateMachine.get", return_value=State("sensor.the_motion_sensor", new_state)) as mock_get_state:
|
||||
# fmt:on
|
||||
# Configurer les méthodes mockées
|
||||
fake_vtherm.save_target_temp = AsyncMock()
|
||||
fake_vtherm.save_target_temp = MagicMock()
|
||||
fake_vtherm.set_hvac_off_reason = MagicMock()
|
||||
fake_vtherm.restore_target_temp = AsyncMock()
|
||||
fake_vtherm.change_target_temperature = AsyncMock()
|
||||
@@ -542,7 +542,7 @@ async def test_window_feature_manager_event_sensor_action_frost_only(
|
||||
with patch("homeassistant.helpers.condition.state", return_value=long_enough):
|
||||
# fmt:on
|
||||
# Configurer les méthodes mockées
|
||||
fake_vtherm.save_target_temp = AsyncMock()
|
||||
fake_vtherm.save_target_temp = MagicMock()
|
||||
fake_vtherm.set_hvac_off_reason = MagicMock()
|
||||
fake_vtherm.restore_target_temp = AsyncMock()
|
||||
fake_vtherm.change_target_temperature = AsyncMock()
|
||||
|
||||
Reference in New Issue
Block a user