Revert "ok + testu ok (#729)" (#730)

This reverts commit 083a3a4c81.
This commit is contained in:
Jean-Marc Collin
2024-12-21 19:31:35 +01:00
committed by GitHub
parent 083a3a4c81
commit 24f6445861
10 changed files with 14 additions and 266 deletions

View File

@@ -259,21 +259,6 @@ class VersatileThermostatBaseConfigFlow(FlowHandler):
if not self.check_valve_regulation_nb_entities(data, step_id):
raise ValveRegulationNbEntitiesIncorrect()
# Check that the min_opening_degrees is correctly set
raw_list = data.get(CONF_MIN_OPENING_DEGREES, None)
if raw_list:
try:
# Validation : Convertir la liste saisie
int_list = [int(x.strip()) for x in raw_list.split(",")]
# Optionnel : Vérifiez des conditions supplémentaires sur la liste
if any(x < 0 for x in int_list):
raise ValueError
except ValueError as exc:
raise ValveRegulationMinOpeningDegreesIncorrect(
CONF_MIN_OPENING_DEGREES
) from exc
def check_config_complete(self, infos) -> bool:
"""True if the config is now complete (ie all mandatory attributes are set)"""
is_central_config = (
@@ -414,8 +399,6 @@ class VersatileThermostatBaseConfigFlow(FlowHandler):
errors["base"] = "configuration_not_complete"
except ValveRegulationNbEntitiesIncorrect as err:
errors["base"] = "valve_regulation_nb_entities_incorrect"
except ValveRegulationMinOpeningDegreesIncorrect as err:
errors[str(err)] = "min_opening_degrees_format"
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unexpected exception")
errors["base"] = "unknown"

View File

@@ -219,7 +219,6 @@ STEP_VALVE_REGULATION = vol.Schema( # pylint: disable=invalid-name
PROPORTIONAL_FUNCTION_TPI,
]
),
vol.Optional(CONF_MIN_OPENING_DEGREES, default=""): str,
}
)

View File

@@ -123,7 +123,6 @@ CONF_STEP_TEMPERATURE = "step_temperature"
CONF_OFFSET_CALIBRATION_LIST = "offset_calibration_entity_ids"
CONF_OPENING_DEGREE_LIST = "opening_degree_entity_ids"
CONF_CLOSING_DEGREE_LIST = "closing_degree_entity_ids"
CONF_MIN_OPENING_DEGREES = "min_opening_degrees"
# Deprecated
CONF_HEATER = "heater_entity_id"
@@ -553,10 +552,6 @@ class ValveRegulationNbEntitiesIncorrect(HomeAssistantError):
The number of specific entities is incorrect."""
class ValveRegulationMinOpeningDegreesIncorrect(HomeAssistantError):
"""Error to indicate that the minimal opening degrees is not a list of int separated by coma"""
class overrides: # pylint: disable=invalid-name
"""An annotation to inform overrides"""

View File

@@ -224,15 +224,13 @@
"offset_calibration_entity_ids": "Offset calibration entities",
"opening_degree_entity_ids": "Opening degree entities",
"closing_degree_entity_ids": "Closing degree entities",
"proportional_function": "Algorithm",
"min_opening_degrees": "Min opening degrees"
"proportional_function": "Algorithm"
},
"data_description": {
"offset_calibration_entity_ids": "The list of the 'offset calibration' entities. Set it if your TRV have the entity for better regulation. There should be one per underlying climate entities",
"opening_degree_entity_ids": "The list of the 'opening degree' entities. There should be one per underlying climate entities",
"closing_degree_entity_ids": "The list of the 'closing degree' entities. Set it if your TRV have the entity for better regulation. There should be one per underlying climate entities",
"proportional_function": "Algorithm to use (TPI is the only one for now)",
"min_opening_degrees": "A comma seperated list of minimal opening degrees. Default to 0. Example: 20, 25, 30"
"proportional_function": "Algorithm to use (TPI is the only one for now)"
}
}
},
@@ -470,15 +468,13 @@
"offset_calibration_entity_ids": "Offset calibration entities",
"opening_degree_entity_ids": "Opening degree entities",
"closing_degree_entity_ids": "Closing degree entities",
"proportional_function": "Algorithm",
"min_opening_degrees": "Min opening degrees"
"proportional_function": "Algorithm"
},
"data_description": {
"offset_calibration_entity_ids": "The list of the 'offset calibration' entities. Set it if your TRV have the entity for better regulation. There should be one per underlying climate entities",
"opening_degree_entity_ids": "The list of the 'opening degree' entities. There should be one per underlying climate entities",
"closing_degree_entity_ids": "The list of the 'closing degree' entities. Set it if your TRV have the entity for better regulation. There should be one per underlying climate entities",
"proportional_function": "Algorithm to use (TPI is the only one for now)",
"min_opening_degrees": "A comma seperated list of minimal opening degrees. Default to 0. Example: 20, 25, 30"
"proportional_function": "Algorithm to use (TPI is the only one for now)"
}
}
},
@@ -488,8 +484,7 @@
"window_open_detection_method": "Only one window open detection method should be used. Use either window sensor or automatic detection through temperature threshold but not both",
"no_central_config": "You cannot check 'use central configuration' because no central configuration was found. You need to create a Versatile Thermostat of type 'Central Configuration' to use it.",
"service_configuration_format": "The format of the service configuration is wrong",
"valve_regulation_nb_entities_incorrect": "The number of valve entities for valve regulation should be equal to the number of underlyings",
"min_opening_degrees_format": "A comma separated list of positive integer is expected. Example: 20, 25, 30"
"valve_regulation_nb_entities_incorrect": "The number of valve entities for valve regulation should be equal to the number of underlyings"
},
"abort": {
"already_configured": "Device is already configured"

View File

@@ -37,7 +37,6 @@ class ThermostatOverClimateValve(ThermostatOverClimate):
"tpi_coef_int",
"tpi_coef_ext",
"power_percent",
"min_opening_degrees",
}
)
)
@@ -52,7 +51,6 @@ class ThermostatOverClimateValve(ThermostatOverClimate):
self._last_calculation_timestamp: datetime | None = None
self._auto_regulation_dpercent: float | None = None
self._auto_regulation_period_min: int | None = None
self._min_opening_degress: list[int] = []
super().__init__(hass, unique_id, name, entry_infos)
@@ -88,14 +86,6 @@ class ThermostatOverClimateValve(ThermostatOverClimate):
offset_list = config_entry.get(CONF_OFFSET_CALIBRATION_LIST, [])
opening_list = config_entry.get(CONF_OPENING_DEGREE_LIST)
closing_list = config_entry.get(CONF_CLOSING_DEGREE_LIST, [])
self._min_opening_degrees = config_entry.get(CONF_MIN_OPENING_DEGREES, None)
min_opening_degrees_list = []
if self._min_opening_degrees:
min_opening_degrees_list = [
int(x.strip()) for x in self._min_opening_degrees.split(",")
]
for idx, _ in enumerate(config_entry.get(CONF_UNDERLYING_LIST)):
offset = offset_list[idx] if idx < len(offset_list) else None
# number of opening should equal number of underlying
@@ -108,11 +98,6 @@ class ThermostatOverClimateValve(ThermostatOverClimate):
opening_degree_entity_id=opening,
closing_degree_entity_id=closing,
climate_underlying=self._underlyings[idx],
min_opening_degree=(
min_opening_degrees_list[idx]
if idx < len(min_opening_degrees_list)
else 0
),
)
self._underlyings_valve_regulation.append(under)
@@ -145,10 +130,6 @@ class ThermostatOverClimateValve(ThermostatOverClimate):
self._attr_extra_state_attributes["tpi_coef_int"] = self._tpi_coef_int
self._attr_extra_state_attributes["tpi_coef_ext"] = self._tpi_coef_ext
self._attr_extra_state_attributes["min_opening_degrees"] = (
self._min_opening_degrees
)
self._attr_extra_state_attributes["valve_open_percent"] = (
self.valve_open_percent
)

View File

@@ -224,15 +224,13 @@
"offset_calibration_entity_ids": "Offset calibration entities",
"opening_degree_entity_ids": "Opening degree entities",
"closing_degree_entity_ids": "Closing degree entities",
"proportional_function": "Algorithm",
"min_opening_degrees": "Min opening degrees"
"proportional_function": "Algorithm"
},
"data_description": {
"offset_calibration_entity_ids": "The list of the 'offset calibration' entities. Set it if your TRV have the entity for better regulation. There should be one per underlying climate entities",
"opening_degree_entity_ids": "The list of the 'opening degree' entities. There should be one per underlying climate entities",
"closing_degree_entity_ids": "The list of the 'closing degree' entities. Set it if your TRV have the entity for better regulation. There should be one per underlying climate entities",
"proportional_function": "Algorithm to use (TPI is the only one for now)",
"min_opening_degrees": "A comma seperated list of minimal opening degrees. Default to 0. Example: 20, 25, 30"
"proportional_function": "Algorithm to use (TPI is the only one for now)"
}
}
},
@@ -470,15 +468,13 @@
"offset_calibration_entity_ids": "Offset calibration entities",
"opening_degree_entity_ids": "Opening degree entities",
"closing_degree_entity_ids": "Closing degree entities",
"proportional_function": "Algorithm",
"min_opening_degrees": "Min opening degrees"
"proportional_function": "Algorithm"
},
"data_description": {
"offset_calibration_entity_ids": "The list of the 'offset calibration' entities. Set it if your TRV have the entity for better regulation. There should be one per underlying climate entities",
"opening_degree_entity_ids": "The list of the 'opening degree' entities. There should be one per underlying climate entities",
"closing_degree_entity_ids": "The list of the 'closing degree' entities. Set it if your TRV have the entity for better regulation. There should be one per underlying climate entities",
"proportional_function": "Algorithm to use (TPI is the only one for now)",
"min_opening_degrees": "A comma seperated list of minimal opening degrees. Default to 0. Example: 20, 25, 30"
"proportional_function": "Algorithm to use (TPI is the only one for now)"
}
}
},

View File

@@ -224,15 +224,13 @@
"offset_calibration_entity_ids": "Entités de 'calibrage du décalage''",
"opening_degree_entity_ids": "Entités 'ouverture de vanne'",
"closing_degree_entity_ids": "Entités 'fermeture de la vanne'",
"proportional_function": "Algorithme",
"min_opening_degrees": "Ouvertures minimales"
"proportional_function": "Algorithme"
},
"data_description": {
"offset_calibration_entity_ids": "La liste des entités 'calibrage du décalage' (offset calibration). Configurez le si votre TRV possède cette fonction pour une meilleure régulation. Il doit y en avoir une par entité climate sous-jacente",
"opening_degree_entity_ids": "La liste des entités 'ouverture de vanne'. Il doit y en avoir une par entité climate sous-jacente",
"closing_degree_entity_ids": "La liste des entités 'fermeture de la vanne'. Configurez le si votre TRV possède cette fonction pour une meilleure régulation. Il doit y en avoir une par entité climate sous-jacente",
"proportional_function": "Algorithme à utiliser (seulement TPI est disponible)",
"min_opening_degrees": "Une liste séparée par des virgules de minimum d'ouverture. Valeur par défaut : 0. Exemple : 20, 25, 30"
"proportional_function": "Algorithme à utiliser (seulement TPI est disponible)"
}
}
},
@@ -464,15 +462,13 @@
"offset_calibration_entity_ids": "Entités de 'calibrage du décalage''",
"opening_degree_entity_ids": "Entités 'ouverture de vanne'",
"closing_degree_entity_ids": "Entités 'fermeture de la vanne'",
"proportional_function": "Algorithme",
"min_opening_degrees": "Ouvertures minimales"
"proportional_function": "Algorithme"
},
"data_description": {
"offset_calibration_entity_ids": "La liste des entités 'calibrage du décalage' (offset calibration). Configurez le si votre TRV possède cette fonction pour une meilleure régulation. Il doit y en avoir une par entité climate sous-jacente",
"opening_degree_entity_ids": "La liste des entités 'ouverture de vanne'. Il doit y en avoir une par entité climate sous-jacente",
"closing_degree_entity_ids": "La liste des entités 'fermeture de la vanne'. Configurez le si votre TRV possède cette fonction pour une meilleure régulation. Il doit y en avoir une par entité climate sous-jacente",
"proportional_function": "Algorithme à utiliser (seulement TPI est disponible)",
"min_opening_degrees": "Une liste séparée par des virgules de minimum d'ouverture. Valeur par défaut : 0. Exemple : 20, 25, 30"
"proportional_function": "Algorithme à utiliser (seulement TPI est disponible)"
}
}
},
@@ -482,8 +478,7 @@
"window_open_detection_method": "Une seule méthode de détection des ouvertures ouvertes doit être utilisée. Utilisez le détecteur d'ouverture ou les seuils de température mais pas les deux.",
"no_central_config": "Vous ne pouvez pas cocher 'Utiliser la configuration centrale' car aucune configuration centrale n'a été trouvée. Vous devez créer un Versatile Thermostat de type 'Central Configuration' pour pouvoir l'utiliser.",
"service_configuration_format": "Mauvais format de la configuration du service",
"valve_regulation_nb_entities_incorrect": "Le nombre d'entités pour la régulation par vanne doit être égal au nombre d'entité sous-jacentes",
"min_opening_degrees_format": "Une liste d'entiers positifs séparés par des ',' est attendu. Exemple : 20, 25, 30"
"valve_regulation_nb_entities_incorrect": "Le nombre d'entités pour la régulation par vanne doit être égal au nombre d'entité sous-jacentes"
},
"abort": {
"already_configured": "Le device est déjà configuré"

View File

@@ -1029,7 +1029,6 @@ class UnderlyingValveRegulation(UnderlyingValve):
opening_degree_entity_id: str,
closing_degree_entity_id: str,
climate_underlying: UnderlyingClimate,
min_opening_degree: int = 0,
) -> None:
"""Initialize the underlying TRV with valve regulation"""
super().__init__(
@@ -1046,7 +1045,6 @@ class UnderlyingValveRegulation(UnderlyingValve):
self._max_opening_degree: float = None
self._min_offset_calibration: float = None
self._max_offset_calibration: float = None
self._min_opening_degree: int = min_opening_degree
async def send_percent_open(self):
"""Send the percent open to the underlying valve"""
@@ -1081,9 +1079,6 @@ class UnderlyingValveRegulation(UnderlyingValve):
return
# Send opening_degree
if 0 < self._percent_open < self._min_opening_degree:
self._percent_open = self._min_opening_degree
await super().send_percent_open()
# Send closing_degree if set
@@ -1143,11 +1138,6 @@ class UnderlyingValveRegulation(UnderlyingValve):
"""The offset_calibration_entity_id"""
return self._closing_degree_entity_id
@property
def min_opening_degree(self) -> int:
"""The minimum opening degree"""
return self._min_opening_degree
@property
def have_closing_degree_entity(self) -> bool:
"""Return True if the underlying have a closing_degree entity"""

View File

@@ -1581,7 +1581,6 @@ async def test_user_config_flow_over_climate_valve(
CONF_OFFSET_CALIBRATION_LIST: ["number.offset_calibration1"],
CONF_OPENING_DEGREE_LIST: ["number.opening_degree1"],
CONF_CLOSING_DEGREE_LIST: ["number.closing_degree1"],
CONF_MIN_OPENING_DEGREES: "10, 20,0",
},
)
assert result["type"] == FlowResultType.FORM
@@ -1620,7 +1619,6 @@ async def test_user_config_flow_over_climate_valve(
"number.opening_degree2",
],
CONF_CLOSING_DEGREE_LIST: [],
CONF_MIN_OPENING_DEGREES: "10, 20,0",
},
)
assert result["type"] == FlowResultType.MENU
@@ -1717,7 +1715,6 @@ async def test_user_config_flow_over_climate_valve(
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
CONF_TPI_COEF_INT: 0.3,
CONF_TPI_COEF_EXT: 0.1,
CONF_MIN_OPENING_DEGREES: "10, 20,0",
}
assert result["result"]
assert result["result"].domain == DOMAIN

View File

@@ -483,186 +483,3 @@ async def test_over_climate_valve_multi_presence(
)
assert vtherm.nb_device_actives == 0
@pytest.mark.parametrize("expected_lingering_timers", [True])
async def test_over_climate_valve_multi_min_opening_degrees(
hass: HomeAssistant, skip_hass_states_get
):
"""Test the normal full start of a thermostat in thermostat_over_climate type
with valve_regulation and min_opening_degreess set"""
entry = MockConfigEntry(
domain=DOMAIN,
title="TheOverClimateMockName",
unique_id="uniqueId",
data={
CONF_NAME: "TheOverClimateMockName",
CONF_TEMP_SENSOR: "sensor.mock_temp_sensor",
CONF_CYCLE_MIN: 5,
CONF_DEVICE_POWER: 1,
CONF_USE_MAIN_CENTRAL_CONFIG: False,
CONF_USE_CENTRAL_MODE: False,
CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_CLIMATE,
CONF_EXTERNAL_TEMP_SENSOR: "sensor.mock_ext_temp_sensor",
CONF_TEMP_MIN: 15,
CONF_TEMP_MAX: 30,
CONF_STEP_TEMPERATURE: 0.1,
CONF_UNDERLYING_LIST: ["climate.mock_climate1", "climate.mock_climate2"],
CONF_AC_MODE: False,
CONF_AUTO_REGULATION_MODE: CONF_AUTO_REGULATION_VALVE,
CONF_AUTO_REGULATION_DTEMP: 0.01,
CONF_AUTO_REGULATION_PERIOD_MIN: 0,
CONF_AUTO_FAN_MODE: CONF_AUTO_FAN_HIGH,
CONF_AUTO_REGULATION_USE_DEVICE_TEMP: False,
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
CONF_TPI_COEF_INT: 0.3,
CONF_TPI_COEF_EXT: 0.1,
CONF_OPENING_DEGREE_LIST: [
"number.mock_opening_degree1",
"number.mock_opening_degree2",
],
CONF_CLOSING_DEGREE_LIST: [
"number.mock_closing_degree1",
"number.mock_closing_degree2",
],
CONF_OFFSET_CALIBRATION_LIST: [
"number.mock_offset_calibration1",
"number.mock_offset_calibration2",
],
CONF_USE_PRESENCE_FEATURE: False,
CONF_USE_WINDOW_FEATURE: False,
CONF_USE_MOTION_FEATURE: False,
CONF_USE_POWER_FEATURE: False,
CONF_MIN_OPENING_DEGREES: "60,70",
}
| MOCK_DEFAULT_CENTRAL_CONFIG
| MOCK_ADVANCED_CONFIG,
)
fake_underlying_climate1 = MockClimate(
hass, "mockUniqueId1", "MockClimateName1", {}
)
fake_underlying_climate2 = MockClimate(
hass, "mockUniqueId2", "MockClimateName2", {}
)
# mock_get_state will be called for each OPENING/CLOSING/OFFSET_CALIBRATION list
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}
),
# 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}
),
},
State("unknown.entity_id", "unknown"),
)
# 1. initialize the VTherm
tz = get_tz(hass) # pylint: disable=invalid-name
now: datetime = datetime.now(tz=tz)
# fmt: off
with patch("custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event") as mock_send_event, \
patch("custom_components.versatile_thermostat.underlyings.UnderlyingClimate.find_underlying_climate", side_effect=[fake_underlying_climate1, fake_underlying_climate2]) as mock_find_climate, \
patch("homeassistant.core.ServiceRegistry.async_call") as mock_service_call,\
patch("homeassistant.core.StateMachine.get", side_effect=mock_get_state_side_effect.get_side_effects()) as mock_get_state:
# fmt: on
vtherm: ThermostatOverClimateValve = await create_thermostat(hass, entry, "climate.theoverclimatemockname")
assert vtherm
assert isinstance(vtherm, ThermostatOverClimateValve)
assert vtherm.name == "TheOverClimateMockName"
assert vtherm.is_over_climate is True
assert vtherm.have_valve_regulation is True
vtherm._set_now(now)
# initialize the temps
await set_all_climate_preset_temp(hass, vtherm, default_temperatures, "theoverclimatemockname")
await send_temperature_change_event(vtherm, 20, now, True)
await send_ext_temperature_change_event(vtherm, 20, now, True)
await send_presence_change_event(vtherm, False, True, now)
await vtherm.async_set_preset_mode(PRESET_COMFORT)
await vtherm.async_set_hvac_mode(HVACMode.HEAT)
assert vtherm.target_temperature == 19
assert vtherm.nb_device_actives == 0
# 2: set temperature -> should activate the valve and change target
# fmt: off
with patch("custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event") as mock_send_event, \
patch("homeassistant.core.ServiceRegistry.async_call") as mock_service_call,\
patch("homeassistant.core.StateMachine.get", side_effect=mock_get_state_side_effect.get_side_effects()) as mock_get_state:
# fmt: on
now = now + timedelta(minutes=3)
vtherm._set_now(now)
await send_temperature_change_event(vtherm, 18, now, True)
await hass.async_block_till_done()
assert vtherm.is_device_active is True
assert vtherm.valve_open_percent == 20
# the underlying set temperature call and the call to the valve
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': 60}, target={'entity_id': 'number.mock_opening_degree1'}),
call(domain='number', service='set_value', service_data={'value': 40}, 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': 70}, target={'entity_id': 'number.mock_opening_degree2'}),
call(domain='number', service='set_value', service_data={'value': 30}, target={'entity_id': 'number.mock_closing_degree2'}),
call(domain='number', service='set_value', service_data={'value': 12}, target={'entity_id': 'number.mock_offset_calibration2'})
]
)
assert vtherm.nb_device_actives >= 2 # should be 2 but when run in // with the first test it give 3
# 3: set high temperature -> should deactivate the valve and change target
# fmt: off
with patch("custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event") as mock_send_event, \
patch("homeassistant.core.ServiceRegistry.async_call") as mock_service_call,\
patch("homeassistant.core.StateMachine.get", side_effect=mock_get_state_side_effect.get_side_effects()) as mock_get_state:
# fmt: on
now = now + timedelta(minutes=3)
vtherm._set_now(now)
await send_temperature_change_event(vtherm, 22, now, True)
await hass.async_block_till_done()
assert vtherm.is_device_active is False
assert vtherm.valve_open_percent == 0
# the underlying set temperature call and the call to the valve
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': 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': 12}, target={'entity_id': 'number.mock_offset_calibration2'})
]
)
assert vtherm.nb_device_actives == 0