diff --git a/custom_components/versatile_thermostat/strings.json b/custom_components/versatile_thermostat/strings.json index 3f200c1..b45e7ea 100644 --- a/custom_components/versatile_thermostat/strings.json +++ b/custom_components/versatile_thermostat/strings.json @@ -348,6 +348,7 @@ }, "auto_regulation_mode": { "options": { + "auto_regulation_slow": "Slow", "auto_regulation_strong": "Strong", "auto_regulation_medium": "Medium", "auto_regulation_light": "Light", diff --git a/custom_components/versatile_thermostat/translations/en.json b/custom_components/versatile_thermostat/translations/en.json index 3f200c1..b45e7ea 100644 --- a/custom_components/versatile_thermostat/translations/en.json +++ b/custom_components/versatile_thermostat/translations/en.json @@ -348,6 +348,7 @@ }, "auto_regulation_mode": { "options": { + "auto_regulation_slow": "Slow", "auto_regulation_strong": "Strong", "auto_regulation_medium": "Medium", "auto_regulation_light": "Light", diff --git a/custom_components/versatile_thermostat/translations/fr.json b/custom_components/versatile_thermostat/translations/fr.json index 6b3dfc7..fbc0845 100644 --- a/custom_components/versatile_thermostat/translations/fr.json +++ b/custom_components/versatile_thermostat/translations/fr.json @@ -349,6 +349,7 @@ }, "auto_regulation_mode": { "options": { + "auto_regulation_slow": "Lente", "auto_regulation_strong": "Forte", "auto_regulation_medium": "Moyenne", "auto_regulation_light": "Légère", diff --git a/custom_components/versatile_thermostat/translations/it.json b/custom_components/versatile_thermostat/translations/it.json index 9646d40..4b8b983 100644 --- a/custom_components/versatile_thermostat/translations/it.json +++ b/custom_components/versatile_thermostat/translations/it.json @@ -326,6 +326,7 @@ }, "auto_regulation_mode": { "options": { + "auto_regulation_slow": "Lento", "auto_regulation_strong": "Forte", "auto_regulation_medium": "Media", "auto_regulation_light": "Leggera", @@ -348,4 +349,4 @@ } } } -} +} \ No newline at end of file diff --git a/custom_components/versatile_thermostat/translations/sk.json b/custom_components/versatile_thermostat/translations/sk.json index cbfbf5e..716b8d9 100644 --- a/custom_components/versatile_thermostat/translations/sk.json +++ b/custom_components/versatile_thermostat/translations/sk.json @@ -348,6 +348,7 @@ }, "auto_regulation_mode": { "options": { + "auto_regulation_slow": "Slow", "auto_regulation_strong": "Strong", "auto_regulation_medium": "Medium", "auto_regulation_light": "Light", diff --git a/tests/test_multiple_switch.py b/tests/test_multiple_switch.py index b1f37bc..97f0f67 100644 --- a/tests/test_multiple_switch.py +++ b/tests/test_multiple_switch.py @@ -163,7 +163,9 @@ async def test_one_switch_cycle( # assert entity.underlying_entity(0)._should_relaunch_control_heating is True # Simulate the relaunch - await entity.underlying_entity(0)._turn_on_later( # pylint: disable=protected-access + await entity.underlying_entity( + 0 + )._turn_on_later( # pylint: disable=protected-access None ) # wait restart @@ -184,7 +186,9 @@ async def test_one_switch_cycle( "custom_components.versatile_thermostat.underlyings.UnderlyingSwitch.is_device_active", return_value=True, ) as mock_device_active: - await entity.underlying_entity(0)._turn_off_later( # pylint: disable=protected-access + await entity.underlying_entity( + 0 + )._turn_off_later( # pylint: disable=protected-access None ) @@ -207,7 +211,9 @@ async def test_one_switch_cycle( "custom_components.versatile_thermostat.underlyings.UnderlyingSwitch.is_device_active", return_value=True, ) as mock_device_active: - await entity.underlying_entity(0)._turn_on_later( # pylint: disable=protected-access + await entity.underlying_entity( + 0 + )._turn_on_later( # pylint: disable=protected-access None ) @@ -591,3 +597,139 @@ async def test_multiple_climates_underlying_changes( assert entity.hvac_mode == HVACMode.HEAT assert entity.hvac_action == HVACAction.IDLE 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_switch_power_management( + hass: HomeAssistant, skip_hass_states_is_state +): + """Test the Power management""" + + entry = MockConfigEntry( + domain=DOMAIN, + title="TheOverSwitchMockName", + unique_id="uniqueId", + data={ + CONF_NAME: "TheOver4SwitchMockName", + CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_SWITCH, + 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: True, + CONF_USE_PRESENCE_FEATURE: False, + CONF_HEATER: "switch.mock_switch1", + CONF_HEATER_2: "switch.mock_switch2", + CONF_HEATER_3: "switch.mock_switch3", + CONF_HEATER_4: "switch.mock_switch4", + CONF_MINIMAL_ACTIVATION_DELAY: 30, + CONF_SECURITY_DELAY_MIN: 5, + CONF_SECURITY_MIN_ON_PERCENT: 0.3, + CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI, + CONF_TPI_COEF_INT: 0.3, + CONF_TPI_COEF_EXT: 0.01, + CONF_POWER_SENSOR: "sensor.mock_power_sensor", + CONF_MAX_POWER_SENSOR: "sensor.mock_power_max_sensor", + CONF_DEVICE_POWER: 100, + CONF_PRESET_POWER: 12, + }, + ) + + entity: BaseThermostat = await create_thermostat( + hass, entry, "climate.theover4switchmockname" + ) + assert entity + assert entity.is_over_climate is False + assert entity.nb_underlying_entities == 4 + + tpi_algo = entity._prop_algorithm + assert tpi_algo + + 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.overpowering_state is None + assert entity.target_temperature == 19 + + # 1. Send power mesurement + await send_power_change_event(entity, 50, datetime.now()) + # Send power max mesurement + await send_max_power_change_event(entity, 300, datetime.now()) + assert await entity.check_overpowering() is False + # All configuration is complete and power is < power_max + assert entity.preset_mode is PRESET_BOOST + assert entity.overpowering_state is False + + # 2. Send power max mesurement too low and HVACMode is on + with patch( + "custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event" + ) as mock_send_event, patch( + "custom_components.versatile_thermostat.underlyings.UnderlyingSwitch.turn_on" + ) as mock_heater_on, patch( + "custom_components.versatile_thermostat.underlyings.UnderlyingSwitch.turn_off" + ) as mock_heater_off: + # 100 of the device / 4 -> 25, current power 50 so max is 75 + await send_max_power_change_event(entity, 74, datetime.now()) + assert await entity.check_overpowering() is True + # All configuration is complete and power is > power_max we switch to POWER preset + assert entity.preset_mode is PRESET_POWER + assert entity.overpowering_state is True + assert entity.target_temperature == 12 + + assert mock_send_event.call_count == 2 + mock_send_event.assert_has_calls( + [ + call.send_event(EventType.PRESET_EVENT, {"preset": PRESET_POWER}), + call.send_event( + EventType.POWER_EVENT, + { + "type": "start", + "current_power": 50, + "device_power": 100, + "current_power_max": 74, + "current_power_consumption": 25.0, + }, + ), + ], + any_order=True, + ) + assert mock_heater_on.call_count == 0 + assert mock_heater_off.call_count == 4 # The fourth are shutdown + + # 3. change PRESET + with patch( + "custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event" + ) as mock_send_event: + await entity.async_set_preset_mode(PRESET_ECO) + assert entity.preset_mode is PRESET_ECO + # No change + assert entity.overpowering_state is True + + # 4. Send hugh power max mesurement to release overpowering + with patch( + "custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event" + ) as mock_send_event, patch( + "custom_components.versatile_thermostat.underlyings.UnderlyingSwitch.turn_on" + ) as mock_heater_on, patch( + "custom_components.versatile_thermostat.underlyings.UnderlyingSwitch.turn_off" + ) as mock_heater_off: + # 100 of the device / 4 -> 25, current power 50 so max is 75. With 150 no overheating + await send_max_power_change_event(entity, 150, datetime.now()) + assert await entity.check_overpowering() is False + # All configuration is complete and power is > power_max we switch to POWER preset + assert entity.preset_mode is PRESET_ECO + assert entity.overpowering_state is False + assert entity.target_temperature == 17 + + assert ( + mock_heater_on.call_count == 0 + ) # The fourth are not restarted because temperature is enought + assert mock_heater_off.call_count == 0