From 2e2dca8593d7477dd2aa09d4963462a609c27b03 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sun, 21 Jun 2026 18:32:59 +0200 Subject: [PATCH 01/66] Link to updated backend library --- custom_components/plugwise/manifest.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/custom_components/plugwise/manifest.json b/custom_components/plugwise/manifest.json index 09f91d310..3c0b27bcc 100644 --- a/custom_components/plugwise/manifest.json +++ b/custom_components/plugwise/manifest.json @@ -7,7 +7,9 @@ "integration_type": "hub", "iot_class": "local_polling", "loggers": ["plugwise"], - "requirements": ["plugwise==1.12.0"], + "requirements": [ + "plugwise@git+https://github.com/plugwise/python-plugwise.git/@water_heater_2" + ], "version": "0.65.0", "zeroconf": ["_plugwise._tcp.local."] } From c7249177ae94d6aacc6273f3e447e528c0fba4f8 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sun, 21 Jun 2026 18:37:19 +0200 Subject: [PATCH 02/66] Refresh test-fixtures --- .../fixtures/adam_plus_anna_new/data.json | 16 +++++++------- .../fixtures/anna_heatpump_heating/data.json | 22 +++++++++---------- .../plugwise/fixtures/anna_v4/data.json | 21 +++++++++--------- .../plugwise/fixtures/anna_v4_dhw/data.json | 21 +++++++++--------- .../fixtures/m_adam_cooling/data.json | 16 +++++++------- .../fixtures/m_adam_heating/data.json | 21 +++++++++--------- .../m_adam_heating_off_schedule/data.json | 21 +++++++++--------- .../plugwise/fixtures/m_adam_jip/data.json | 21 +++++++++--------- .../m_anna_heatpump_cooling/data.json | 22 +++++++++---------- 9 files changed, 93 insertions(+), 88 deletions(-) diff --git a/tests/components/plugwise/fixtures/adam_plus_anna_new/data.json b/tests/components/plugwise/fixtures/adam_plus_anna_new/data.json index 56c7ffbb0..5a199f12a 100644 --- a/tests/components/plugwise/fixtures/adam_plus_anna_new/data.json +++ b/tests/components/plugwise/fixtures/adam_plus_anna_new/data.json @@ -6,24 +6,24 @@ "flame_state": true, "heating_state": true }, + "boiler_temperature": { + "current": 43.0, + "lower_bound": 25.0, + "resolution": 0.01, + "setpoint": 50.0, + "upper_bound": 95.0 + }, "dev_class": "heater_central", "dhw_modes": [ "comfort", "off" ], "location": "bc93488efab249e5bc54fd7e175a6f91", - "maximum_boiler_temperature": { - "lower_bound": 25.0, - "resolution": 0.01, - "setpoint": 50.0, - "upper_bound": 95.0 - }, "model": "Generic heater", "name": "OpenTherm", "select_dhw_mode": "off", "sensors": { - "intended_boiler_temperature": 22.5, - "water_temperature": 43.0 + "intended_boiler_temperature": 22.5 } }, "10016900610d4c7481df78c89606ef22": { diff --git a/tests/components/plugwise/fixtures/anna_heatpump_heating/data.json b/tests/components/plugwise/fixtures/anna_heatpump_heating/data.json index 54a045273..69ea20098 100644 --- a/tests/components/plugwise/fixtures/anna_heatpump_heating/data.json +++ b/tests/components/plugwise/fixtures/anna_heatpump_heating/data.json @@ -28,35 +28,35 @@ "heating_state": true, "secondary_boiler_state": false }, + "boiler_temperature": { + "current": 29.1, + "lower_bound": 0.0, + "resolution": 1.0, + "setpoint": 60.0, + "upper_bound": 100.0 + }, "dev_class": "heater_central", "dhw_mode": "off", "dhw_modes": [ "comfort", "off" ], - "location": "a57efe5f145f498c9be62a9b63626fbf", - "max_dhw_temperature": { + "dhw_temperature": { + "current": 46.3, "lower_bound": 35.0, "resolution": 0.01, "setpoint": 53.0, "upper_bound": 60.0 }, - "maximum_boiler_temperature": { - "lower_bound": 0.0, - "resolution": 1.0, - "setpoint": 60.0, - "upper_bound": 100.0 - }, + "location": "a57efe5f145f498c9be62a9b63626fbf", "model": "Generic heater/cooler", "name": "OpenTherm", "sensors": { - "dhw_temperature": 46.3, "intended_boiler_temperature": 35.0, "modulation_level": 52, "outdoor_air_temperature": 3.0, "return_temperature": 25.1, - "water_pressure": 1.57, - "water_temperature": 29.1 + "water_pressure": 1.57 }, "vendor": "Techneco" }, diff --git a/tests/components/plugwise/fixtures/anna_v4/data.json b/tests/components/plugwise/fixtures/anna_v4/data.json index 563560b49..fbf163590 100644 --- a/tests/components/plugwise/fixtures/anna_v4/data.json +++ b/tests/components/plugwise/fixtures/anna_v4/data.json @@ -66,25 +66,27 @@ "flame_state": false, "heating_state": true }, + "boiler_temperature": { + "current": 45.0, + "lower_bound": 0.0, + "resolution": 1.0, + "setpoint": 70.0, + "upper_bound": 100.0 + }, "dev_class": "heater_central", "dhw_mode": "off", "dhw_modes": [ "comfort", "off" ], - "location": "94c107dc6ac84ed98e9f68c0dd06bf71", - "max_dhw_temperature": { + "dhw_temperature": { + "current": 45.0, "lower_bound": 30.0, "resolution": 0.01, "setpoint": 60.0, "upper_bound": 60.0 }, - "maximum_boiler_temperature": { - "lower_bound": 0.0, - "resolution": 1.0, - "setpoint": 70.0, - "upper_bound": 100.0 - }, + "location": "94c107dc6ac84ed98e9f68c0dd06bf71", "model": "Generic heater", "model_id": "2.32", "name": "OpenTherm", @@ -92,8 +94,7 @@ "intended_boiler_temperature": 39.9, "modulation_level": 0.0, "return_temperature": 32.0, - "water_pressure": 2.2, - "water_temperature": 45.0 + "water_pressure": 2.2 }, "vendor": "Bosch Thermotechniek B.V." } diff --git a/tests/components/plugwise/fixtures/anna_v4_dhw/data.json b/tests/components/plugwise/fixtures/anna_v4_dhw/data.json index 9c1f13360..6ec073250 100644 --- a/tests/components/plugwise/fixtures/anna_v4_dhw/data.json +++ b/tests/components/plugwise/fixtures/anna_v4_dhw/data.json @@ -66,25 +66,27 @@ "flame_state": true, "heating_state": false }, + "boiler_temperature": { + "current": 45.0, + "lower_bound": 0.0, + "resolution": 1.0, + "setpoint": 70.0, + "upper_bound": 100.0 + }, "dev_class": "heater_central", "dhw_mode": "off", "dhw_modes": [ "comfort", "off" ], - "location": "94c107dc6ac84ed98e9f68c0dd06bf71", - "max_dhw_temperature": { + "dhw_temperature": { + "current": 45.0, "lower_bound": 30.0, "resolution": 0.01, "setpoint": 60.0, "upper_bound": 60.0 }, - "maximum_boiler_temperature": { - "lower_bound": 0.0, - "resolution": 1.0, - "setpoint": 70.0, - "upper_bound": 100.0 - }, + "location": "94c107dc6ac84ed98e9f68c0dd06bf71", "model": "Generic heater", "model_id": "2.32", "name": "OpenTherm", @@ -92,8 +94,7 @@ "intended_boiler_temperature": 39.9, "modulation_level": 0.0, "return_temperature": 32.0, - "water_pressure": 2.2, - "water_temperature": 45.0 + "water_pressure": 2.2 }, "vendor": "Bosch Thermotechniek B.V." } diff --git a/tests/components/plugwise/fixtures/m_adam_cooling/data.json b/tests/components/plugwise/fixtures/m_adam_cooling/data.json index c5b321660..c388b60a6 100644 --- a/tests/components/plugwise/fixtures/m_adam_cooling/data.json +++ b/tests/components/plugwise/fixtures/m_adam_cooling/data.json @@ -7,24 +7,24 @@ "flame_state": false, "heating_state": false }, + "boiler_temperature": { + "current": 19.0, + "lower_bound": 25.0, + "resolution": 0.01, + "setpoint": 50.0, + "upper_bound": 95.0 + }, "dev_class": "heater_central", "dhw_modes": [ "comfort", "off" ], "location": "bc93488efab249e5bc54fd7e175a6f91", - "maximum_boiler_temperature": { - "lower_bound": 25.0, - "resolution": 0.01, - "setpoint": 50.0, - "upper_bound": 95.0 - }, "model": "Generic heater", "name": "OpenTherm", "select_dhw_mode": "off", "sensors": { - "intended_boiler_temperature": 17.5, - "water_temperature": 19.0 + "intended_boiler_temperature": 17.5 } }, "14df5c4dc8cb4ba69f9d1ac0eaf7c5c6": { diff --git a/tests/components/plugwise/fixtures/m_adam_heating/data.json b/tests/components/plugwise/fixtures/m_adam_heating/data.json index f29aa84c7..a45d345d8 100644 --- a/tests/components/plugwise/fixtures/m_adam_heating/data.json +++ b/tests/components/plugwise/fixtures/m_adam_heating/data.json @@ -6,30 +6,31 @@ "flame_state": false, "heating_state": true }, + "boiler_temperature": { + "current": 37.0, + "lower_bound": 25.0, + "resolution": 0.01, + "setpoint": 50.0, + "upper_bound": 95.0 + }, "dev_class": "heater_central", "dhw_modes": [ "comfort", "off" ], - "location": "bc93488efab249e5bc54fd7e175a6f91", - "max_dhw_temperature": { + "dhw_temperature": { + "current": 37.0, "lower_bound": 40.0, "resolution": 0.01, "setpoint": 60.0, "upper_bound": 60.0 }, - "maximum_boiler_temperature": { - "lower_bound": 25.0, - "resolution": 0.01, - "setpoint": 50.0, - "upper_bound": 95.0 - }, + "location": "bc93488efab249e5bc54fd7e175a6f91", "model": "Generic heater", "name": "OpenTherm", "select_dhw_mode": "off", "sensors": { - "intended_boiler_temperature": 38.1, - "water_temperature": 37.0 + "intended_boiler_temperature": 38.1 } }, "14df5c4dc8cb4ba69f9d1ac0eaf7c5c6": { diff --git a/tests/components/plugwise/fixtures/m_adam_heating_off_schedule/data.json b/tests/components/plugwise/fixtures/m_adam_heating_off_schedule/data.json index aaabc1495..a3c7095c4 100644 --- a/tests/components/plugwise/fixtures/m_adam_heating_off_schedule/data.json +++ b/tests/components/plugwise/fixtures/m_adam_heating_off_schedule/data.json @@ -6,30 +6,31 @@ "flame_state": false, "heating_state": false }, + "boiler_temperature": { + "current": 37.0, + "lower_bound": 25.0, + "resolution": 0.01, + "setpoint": 50.0, + "upper_bound": 95.0 + }, "dev_class": "heater_central", "dhw_modes": [ "comfort", "off" ], - "location": "bc93488efab249e5bc54fd7e175a6f91", - "max_dhw_temperature": { + "dhw_temperature": { + "current": 37.0, "lower_bound": 40.0, "resolution": 0.01, "setpoint": 60.0, "upper_bound": 60.0 }, - "maximum_boiler_temperature": { - "lower_bound": 25.0, - "resolution": 0.01, - "setpoint": 50.0, - "upper_bound": 95.0 - }, + "location": "bc93488efab249e5bc54fd7e175a6f91", "model": "Generic heater", "name": "OpenTherm", "select_dhw_mode": "off", "sensors": { - "intended_boiler_temperature": 0.0, - "water_temperature": 37.0 + "intended_boiler_temperature": 0.0 } }, "14df5c4dc8cb4ba69f9d1ac0eaf7c5c6": { diff --git a/tests/components/plugwise/fixtures/m_adam_jip/data.json b/tests/components/plugwise/fixtures/m_adam_jip/data.json index ff33d77c2..fd2ccd4dc 100644 --- a/tests/components/plugwise/fixtures/m_adam_jip/data.json +++ b/tests/components/plugwise/fixtures/m_adam_jip/data.json @@ -392,25 +392,27 @@ "flame_state": false, "heating_state": false }, + "boiler_temperature": { + "current": 37.3, + "lower_bound": 20.0, + "resolution": 0.01, + "setpoint": 90.0, + "upper_bound": 90.0 + }, "dev_class": "heater_central", "dhw_mode": "off", "dhw_modes": [ "comfort", "off" ], - "location": "9e4433a9d69f40b3aefd15e74395eaec", - "max_dhw_temperature": { + "dhw_temperature": { + "current": 37.3, "lower_bound": 40.0, "resolution": 0.01, "setpoint": 60.0, "upper_bound": 60.0 }, - "maximum_boiler_temperature": { - "lower_bound": 20.0, - "resolution": 0.01, - "setpoint": 90.0, - "upper_bound": 90.0 - }, + "location": "9e4433a9d69f40b3aefd15e74395eaec", "model": "Generic heater", "model_id": "10.20", "name": "OpenTherm", @@ -418,8 +420,7 @@ "intended_boiler_temperature": 0.0, "modulation_level": 0.0, "return_temperature": 37.1, - "water_pressure": 1.4, - "water_temperature": 37.3 + "water_pressure": 1.4 }, "vendor": "Remeha B.V." }, diff --git a/tests/components/plugwise/fixtures/m_anna_heatpump_cooling/data.json b/tests/components/plugwise/fixtures/m_anna_heatpump_cooling/data.json index fb4085270..44729c758 100644 --- a/tests/components/plugwise/fixtures/m_anna_heatpump_cooling/data.json +++ b/tests/components/plugwise/fixtures/m_anna_heatpump_cooling/data.json @@ -28,35 +28,35 @@ "heating_state": false, "secondary_boiler_state": false }, + "boiler_temperature": { + "current": 22.7, + "lower_bound": 0.0, + "resolution": 1.0, + "setpoint": 60.0, + "upper_bound": 100.0 + }, "dev_class": "heater_central", "dhw_mode": "off", "dhw_modes": [ "comfort", "off" ], - "location": "a57efe5f145f498c9be62a9b63626fbf", - "max_dhw_temperature": { + "dhw_temperature": { + "current": 41.5, "lower_bound": 35.0, "resolution": 0.01, "setpoint": 53.0, "upper_bound": 60.0 }, - "maximum_boiler_temperature": { - "lower_bound": 0.0, - "resolution": 1.0, - "setpoint": 60.0, - "upper_bound": 100.0 - }, + "location": "a57efe5f145f498c9be62a9b63626fbf", "model": "Generic heater/cooler", "name": "OpenTherm", "sensors": { - "dhw_temperature": 41.5, "intended_boiler_temperature": 0.0, "modulation_level": 40, "outdoor_air_temperature": 28.0, "return_temperature": 23.8, - "water_pressure": 1.57, - "water_temperature": 22.7 + "water_pressure": 1.57 }, "vendor": "Techneco" }, From e74ed946cd0e5a641daa0c4f89a218618005dc70 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sun, 21 Jun 2026 18:43:54 +0200 Subject: [PATCH 03/66] Rework water_heater to support the updated backend library --- custom_components/plugwise/water_heater.py | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/custom_components/plugwise/water_heater.py b/custom_components/plugwise/water_heater.py index d7758a242..c37fecc13 100644 --- a/custom_components/plugwise/water_heater.py +++ b/custom_components/plugwise/water_heater.py @@ -50,7 +50,7 @@ def _add_entities() -> None: entities: list[PlugwiseWaterHeaterEntity] = [] for device_id in coordinator.new_devices: device = coordinator.data[device_id] - if device.get(MAX_DHW_TEMP) is not None: + if device.get(DHW_TEMP) is not None: entities.append(PlugwiseWaterHeaterEntity(coordinator, device_id)) LOGGER.debug("Add %s water_heater", device[ATTR_NAME]) async_add_entities(entities) @@ -76,10 +76,10 @@ def __init__( entity_name = f"{self.device[ATTR_NAME]}".lower() self._attr_unique_id = f"{device_id}-{entity_name}" - max_dhw_temp_bounds = self.device.get(MAX_DHW_TEMP, {}) - if max_dhw_temp_bounds: - self._attr_max_temp = max_dhw_temp_bounds.get(UPPER_BOUND, 75.0) - self._attr_min_temp = max_dhw_temp_bounds.get(LOWER_BOUND, 40.0) + self.dhw_temp = self.device.get(DHW_TEMP, {}) + if self.dhw_temp: + self._attr_max_temp = self.dhw_temp.get(UPPER_BOUND, 75.0) + self._attr_min_temp = self.dhw_temp.get(LOWER_BOUND, 40.0) self._attr_supported_features = WaterHeaterEntityFeature.OPERATION_MODE self._attr_supported_features |= WaterHeaterEntityFeature.TARGET_TEMPERATURE @@ -94,9 +94,7 @@ def current_operation(self) -> str | None: @override def current_temperature(self) -> float | None: """Return the current water temperature.""" - boiler_temperature = self.device.get(SENSORS, {}).get(WATER_TEMP) - dhw_temperature = self.device.get(SENSORS, {}).get(DHW_TEMP) - return dhw_temperature or boiler_temperature + return self.dhw_temp.get("current") @property @override @@ -110,10 +108,7 @@ def operation_list(self) -> list[str]: @override def target_temperature(self) -> float | None: """Return the water temperature we try to reach.""" - return ( - self.device.get(MAX_DHW_TEMP, {}).get(TARGET_TEMP) - or self.device.get(SENSORS, {}).get(DHW_SETPOINT) - ) + return self.dhw_temp.get("setpoint") @plugwise_command @override @@ -127,4 +122,4 @@ async def async_set_operation_mode(self, operation_mode: str) -> None: async def async_set_temperature(self, **kwargs: Any) -> None: """Set new target temperature.""" if (temperature := kwargs.get(ATTR_TEMPERATURE)) is not None: - await self.coordinator.api.set_number(self._dev_id, MAX_DHW_TEMP, float(temperature)) + await self.coordinator.api.set_number(self._dev_id, DHW_TEMP, float(temperature)) From b5610afe298065cc37c07ac437c83a604484f8e0 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sun, 21 Jun 2026 18:56:34 +0200 Subject: [PATCH 04/66] Update constants and deploy --- custom_components/plugwise/const.py | 7 +++---- custom_components/plugwise/number.py | 6 +++--- custom_components/plugwise/water_heater.py | 1 - 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/custom_components/plugwise/const.py b/custom_components/plugwise/const.py index 99f66b67b..4c568eb9f 100644 --- a/custom_components/plugwise/const.py +++ b/custom_components/plugwise/const.py @@ -77,8 +77,7 @@ VENDOR: Final = "vendor" # Number constants -MAX_BOILER_TEMP: Final = "maximum_boiler_temperature" -MAX_DHW_TEMP: Final = "max_dhw_temperature" +BOILER_TEMP: Final = "boiler_temperature" LOWER_BOUND: Final = "lower_bound" RESOLUTION: Final = "resolution" TEMPERATURE_OFFSET: Final = "temperature_offset" @@ -188,8 +187,8 @@ } type NumberType = Literal[ - "maximum_boiler_temperature", - "max_dhw_temperature", + "boiler_temperature", + "dhw_temperature", "temperature_offset", ] diff --git a/custom_components/plugwise/number.py b/custom_components/plugwise/number.py index 5f88a80a3..a42dd8b08 100644 --- a/custom_components/plugwise/number.py +++ b/custom_components/plugwise/number.py @@ -14,9 +14,9 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from .const import ( + BOILER_TEMP, LOGGER, LOWER_BOUND, - MAX_BOILER_TEMP, RESOLUTION, TEMPERATURE_OFFSET, UPPER_BOUND, @@ -41,8 +41,8 @@ class PlugwiseNumberEntityDescription(NumberEntityDescription): # Upstream + is there a reason we didn't rename this one prefixed? NUMBER_TYPES = ( PlugwiseNumberEntityDescription( - key=MAX_BOILER_TEMP, - translation_key=MAX_BOILER_TEMP, + key=BOILER_TEMP, + translation_key=BOILER_TEMP, device_class=NumberDeviceClass.TEMPERATURE, entity_category=EntityCategory.CONFIG, native_unit_of_measurement=UnitOfTemperature.CELSIUS, diff --git a/custom_components/plugwise/water_heater.py b/custom_components/plugwise/water_heater.py index c37fecc13..f72fc90e6 100644 --- a/custom_components/plugwise/water_heater.py +++ b/custom_components/plugwise/water_heater.py @@ -22,7 +22,6 @@ DHW_TEMP, LOGGER, LOWER_BOUND, - MAX_DHW_TEMP, SENSORS, TARGET_TEMP, UPPER_BOUND, From 66e48b88ab92d8a3839e5343c790d47c9042c96b Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sun, 21 Jun 2026 19:02:34 +0200 Subject: [PATCH 05/66] Updates --- custom_components/plugwise/number.py | 10 +++++----- tests/components/plugwise/test_number.py | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/custom_components/plugwise/number.py b/custom_components/plugwise/number.py index a42dd8b08..2ab24c736 100644 --- a/custom_components/plugwise/number.py +++ b/custom_components/plugwise/number.py @@ -116,11 +116,11 @@ def __init__( self.entity_description = description self._attr_unique_id = f"{device_id}-{description.key}" self._attr_mode = NumberMode.BOX - ctrl = self.device.get(description.key, {}) - self._attr_native_max_value = ctrl.get(UPPER_BOUND, 100.0) # Upstream const - self._attr_native_min_value = ctrl.get(LOWER_BOUND, 0.0) # Upstream const + self.ctrl = self.device.get(description.key, {}) + self._attr_native_max_value = self.ctrl.get(UPPER_BOUND, 100.0) # Upstream const + self._attr_native_min_value = self.ctrl.get(LOWER_BOUND, 0.0) # Upstream const - native_step = ctrl.get(RESOLUTION, 0.5) # Upstream const + native_step = self.ctrl.get(RESOLUTION, 0.5) # Upstream const if description.key != TEMPERATURE_OFFSET: # Upstream const native_step = max(native_step, 0.5) self._attr_native_step = native_step @@ -129,7 +129,7 @@ def __init__( @override def native_value(self) -> float | None: """Return the present setpoint value.""" - return self.device.get(self.entity_description.key, {}).get("setpoint") + return self.ctrl.get("setpoint") @plugwise_command @override diff --git a/tests/components/plugwise/test_number.py b/tests/components/plugwise/test_number.py index 9acf82fb4..f8fa61c20 100644 --- a/tests/components/plugwise/test_number.py +++ b/tests/components/plugwise/test_number.py @@ -93,7 +93,7 @@ async def test_anna_max_boiler_temp_change( NUMBER_DOMAIN, SERVICE_SET_VALUE, { - ATTR_ENTITY_ID: "number.opentherm_maximum_boiler_temperature_setpoint", + ATTR_ENTITY_ID: "number.opentherm_boiler_temperature_setpoint", ATTR_VALUE: 65, }, blocking=True, @@ -101,5 +101,5 @@ async def test_anna_max_boiler_temp_change( assert mock_smile_anna.set_number.call_count == 1 mock_smile_anna.set_number.assert_called_with( - "1cbf783bb11e4a7c8a6843dee3a86927", "maximum_boiler_temperature", 65.0 + "1cbf783bb11e4a7c8a6843dee3a86927", "boiler_temperature", 65.0 ) From fddd81bdc5b3d4b8494ef16892c8117bebe5b6dd Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sun, 21 Jun 2026 19:07:01 +0200 Subject: [PATCH 06/66] Update water_heater testcase --- tests/components/plugwise/test_water_heater.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/components/plugwise/test_water_heater.py b/tests/components/plugwise/test_water_heater.py index 3f2446637..4976781d5 100644 --- a/tests/components/plugwise/test_water_heater.py +++ b/tests/components/plugwise/test_water_heater.py @@ -47,7 +47,7 @@ async def test_adam_water_heater_setpoint_change( ) assert mock_smile_adam_jip.set_number.call_count == 1 mock_smile_adam_jip.set_number.assert_called_with( - "e4684553153b44afbef2200885f379dc", "max_dhw_temperature", 65.0, + "e4684553153b44afbef2200885f379dc", "dhw_temperature", 65.0, ) await hass.services.async_call( From 101faaab606f488d6ad114471ac808804801b909 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sun, 21 Jun 2026 19:16:45 +0200 Subject: [PATCH 07/66] Fix len asserts in test_update_device() --- tests/components/plugwise/test_init.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/components/plugwise/test_init.py b/tests/components/plugwise/test_init.py index 427d0e2de..1eeebf2eb 100644 --- a/tests/components/plugwise/test_init.py +++ b/tests/components/plugwise/test_init.py @@ -318,7 +318,7 @@ async def test_update_device( assert ( len(er.async_entries_for_config_entry(entity_registry, mock_config_entry.entry_id)) - == 53 + == 52 ) assert ( len(dr.async_entries_for_config_entry(device_registry, mock_config_entry.entry_id)) @@ -342,7 +342,7 @@ async def test_update_device( assert ( len(er.async_entries_for_config_entry(entity_registry, mock_config_entry.entry_id)) - == 60 + == 59 ) assert ( len(dr.async_entries_for_config_entry(device_registry, mock_config_entry.entry_id)) @@ -369,7 +369,7 @@ async def test_update_device( assert ( len(er.async_entries_for_config_entry(entity_registry, mock_config_entry.entry_id)) - == 53 + == 52 ) assert ( len(dr.async_entries_for_config_entry(device_registry, mock_config_entry.entry_id)) From f9ed4a1360e07b357ec41c79fce7d2b39a48c5e9 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sun, 21 Jun 2026 19:20:29 +0200 Subject: [PATCH 08/66] Update translations --- custom_components/plugwise/translations/en.json | 7 ++----- custom_components/plugwise/translations/nl.json | 7 ++----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/custom_components/plugwise/translations/en.json b/custom_components/plugwise/translations/en.json index 0015e95e4..0f410e0c3 100644 --- a/custom_components/plugwise/translations/en.json +++ b/custom_components/plugwise/translations/en.json @@ -93,11 +93,8 @@ } }, "number": { - "max_dhw_temperature": { - "name": "Domestic hot water setpoint" - }, - "maximum_boiler_temperature": { - "name": "Maximum boiler temperature setpoint" + "boiler_temperature": { + "name": "Boiler temperature setpoint" }, "temperature_offset": { "name": "Temperature offset" diff --git a/custom_components/plugwise/translations/nl.json b/custom_components/plugwise/translations/nl.json index b76c57143..675a9e972 100644 --- a/custom_components/plugwise/translations/nl.json +++ b/custom_components/plugwise/translations/nl.json @@ -93,11 +93,8 @@ } }, "number": { - "max_dhw_temperature": { - "name": "Instelpunt sanitair warm water" - }, - "maximum_boiler_temperature": { - "name": "Instelpunt maximale boiler temperatuur" + "boiler_temperature": { + "name": "Instelpunt boiler temperatuur" }, "temperature_offset": { "name": "Temperatuurcompensatie" From 659c8f2226eccbb49c238a87664e99c310189e93 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sun, 21 Jun 2026 19:22:46 +0200 Subject: [PATCH 09/66] Save updated snapshot files --- .../plugwise/snapshots/test_number.ambr | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/components/plugwise/snapshots/test_number.ambr b/tests/components/plugwise/snapshots/test_number.ambr index 1fdd2ea6e..0d1601e30 100644 --- a/tests/components/plugwise/snapshots/test_number.ambr +++ b/tests/components/plugwise/snapshots/test_number.ambr @@ -609,7 +609,7 @@ 'state': '-0.5', }) # --- -# name: test_anna_number_entities[platforms0-True-anna_heatpump_heating][number.opentherm_maximum_boiler_temperature_setpoint-entry] +# name: test_anna_number_entities[platforms0-True-anna_heatpump_heating][number.opentherm_boiler_temperature_setpoint-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ None, @@ -628,7 +628,7 @@ 'disabled_by': None, 'domain': 'number', 'entity_category': , - 'entity_id': 'number.opentherm_maximum_boiler_temperature_setpoint', + 'entity_id': 'number.opentherm_boiler_temperature_setpoint', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -636,22 +636,22 @@ 'labels': set({ }), 'name': None, - 'object_id_base': 'Maximum boiler temperature setpoint', + 'object_id_base': 'Boiler temperature setpoint', 'options': dict({ }), 'original_device_class': , 'original_icon': None, - 'original_name': 'Maximum boiler temperature setpoint', + 'original_name': 'Boiler temperature setpoint', 'platform': 'plugwise', 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': 'maximum_boiler_temperature', - 'unique_id': '1cbf783bb11e4a7c8a6843dee3a86927-maximum_boiler_temperature', + 'translation_key': 'boiler_temperature', + 'unique_id': '1cbf783bb11e4a7c8a6843dee3a86927-boiler_temperature', 'unit_of_measurement': , }) # --- -# name: test_anna_number_entities[platforms0-True-anna_heatpump_heating][number.opentherm_maximum_boiler_temperature_setpoint-state] +# name: test_anna_number_entities[platforms0-True-anna_heatpump_heating][number.opentherm_boiler_temperature_setpoint-state] StateSnapshot({ 'attributes': ReadOnlyDict({ : 'temperature', @@ -663,7 +663,7 @@ : , }), 'context': , - 'entity_id': 'number.opentherm_maximum_boiler_temperature_setpoint', + 'entity_id': 'number.opentherm_boiler_temperature_setpoint', 'last_changed': , 'last_reported': , 'last_updated': , From 81f1774a2423543ddeec834e48eb97b1aa4bdad3 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sun, 21 Jun 2026 19:23:22 +0200 Subject: [PATCH 10/66] Ruffed --- custom_components/plugwise/water_heater.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/custom_components/plugwise/water_heater.py b/custom_components/plugwise/water_heater.py index f72fc90e6..cfa0dd9f7 100644 --- a/custom_components/plugwise/water_heater.py +++ b/custom_components/plugwise/water_heater.py @@ -15,18 +15,7 @@ from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback -from .const import ( - DHW_MODE, - DHW_MODES, - DHW_SETPOINT, - DHW_TEMP, - LOGGER, - LOWER_BOUND, - SENSORS, - TARGET_TEMP, - UPPER_BOUND, - WATER_TEMP, -) +from .const import DHW_MODE, DHW_MODES, DHW_TEMP, LOGGER, LOWER_BOUND, UPPER_BOUND from .coordinator import PlugwiseConfigEntry, PlugwiseDataUpdateCoordinator from .entity import PlugwiseEntity from .util import plugwise_command From 52a8b6a56a0c5da91be3eb8570d13e3235b9156c Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sun, 21 Jun 2026 19:43:36 +0200 Subject: [PATCH 11/66] More updates --- custom_components/plugwise/const.py | 17 +++++++--- custom_components/plugwise/water_heater.py | 37 ++++++++++++++++++++-- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/custom_components/plugwise/const.py b/custom_components/plugwise/const.py index 4c568eb9f..0c741b718 100644 --- a/custom_components/plugwise/const.py +++ b/custom_components/plugwise/const.py @@ -77,14 +77,12 @@ VENDOR: Final = "vendor" # Number constants -BOILER_TEMP: Final = "boiler_temperature" LOWER_BOUND: Final = "lower_bound" RESOLUTION: Final = "resolution" TEMPERATURE_OFFSET: Final = "temperature_offset" UPPER_BOUND: Final = "upper_bound" # Sensor constants -DHW_TEMP: Final = "dhw_temperature" DHW_SETPOINT: Final = "domestic_hot_water_setpoint" EL_CONSUMED: Final = "electricity_consumed" EL_CONS_INTERVAL: Final = "electricity_consumed_interval" @@ -149,6 +147,10 @@ COOLING_ENA_SWITCH: Final ="cooling_ena_switch" SWITCHES: Final = "switches" +# Water_heater constants +BOILER_TEMP: Final = "boiler_temperature" +DHW_TEMP: Final = "dhw_temperature" + # Default directives DEFAULT_PORT: Final[int] = 80 DEFAULT_TIMEOUT: Final[int] = 30 @@ -187,11 +189,8 @@ } type NumberType = Literal[ - "boiler_temperature", - "dhw_temperature", "temperature_offset", ] - type SelectType = Literal[ "select_dhw_mode", "select_gateway_mode", @@ -206,3 +205,11 @@ "regulation_modes", "zone_profiles", ] +type WaterHeaterType = Literal[ + "boiler_temperature", + "dhw_temperature", +] +type WaterHeaterOptionsType = Literal[ + "boiler_modes", + "dhw_modes", +] diff --git a/custom_components/plugwise/water_heater.py b/custom_components/plugwise/water_heater.py index cfa0dd9f7..0ffcbc06e 100644 --- a/custom_components/plugwise/water_heater.py +++ b/custom_components/plugwise/water_heater.py @@ -4,12 +4,14 @@ from homeassistant.components.water_heater import ( WaterHeaterEntity, + WaterHeaterEntityDescription, WaterHeaterEntityFeature, ) from homeassistant.const import ( ATTR_NAME, ATTR_TEMPERATURE, STATE_OFF, + STATE_ON, UnitOfTemperature, ) from homeassistant.core import HomeAssistant, callback @@ -21,6 +23,32 @@ from .util import plugwise_command +@dataclass(frozen=True, kw_only=True) +class PlugwiseWaterHeaterEntityDescription(WaterHeaterEntityDescription): + """Class describing Plugwise WaterHeater entities.""" + + key: WaterHeaterType + options_key: WaterHeaterOptionsType + +# Upstream + is there a reason we didn't rename this one prefixed? +WATERHEATER_TYPES = ( + PlugwiseWaterHeaterEntityDescription( + key=BOILER_TEMP, + translation_key=BOILER_TEMP, + device_class=NumberDeviceClass.TEMPERATURE, + entity_category=EntityCategory.CONFIG, + native_unit_of_measurement=UnitOfTemperature.CELSIUS, + ), + PlugwiseWaterHeaterEntityDescription( + key=DHW_TEMP, + translation_key=DHW_TEMP, + device_class=NumberDeviceClass.TEMPERATURE, + entity_category=EntityCategory.CONFIG, + options_key=DHW_MODES + native_unit_of_measurement=UnitOfTemperature.CELSIUS, + ), +) + async def async_setup_entry( _hass: HomeAssistant, entry: PlugwiseConfigEntry, @@ -87,10 +115,13 @@ def current_temperature(self) -> float | None: @property @override def operation_list(self) -> list[str]: - """Return the list of available operation modes.""" - if (op_list := self.device.get(DHW_MODES, [])): + """Return the list of available operation modes. + + When no list is available the water_heater only has an "on" mode. + """ + if (op_list := self.device.get(self.entity_description.options_key, [])): return op_list - return [STATE_OFF] # pragma: no cover + return [STATE_ON] @property @override From 6be004bc3d426e25fd74178bf96a22f0ac295d75 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Mon, 22 Jun 2026 19:28:06 +0200 Subject: [PATCH 12/66] Remove boiler_temperature as number, moved to water_heater --- custom_components/plugwise/number.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/custom_components/plugwise/number.py b/custom_components/plugwise/number.py index 2ab24c736..107c2adf9 100644 --- a/custom_components/plugwise/number.py +++ b/custom_components/plugwise/number.py @@ -40,13 +40,6 @@ class PlugwiseNumberEntityDescription(NumberEntityDescription): # Upstream + is there a reason we didn't rename this one prefixed? NUMBER_TYPES = ( - PlugwiseNumberEntityDescription( - key=BOILER_TEMP, - translation_key=BOILER_TEMP, - device_class=NumberDeviceClass.TEMPERATURE, - entity_category=EntityCategory.CONFIG, - native_unit_of_measurement=UnitOfTemperature.CELSIUS, - ), PlugwiseNumberEntityDescription( key=TEMPERATURE_OFFSET, translation_key=TEMPERATURE_OFFSET, From 723aabfa0c336284636a7c353020ef9176cb7124 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Mon, 22 Jun 2026 19:29:12 +0200 Subject: [PATCH 13/66] Water_heater updates --- custom_components/plugwise/water_heater.py | 38 +++++++++++++++------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/custom_components/plugwise/water_heater.py b/custom_components/plugwise/water_heater.py index 0ffcbc06e..26e4a1231 100644 --- a/custom_components/plugwise/water_heater.py +++ b/custom_components/plugwise/water_heater.py @@ -1,5 +1,6 @@ """Plugwise water heater component for HomeAssistant.""" +from dataclasses import dataclass from typing import Any, override from homeassistant.components.water_heater import ( @@ -10,14 +11,24 @@ from homeassistant.const import ( ATTR_NAME, ATTR_TEMPERATURE, - STATE_OFF, STATE_ON, + EntityCategory, UnitOfTemperature, ) from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback -from .const import DHW_MODE, DHW_MODES, DHW_TEMP, LOGGER, LOWER_BOUND, UPPER_BOUND +from .const import ( + BOILER_TEMP, + DHW_MODE, + DHW_MODES, + DHW_TEMP, + LOGGER, + LOWER_BOUND, + UPPER_BOUND, + WaterHeaterOptionsType, + WaterHeaterType, +) from .coordinator import PlugwiseConfigEntry, PlugwiseDataUpdateCoordinator from .entity import PlugwiseEntity from .util import plugwise_command @@ -28,24 +39,23 @@ class PlugwiseWaterHeaterEntityDescription(WaterHeaterEntityDescription): """Class describing Plugwise WaterHeater entities.""" key: WaterHeaterType - options_key: WaterHeaterOptionsType + options_key: WaterHeaterOptionsType | None # Upstream + is there a reason we didn't rename this one prefixed? WATERHEATER_TYPES = ( PlugwiseWaterHeaterEntityDescription( key=BOILER_TEMP, translation_key=BOILER_TEMP, - device_class=NumberDeviceClass.TEMPERATURE, entity_category=EntityCategory.CONFIG, - native_unit_of_measurement=UnitOfTemperature.CELSIUS, + options_key=None, + unit_of_measurement=UnitOfTemperature.CELSIUS, ), PlugwiseWaterHeaterEntityDescription( key=DHW_TEMP, translation_key=DHW_TEMP, - device_class=NumberDeviceClass.TEMPERATURE, entity_category=EntityCategory.CONFIG, - options_key=DHW_MODES - native_unit_of_measurement=UnitOfTemperature.CELSIUS, + options_key=DHW_MODES, + unit_of_measurement=UnitOfTemperature.CELSIUS, ), ) @@ -66,9 +76,15 @@ def _add_entities() -> None: entities: list[PlugwiseWaterHeaterEntity] = [] for device_id in coordinator.new_devices: device = coordinator.data[device_id] - if device.get(DHW_TEMP) is not None: - entities.append(PlugwiseWaterHeaterEntity(coordinator, device_id)) - LOGGER.debug("Add %s water_heater", device[ATTR_NAME]) + for description in WATERHEATER_TYPES: + if description.key in device: + entities.append( + PlugwiseWaterHeaterEntity(coordinator, device_id, description) + ) + LOGGER.debug( + "Add %s %s water_heater", device["name"], description.translation_key + ) + async_add_entities(entities) _add_entities() From 1f218c3e521d8239448bb402fd0ac78788cb5f56 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Mon, 22 Jun 2026 19:46:57 +0200 Subject: [PATCH 14/66] More fixture updates --- .../components/plugwise/fixtures/adam_plus_anna_new/data.json | 4 ++-- .../plugwise/fixtures/anna_heatpump_heating/data.json | 4 ++-- tests/components/plugwise/fixtures/anna_p1/data.json | 2 +- tests/components/plugwise/fixtures/anna_v4/data.json | 4 ++-- tests/components/plugwise/fixtures/anna_v4_dhw/data.json | 4 ++-- tests/components/plugwise/fixtures/m_adam_cooling/data.json | 4 ++-- tests/components/plugwise/fixtures/m_adam_heating/data.json | 4 ++-- .../plugwise/fixtures/m_adam_heating_off_schedule/data.json | 4 ++-- tests/components/plugwise/fixtures/m_adam_jip/data.json | 4 ++-- .../plugwise/fixtures/m_anna_heatpump_cooling/data.json | 4 ++-- 10 files changed, 19 insertions(+), 19 deletions(-) diff --git a/tests/components/plugwise/fixtures/adam_plus_anna_new/data.json b/tests/components/plugwise/fixtures/adam_plus_anna_new/data.json index 5a199f12a..1f0aa4196 100644 --- a/tests/components/plugwise/fixtures/adam_plus_anna_new/data.json +++ b/tests/components/plugwise/fixtures/adam_plus_anna_new/data.json @@ -16,12 +16,12 @@ "dev_class": "heater_central", "dhw_modes": [ "comfort", - "off" + "eco" ], "location": "bc93488efab249e5bc54fd7e175a6f91", "model": "Generic heater", "name": "OpenTherm", - "select_dhw_mode": "off", + "select_dhw_mode": "eco", "sensors": { "intended_boiler_temperature": 22.5 } diff --git a/tests/components/plugwise/fixtures/anna_heatpump_heating/data.json b/tests/components/plugwise/fixtures/anna_heatpump_heating/data.json index 69ea20098..53b710551 100644 --- a/tests/components/plugwise/fixtures/anna_heatpump_heating/data.json +++ b/tests/components/plugwise/fixtures/anna_heatpump_heating/data.json @@ -36,10 +36,10 @@ "upper_bound": 100.0 }, "dev_class": "heater_central", - "dhw_mode": "off", + "dhw_mode": "eco", "dhw_modes": [ "comfort", - "off" + "eco" ], "dhw_temperature": { "current": 46.3, diff --git a/tests/components/plugwise/fixtures/anna_p1/data.json b/tests/components/plugwise/fixtures/anna_p1/data.json index 6ee72b54c..4a7f5aa03 100644 --- a/tests/components/plugwise/fixtures/anna_p1/data.json +++ b/tests/components/plugwise/fixtures/anna_p1/data.json @@ -50,7 +50,7 @@ "dev_class": "heater_central", "dhw_modes": [ "comfort", - "off" + "eco" ], "location": "da7be222ab3b420c927f3e49fade0304", "model": "Generic heater", diff --git a/tests/components/plugwise/fixtures/anna_v4/data.json b/tests/components/plugwise/fixtures/anna_v4/data.json index fbf163590..cecb3e0a8 100644 --- a/tests/components/plugwise/fixtures/anna_v4/data.json +++ b/tests/components/plugwise/fixtures/anna_v4/data.json @@ -74,10 +74,10 @@ "upper_bound": 100.0 }, "dev_class": "heater_central", - "dhw_mode": "off", + "dhw_mode": "eco", "dhw_modes": [ "comfort", - "off" + "eco" ], "dhw_temperature": { "current": 45.0, diff --git a/tests/components/plugwise/fixtures/anna_v4_dhw/data.json b/tests/components/plugwise/fixtures/anna_v4_dhw/data.json index 6ec073250..01c6bb25d 100644 --- a/tests/components/plugwise/fixtures/anna_v4_dhw/data.json +++ b/tests/components/plugwise/fixtures/anna_v4_dhw/data.json @@ -74,10 +74,10 @@ "upper_bound": 100.0 }, "dev_class": "heater_central", - "dhw_mode": "off", + "dhw_mode": "eco", "dhw_modes": [ "comfort", - "off" + "eco" ], "dhw_temperature": { "current": 45.0, diff --git a/tests/components/plugwise/fixtures/m_adam_cooling/data.json b/tests/components/plugwise/fixtures/m_adam_cooling/data.json index c388b60a6..6aaec3e90 100644 --- a/tests/components/plugwise/fixtures/m_adam_cooling/data.json +++ b/tests/components/plugwise/fixtures/m_adam_cooling/data.json @@ -17,12 +17,12 @@ "dev_class": "heater_central", "dhw_modes": [ "comfort", - "off" + "eco" ], "location": "bc93488efab249e5bc54fd7e175a6f91", "model": "Generic heater", "name": "OpenTherm", - "select_dhw_mode": "off", + "select_dhw_mode": "eco", "sensors": { "intended_boiler_temperature": 17.5 } diff --git a/tests/components/plugwise/fixtures/m_adam_heating/data.json b/tests/components/plugwise/fixtures/m_adam_heating/data.json index a45d345d8..ad2fb4df1 100644 --- a/tests/components/plugwise/fixtures/m_adam_heating/data.json +++ b/tests/components/plugwise/fixtures/m_adam_heating/data.json @@ -16,7 +16,7 @@ "dev_class": "heater_central", "dhw_modes": [ "comfort", - "off" + "eco" ], "dhw_temperature": { "current": 37.0, @@ -28,7 +28,7 @@ "location": "bc93488efab249e5bc54fd7e175a6f91", "model": "Generic heater", "name": "OpenTherm", - "select_dhw_mode": "off", + "select_dhw_mode": "eco", "sensors": { "intended_boiler_temperature": 38.1 } diff --git a/tests/components/plugwise/fixtures/m_adam_heating_off_schedule/data.json b/tests/components/plugwise/fixtures/m_adam_heating_off_schedule/data.json index a3c7095c4..9b2b1b245 100644 --- a/tests/components/plugwise/fixtures/m_adam_heating_off_schedule/data.json +++ b/tests/components/plugwise/fixtures/m_adam_heating_off_schedule/data.json @@ -16,7 +16,7 @@ "dev_class": "heater_central", "dhw_modes": [ "comfort", - "off" + "eco" ], "dhw_temperature": { "current": 37.0, @@ -28,7 +28,7 @@ "location": "bc93488efab249e5bc54fd7e175a6f91", "model": "Generic heater", "name": "OpenTherm", - "select_dhw_mode": "off", + "select_dhw_mode": "eco", "sensors": { "intended_boiler_temperature": 0.0 } diff --git a/tests/components/plugwise/fixtures/m_adam_jip/data.json b/tests/components/plugwise/fixtures/m_adam_jip/data.json index fd2ccd4dc..28867a99d 100644 --- a/tests/components/plugwise/fixtures/m_adam_jip/data.json +++ b/tests/components/plugwise/fixtures/m_adam_jip/data.json @@ -400,10 +400,10 @@ "upper_bound": 90.0 }, "dev_class": "heater_central", - "dhw_mode": "off", + "dhw_mode": "eco", "dhw_modes": [ "comfort", - "off" + "eco" ], "dhw_temperature": { "current": 37.3, diff --git a/tests/components/plugwise/fixtures/m_anna_heatpump_cooling/data.json b/tests/components/plugwise/fixtures/m_anna_heatpump_cooling/data.json index 44729c758..018610533 100644 --- a/tests/components/plugwise/fixtures/m_anna_heatpump_cooling/data.json +++ b/tests/components/plugwise/fixtures/m_anna_heatpump_cooling/data.json @@ -36,10 +36,10 @@ "upper_bound": 100.0 }, "dev_class": "heater_central", - "dhw_mode": "off", + "dhw_mode": "eco", "dhw_modes": [ "comfort", - "off" + "eco" ], "dhw_temperature": { "current": 41.5, From 97f79533b2ff564d594aad0baac33792ae5bf3a9 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Mon, 22 Jun 2026 19:49:19 +0200 Subject: [PATCH 15/66] More water_heater updates --- custom_components/plugwise/water_heater.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/custom_components/plugwise/water_heater.py b/custom_components/plugwise/water_heater.py index 26e4a1231..3f593071f 100644 --- a/custom_components/plugwise/water_heater.py +++ b/custom_components/plugwise/water_heater.py @@ -101,9 +101,11 @@ def __init__( self, coordinator: PlugwiseDataUpdateCoordinator, device_id: str, + description: PlugwiseWaterHeaterEntityDescription, ) -> None: """Initialise the water_heater.""" super().__init__(coordinator, device_id) + self.entity_description = description entity_name = f"{self.device[ATTR_NAME]}".lower() self._attr_unique_id = f"{device_id}-{entity_name}" @@ -114,7 +116,7 @@ def __init__( self._attr_min_temp = self.dhw_temp.get(LOWER_BOUND, 40.0) self._attr_supported_features = WaterHeaterEntityFeature.OPERATION_MODE self._attr_supported_features |= WaterHeaterEntityFeature.TARGET_TEMPERATURE - + self._attr_unique_id = f"{device_id}-water_heater" @property @override From cf5073347582279aa9187fc314483c509ac19b2f Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Mon, 22 Jun 2026 19:51:35 +0200 Subject: [PATCH 16/66] Update water_heater unique_id --- custom_components/plugwise/water_heater.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/plugwise/water_heater.py b/custom_components/plugwise/water_heater.py index 3f593071f..8a06bef24 100644 --- a/custom_components/plugwise/water_heater.py +++ b/custom_components/plugwise/water_heater.py @@ -116,7 +116,7 @@ def __init__( self._attr_min_temp = self.dhw_temp.get(LOWER_BOUND, 40.0) self._attr_supported_features = WaterHeaterEntityFeature.OPERATION_MODE self._attr_supported_features |= WaterHeaterEntityFeature.TARGET_TEMPERATURE - self._attr_unique_id = f"{device_id}-water_heater" + self._attr_unique_id = f"{device_id}-{description.key}" @property @override From 9f45c7a604612e6969c561a50cdd96dd4019d49a Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Mon, 22 Jun 2026 19:56:34 +0200 Subject: [PATCH 17/66] Update translation strings --- .../plugwise/translations/en.json | 23 ++++++++++--------- .../plugwise/translations/nl.json | 23 ++++++++++--------- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/custom_components/plugwise/translations/en.json b/custom_components/plugwise/translations/en.json index 0f410e0c3..ffb4dd2ab 100644 --- a/custom_components/plugwise/translations/en.json +++ b/custom_components/plugwise/translations/en.json @@ -93,9 +93,6 @@ } }, "number": { - "boiler_temperature": { - "name": "Boiler temperature setpoint" - }, "temperature_offset": { "name": "Temperature offset" } @@ -296,14 +293,18 @@ } }, "water_heater": { - "plugwise": { - "state": { - "auto": "Auto", - "boost": "Boost", - "comfort": "Comfort", - "eco": "Eco", - "off": "Off" - } + "boiler_temperature": { + "name": "Boiler temperature" + }, + "dhw_temperature": { + "name": "DHW temperature" + }, + "state": { + "auto": "Auto", + "boost": "Boost", + "comfort": "Comfort", + "eco": "Eco", + "off": "Off" } } }, diff --git a/custom_components/plugwise/translations/nl.json b/custom_components/plugwise/translations/nl.json index 675a9e972..4bfa4ba6a 100644 --- a/custom_components/plugwise/translations/nl.json +++ b/custom_components/plugwise/translations/nl.json @@ -93,9 +93,6 @@ } }, "number": { - "boiler_temperature": { - "name": "Instelpunt boiler temperatuur" - }, "temperature_offset": { "name": "Temperatuurcompensatie" } @@ -296,14 +293,18 @@ } }, "water_heater": { - "plugwise": { - "state": { - "auto": "Auto", - "boost": "Boost", - "comfort": "Comfort", - "eco": "Eco", - "off": "Off" - } + "boiler_temperature": { + "name": "Boiler temperatuur" + } + "dhw_temperature": { + "name": "SWW temperatuur" + } + "state": { + "auto": "Auto", + "boost": "Boost", + "comfort": "Comfort", + "eco": "Eco", + "off": "Off" } } }, From 4693deb47d2702845de4bf4df44d5ab83f1923c6 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Mon, 22 Jun 2026 20:10:57 +0200 Subject: [PATCH 18/66] Updates --- custom_components/plugwise/water_heater.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/custom_components/plugwise/water_heater.py b/custom_components/plugwise/water_heater.py index 8a06bef24..a19b2718b 100644 --- a/custom_components/plugwise/water_heater.py +++ b/custom_components/plugwise/water_heater.py @@ -48,14 +48,12 @@ class PlugwiseWaterHeaterEntityDescription(WaterHeaterEntityDescription): translation_key=BOILER_TEMP, entity_category=EntityCategory.CONFIG, options_key=None, - unit_of_measurement=UnitOfTemperature.CELSIUS, ), PlugwiseWaterHeaterEntityDescription( key=DHW_TEMP, translation_key=DHW_TEMP, entity_category=EntityCategory.CONFIG, options_key=DHW_MODES, - unit_of_measurement=UnitOfTemperature.CELSIUS, ), ) @@ -94,8 +92,7 @@ def _add_entities() -> None: class PlugwiseWaterHeaterEntity(PlugwiseEntity, WaterHeaterEntity): """Representation of a Plugwise water heater.""" - _attr_name = None - _attr_temperature_unit = UnitOfTemperature.CELSIUS + entity_description: PlugwiseWaterHeaterEntityDescription def __init__( self, @@ -116,6 +113,7 @@ def __init__( self._attr_min_temp = self.dhw_temp.get(LOWER_BOUND, 40.0) self._attr_supported_features = WaterHeaterEntityFeature.OPERATION_MODE self._attr_supported_features |= WaterHeaterEntityFeature.TARGET_TEMPERATURE + self._attr_temperature_unit = UnitOfTemperature.CELSIUS self._attr_unique_id = f"{device_id}-{description.key}" @property From f434ff6eae9b983fd90e7cfd65ccc9d1d754bdea Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Mon, 22 Jun 2026 20:14:34 +0200 Subject: [PATCH 19/66] Water_heater test updates --- tests/components/plugwise/test_water_heater.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/components/plugwise/test_water_heater.py b/tests/components/plugwise/test_water_heater.py index 4976781d5..5391def73 100644 --- a/tests/components/plugwise/test_water_heater.py +++ b/tests/components/plugwise/test_water_heater.py @@ -42,7 +42,7 @@ async def test_adam_water_heater_setpoint_change( await hass.services.async_call( WATER_HEATER_DOMAIN, SERVICE_SET_TEMPERATURE, - {ATTR_ENTITY_ID: "water_heater.opentherm", ATTR_TEMPERATURE: 65}, + {ATTR_ENTITY_ID: "water_heater.opentherm_dhw_temperature", ATTR_TEMPERATURE: 65}, blocking=True, ) assert mock_smile_adam_jip.set_number.call_count == 1 @@ -53,12 +53,12 @@ async def test_adam_water_heater_setpoint_change( await hass.services.async_call( WATER_HEATER_DOMAIN, SERVICE_SET_OPERATION_MODE, - {ATTR_ENTITY_ID: "water_heater.opentherm", ATTR_OPERATION_MODE: "off"}, + {ATTR_ENTITY_ID: "water_heater.opentherm_dhw_temperature", ATTR_OPERATION_MODE: "eco"}, blocking=True, ) assert mock_smile_adam_jip.set_dhw_mode.call_count == 1 mock_smile_adam_jip.set_dhw_mode.assert_called_with( - "dhw_mode", "e4684553153b44afbef2200885f379dc", 2, "off" + "dhw_mode", "e4684553153b44afbef2200885f379dc", 2, "eco" ) @pytest.mark.usefixtures("mock_smile_anna") From 361d7a84f03232114e5186cb45a789bc741eb557 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Mon, 22 Jun 2026 20:17:28 +0200 Subject: [PATCH 20/66] Test-number: remove test case, number removed --- tests/components/plugwise/test_number.py | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/tests/components/plugwise/test_number.py b/tests/components/plugwise/test_number.py index f8fa61c20..a7fa5caaa 100644 --- a/tests/components/plugwise/test_number.py +++ b/tests/components/plugwise/test_number.py @@ -81,25 +81,3 @@ async def test_anna_number_entities( ) -> None: """Test Anna number snapshot.""" await snapshot_platform(hass, entity_registry, snapshot, setup_platform.entry_id) - - -@pytest.mark.parametrize("chosen_env", ["anna_heatpump_heating"], indirect=True) -@pytest.mark.parametrize("cooling_present", [True], indirect=True) -async def test_anna_max_boiler_temp_change( - hass: HomeAssistant, mock_smile_anna: MagicMock, init_integration: MockConfigEntry -) -> None: - """Test changing of number entities.""" - await hass.services.async_call( - NUMBER_DOMAIN, - SERVICE_SET_VALUE, - { - ATTR_ENTITY_ID: "number.opentherm_boiler_temperature_setpoint", - ATTR_VALUE: 65, - }, - blocking=True, - ) - - assert mock_smile_anna.set_number.call_count == 1 - mock_smile_anna.set_number.assert_called_with( - "1cbf783bb11e4a7c8a6843dee3a86927", "boiler_temperature", 65.0 - ) From 0bbcf924bfbe85a93bfae81ae313632665c25bc1 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Mon, 22 Jun 2026 20:22:51 +0200 Subject: [PATCH 21/66] Fix code --- custom_components/plugwise/number.py | 2 -- custom_components/plugwise/water_heater.py | 8 +++++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/custom_components/plugwise/number.py b/custom_components/plugwise/number.py index 107c2adf9..6e93d1c52 100644 --- a/custom_components/plugwise/number.py +++ b/custom_components/plugwise/number.py @@ -114,8 +114,6 @@ def __init__( self._attr_native_min_value = self.ctrl.get(LOWER_BOUND, 0.0) # Upstream const native_step = self.ctrl.get(RESOLUTION, 0.5) # Upstream const - if description.key != TEMPERATURE_OFFSET: # Upstream const - native_step = max(native_step, 0.5) self._attr_native_step = native_step @property diff --git a/custom_components/plugwise/water_heater.py b/custom_components/plugwise/water_heater.py index a19b2718b..190a931c5 100644 --- a/custom_components/plugwise/water_heater.py +++ b/custom_components/plugwise/water_heater.py @@ -9,7 +9,6 @@ WaterHeaterEntityFeature, ) from homeassistant.const import ( - ATTR_NAME, ATTR_TEMPERATURE, STATE_ON, EntityCategory, @@ -135,8 +134,11 @@ def operation_list(self) -> list[str]: When no list is available the water_heater only has an "on" mode. """ - if (op_list := self.device.get(self.entity_description.options_key, [])): - return op_list + if self.entity_description.options_key is not None: + op_list = self.device.get(self.entity_description.options_key) + if op_list is not None: + return cast(list[str], op_list) + return [STATE_ON] @property From 16d9b295a307341c9e4a0dfe168fadd3ea3e75b7 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Tue, 23 Jun 2026 08:01:41 +0200 Subject: [PATCH 22/66] Save updated snapshot files --- .../plugwise/snapshots/test_select.ambr | 6 +-- .../plugwise/snapshots/test_water_heater.ambr | 48 +++++++++---------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/tests/components/plugwise/snapshots/test_select.ambr b/tests/components/plugwise/snapshots/test_select.ambr index 1b6804115..f9427f3b9 100644 --- a/tests/components/plugwise/snapshots/test_select.ambr +++ b/tests/components/plugwise/snapshots/test_select.ambr @@ -386,7 +386,7 @@ 'capabilities': dict({ : list([ 'comfort', - 'off', + 'eco', ]), }), 'config_entry_id': , @@ -425,7 +425,7 @@ : 'OpenTherm DHW mode', : list([ 'comfort', - 'off', + 'eco', ]), }), 'context': , @@ -433,7 +433,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'off', + 'state': 'eco', }) # --- # name: test_adam_select_entities[platforms0][select.badkamer_thermostat_schedule-entry] diff --git a/tests/components/plugwise/snapshots/test_water_heater.ambr b/tests/components/plugwise/snapshots/test_water_heater.ambr index 2f3ef30d5..29dee55b4 100644 --- a/tests/components/plugwise/snapshots/test_water_heater.ambr +++ b/tests/components/plugwise/snapshots/test_water_heater.ambr @@ -1,5 +1,5 @@ # serializer version: 1 -# name: test_adam_water_heater_snapshot[platforms0][water_heater.opentherm-entry] +# name: test_adam_water_heater_snapshot[platforms0][water_heater.opentherm_boiler_temperature-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ None, @@ -10,7 +10,7 @@ : 40.0, : list([ 'comfort', - 'off', + 'eco', ]), }), 'config_entry_id': , @@ -19,8 +19,8 @@ 'device_id': , 'disabled_by': None, 'domain': 'water_heater', - 'entity_category': None, - 'entity_id': 'water_heater.opentherm', + 'entity_category': , + 'entity_id': 'water_heater.opentherm_dhw_temperature', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -28,22 +28,22 @@ 'labels': set({ }), 'name': None, - 'object_id_base': None, + 'object_id_base': 'DHW temperature', 'options': dict({ }), 'original_device_class': None, 'original_icon': None, - 'original_name': None, + 'original_name': 'DHW temperature', 'platform': 'plugwise', 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': , - 'translation_key': None, - 'unique_id': 'e4684553153b44afbef2200885f379dc-opentherm', + 'translation_key': 'dhw_temperature', + 'unique_id': 'e4684553153b44afbef2200885f379dc-dhw_temperature', 'unit_of_measurement': None, }) # --- -# name: test_adam_water_heater_snapshot[platforms0][water_heater.opentherm-state] +# name: test_adam_water_heater_snapshot[platforms0][water_heater.opentherm_dhw_temperature-state] StateSnapshot({ 'attributes': ReadOnlyDict({ : 37.3, @@ -52,7 +52,7 @@ : 40.0, : list([ 'comfort', - 'off', + 'eco', ]), : 'off', : , @@ -61,14 +61,14 @@ : 60.0, }), 'context': , - 'entity_id': 'water_heater.opentherm', + 'entity_id': 'water_heater.opentherm_dhw_temperature', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'off', + 'state': 'eco', }) # --- -# name: test_anna_water_heater_snapshot[platforms0-False-anna_v4_dhw][water_heater.opentherm-entry] +# name: test_anna_water_heater_snapshot[platforms0-False-anna_v4_dhw][water_heater.opentherm_boiler_temperature-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ None, @@ -79,7 +79,7 @@ : 30.0, : list([ 'comfort', - 'off', + 'eco', ]), }), 'config_entry_id': , @@ -88,8 +88,8 @@ 'device_id': , 'disabled_by': None, 'domain': 'water_heater', - 'entity_category': None, - 'entity_id': 'water_heater.opentherm', + 'entity_category': , + 'entity_id': 'water_heater.opentherm_dhw_temperature', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -97,22 +97,22 @@ 'labels': set({ }), 'name': None, - 'object_id_base': None, + 'object_id_base': 'DHW temperature', 'options': dict({ }), 'original_device_class': None, 'original_icon': None, - 'original_name': None, + 'original_name': 'DHW temperature', 'platform': 'plugwise', 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': , - 'translation_key': None, - 'unique_id': 'cd0e6156b1f04d5f952349ffbe397481-opentherm', + 'translation_key': 'dhw_temperature', + 'unique_id': 'cd0e6156b1f04d5f952349ffbe397481-dhw_temperature', 'unit_of_measurement': None, }) # --- -# name: test_anna_water_heater_snapshot[platforms0-False-anna_v4_dhw][water_heater.opentherm-state] +# name: test_anna_water_heater_snapshot[platforms0-False-anna_v4_dhw][water_heater.opentherm_dhw_temperature-state] StateSnapshot({ 'attributes': ReadOnlyDict({ : 45.0, @@ -121,7 +121,7 @@ : 30.0, : list([ 'comfort', - 'off', + 'eco', ]), : 'off', : , @@ -130,10 +130,10 @@ : 60.0, }), 'context': , - 'entity_id': 'water_heater.opentherm', + 'entity_id': 'water_heater.opentherm_dhw_temperature', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'off', + 'state': 'eco', }) # --- From 1914986dab6b70a056408e4adab4c847387d06c7 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Tue, 23 Jun 2026 08:02:12 +0200 Subject: [PATCH 23/66] Clean up --- custom_components/plugwise/number.py | 1 - 1 file changed, 1 deletion(-) diff --git a/custom_components/plugwise/number.py b/custom_components/plugwise/number.py index 6e93d1c52..13e777359 100644 --- a/custom_components/plugwise/number.py +++ b/custom_components/plugwise/number.py @@ -14,7 +14,6 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from .const import ( - BOILER_TEMP, LOGGER, LOWER_BOUND, RESOLUTION, From 7e4796d22fa6728df564cde0ab8c912f19f58190 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Tue, 23 Jun 2026 08:08:56 +0200 Subject: [PATCH 24/66] Correct translation files --- custom_components/plugwise/translations/en.json | 7 ------- custom_components/plugwise/translations/nl.json | 9 +-------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/custom_components/plugwise/translations/en.json b/custom_components/plugwise/translations/en.json index ffb4dd2ab..c6a52b3b8 100644 --- a/custom_components/plugwise/translations/en.json +++ b/custom_components/plugwise/translations/en.json @@ -298,13 +298,6 @@ }, "dhw_temperature": { "name": "DHW temperature" - }, - "state": { - "auto": "Auto", - "boost": "Boost", - "comfort": "Comfort", - "eco": "Eco", - "off": "Off" } } }, diff --git a/custom_components/plugwise/translations/nl.json b/custom_components/plugwise/translations/nl.json index 4bfa4ba6a..1a70c6ddb 100644 --- a/custom_components/plugwise/translations/nl.json +++ b/custom_components/plugwise/translations/nl.json @@ -295,17 +295,10 @@ "water_heater": { "boiler_temperature": { "name": "Boiler temperatuur" - } + }, "dhw_temperature": { "name": "SWW temperatuur" } - "state": { - "auto": "Auto", - "boost": "Boost", - "comfort": "Comfort", - "eco": "Eco", - "off": "Off" - } } }, "exceptions": { From 410184d2e4c69d3f6de8c2c8a52c10132508135f Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Tue, 23 Jun 2026 08:15:47 +0200 Subject: [PATCH 25/66] Fix requirements format --- custom_components/plugwise/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/plugwise/manifest.json b/custom_components/plugwise/manifest.json index 3c0b27bcc..23e5c8a65 100644 --- a/custom_components/plugwise/manifest.json +++ b/custom_components/plugwise/manifest.json @@ -8,7 +8,7 @@ "iot_class": "local_polling", "loggers": ["plugwise"], "requirements": [ - "plugwise@git+https://github.com/plugwise/python-plugwise.git/@water_heater_2" + "plugwise@git+https://github.com/plugwise/python-plugwise.git@water_heater_2" ], "version": "0.65.0", "zeroconf": ["_plugwise._tcp.local."] From baf4b9500059b91b6b232afd13f18a56c97a9500 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Tue, 23 Jun 2026 08:21:17 +0200 Subject: [PATCH 26/66] Implement suggested fixes --- custom_components/plugwise/number.py | 10 ++++---- custom_components/plugwise/water_heater.py | 29 ++++++++++++++-------- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/custom_components/plugwise/number.py b/custom_components/plugwise/number.py index 13e777359..39a71179a 100644 --- a/custom_components/plugwise/number.py +++ b/custom_components/plugwise/number.py @@ -108,18 +108,18 @@ def __init__( self.entity_description = description self._attr_unique_id = f"{device_id}-{description.key}" self._attr_mode = NumberMode.BOX - self.ctrl = self.device.get(description.key, {}) - self._attr_native_max_value = self.ctrl.get(UPPER_BOUND, 100.0) # Upstream const - self._attr_native_min_value = self.ctrl.get(LOWER_BOUND, 0.0) # Upstream const + ctrl = self.device.get(description.key, {}) + self._attr_native_max_value = ctrl.get(UPPER_BOUND, 100.0) # Upstream const + self._attr_native_min_value = ctrl.get(LOWER_BOUND, 0.0) # Upstream const - native_step = self.ctrl.get(RESOLUTION, 0.5) # Upstream const + native_step = ctrl.get(RESOLUTION, 0.5) # Upstream const self._attr_native_step = native_step @property @override def native_value(self) -> float | None: """Return the present setpoint value.""" - return self.ctrl.get("setpoint") + return self.device.get(self.entity_description.key, {}).get("setpoint") @plugwise_command @override diff --git a/custom_components/plugwise/water_heater.py b/custom_components/plugwise/water_heater.py index 190a931c5..6bfa4db45 100644 --- a/custom_components/plugwise/water_heater.py +++ b/custom_components/plugwise/water_heater.py @@ -102,16 +102,15 @@ def __init__( """Initialise the water_heater.""" super().__init__(coordinator, device_id) self.entity_description = description - entity_name = f"{self.device[ATTR_NAME]}".lower() self._attr_unique_id = f"{device_id}-{entity_name}" - - self.dhw_temp = self.device.get(DHW_TEMP, {}) - if self.dhw_temp: - self._attr_max_temp = self.dhw_temp.get(UPPER_BOUND, 75.0) - self._attr_min_temp = self.dhw_temp.get(LOWER_BOUND, 40.0) - self._attr_supported_features = WaterHeaterEntityFeature.OPERATION_MODE - self._attr_supported_features |= WaterHeaterEntityFeature.TARGET_TEMPERATURE + temp_data = self.device.get(description.key, {}) + if temp_data: + self._attr_max_temp = temp_data.get(UPPER_BOUND, 75.0) + self._attr_min_temp = temp_data.get(LOWER_BOUND, 40.0) + self._attr_supported_features = WaterHeaterEntityFeature.TARGET_TEMPERATURE + if description.options_key is not None: + self._attr_supported_features |= WaterHeaterEntityFeature.OPERATION_MODE self._attr_temperature_unit = UnitOfTemperature.CELSIUS self._attr_unique_id = f"{device_id}-{description.key}" @@ -119,13 +118,15 @@ def __init__( @override def current_operation(self) -> str | None: """Return current readable operation mode.""" + if self.entity_description.options_key is None: + return STATE_ON return self.device.get(DHW_MODE) @property @override def current_temperature(self) -> float | None: """Return the current water temperature.""" - return self.dhw_temp.get("current") + return self.device.get(self.entity_description.key, {}).get("current") @property @override @@ -145,12 +146,14 @@ def operation_list(self) -> list[str]: @override def target_temperature(self) -> float | None: """Return the water temperature we try to reach.""" - return self.dhw_temp.get("setpoint") + return self.device.get(self.entity_description.key, {}).get("setpoint") @plugwise_command @override async def async_set_operation_mode(self, operation_mode: str) -> None: """Set the operation mode.""" + if self.entity_description.options_key is None: + return list_type: int = len(self.operation_list) await self.coordinator.api.set_dhw_mode(DHW_MODE, self._dev_id, list_type, operation_mode) @@ -159,4 +162,8 @@ async def async_set_operation_mode(self, operation_mode: str) -> None: async def async_set_temperature(self, **kwargs: Any) -> None: """Set new target temperature.""" if (temperature := kwargs.get(ATTR_TEMPERATURE)) is not None: - await self.coordinator.api.set_number(self._dev_id, DHW_TEMP, float(temperature)) + await self.coordinator.api.set_number( + self._dev_id, + self.entity_description.key, + float(temperature), + ) From a04bcaffcac1cee8d46adedbf9c11272e6e3367b Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Thu, 25 Jun 2026 17:53:02 +0200 Subject: [PATCH 27/66] Update dhw-select translations --- custom_components/plugwise/translations/en.json | 2 +- custom_components/plugwise/translations/nl.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/plugwise/translations/en.json b/custom_components/plugwise/translations/en.json index c6a52b3b8..e3c262381 100644 --- a/custom_components/plugwise/translations/en.json +++ b/custom_components/plugwise/translations/en.json @@ -102,7 +102,7 @@ "name": "DHW mode", "state": { "comfort": "Comfort", - "off": "Off" + "eco": "Eco" } }, "select_gateway_mode": { diff --git a/custom_components/plugwise/translations/nl.json b/custom_components/plugwise/translations/nl.json index 1a70c6ddb..0c7687071 100644 --- a/custom_components/plugwise/translations/nl.json +++ b/custom_components/plugwise/translations/nl.json @@ -102,7 +102,7 @@ "name": "SWW modus", "state": { "comfort": "Comfort", - "off": "Uit" + "eco": "Eco" } }, "select_gateway_mode": { From dbc9d60e11db3063aa73a9fde494f6a372df7f24 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Thu, 25 Jun 2026 17:57:24 +0200 Subject: [PATCH 28/66] Add water_heater state translation string --- custom_components/plugwise/translations/en.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/custom_components/plugwise/translations/en.json b/custom_components/plugwise/translations/en.json index e3c262381..f7b7a9985 100644 --- a/custom_components/plugwise/translations/en.json +++ b/custom_components/plugwise/translations/en.json @@ -297,7 +297,14 @@ "name": "Boiler temperature" }, "dhw_temperature": { - "name": "DHW temperature" + "name": "DHW temperature", + "state": { + "auto": "Auto", + "boost": "Boost", + "comfort": "Comfort", + "eco": "Eco", + "off": "Off" + } } } }, From f4c851c8294c830a8e7445c080d253f605c4ef98 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Thu, 25 Jun 2026 18:18:34 +0200 Subject: [PATCH 29/66] Correct water_heater translation string --- custom_components/plugwise/translations/en.json | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/custom_components/plugwise/translations/en.json b/custom_components/plugwise/translations/en.json index f7b7a9985..d3436c798 100644 --- a/custom_components/plugwise/translations/en.json +++ b/custom_components/plugwise/translations/en.json @@ -298,12 +298,16 @@ }, "dhw_temperature": { "name": "DHW temperature", - "state": { - "auto": "Auto", - "boost": "Boost", - "comfort": "Comfort", - "eco": "Eco", - "off": "Off" + "state_attributes": { + "dhw_modes": { + "state": { + "auto": "Auto", + "boost": "Boost", + "comfort": "Comfort", + "eco": "Eco", + "off": "Off" + } + } } } } From e274e0c28883fe18bf6b642237ee677a6f39a0df Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Fri, 26 Jun 2026 20:27:13 +0200 Subject: [PATCH 30/66] Fix removed import after rebase --- custom_components/plugwise/water_heater.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/plugwise/water_heater.py b/custom_components/plugwise/water_heater.py index 6bfa4db45..b74ec5a9e 100644 --- a/custom_components/plugwise/water_heater.py +++ b/custom_components/plugwise/water_heater.py @@ -1,7 +1,7 @@ """Plugwise water heater component for HomeAssistant.""" from dataclasses import dataclass -from typing import Any, override +from typing import Any, cast, override from homeassistant.components.water_heater import ( WaterHeaterEntity, From d858a6c516e33c53f08d1ac52641f017b4b4e265 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Fri, 26 Jun 2026 20:29:39 +0200 Subject: [PATCH 31/66] Regenerate snapshots after rebase --- .../plugwise/snapshots/test_number.ambr | 61 ------ .../plugwise/snapshots/test_sensor.ambr | 174 ------------------ .../plugwise/snapshots/test_water_heater.ambr | 128 ++++++++++++- 3 files changed, 124 insertions(+), 239 deletions(-) diff --git a/tests/components/plugwise/snapshots/test_number.ambr b/tests/components/plugwise/snapshots/test_number.ambr index 0d1601e30..ed8383fff 100644 --- a/tests/components/plugwise/snapshots/test_number.ambr +++ b/tests/components/plugwise/snapshots/test_number.ambr @@ -609,64 +609,3 @@ 'state': '-0.5', }) # --- -# name: test_anna_number_entities[platforms0-True-anna_heatpump_heating][number.opentherm_boiler_temperature_setpoint-entry] - EntityRegistryEntrySnapshot({ - 'aliases': list([ - None, - ]), - 'area_id': None, - 'capabilities': dict({ - : 100.0, - : 0.0, - : , - : 1.0, - }), - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'number', - 'entity_category': , - 'entity_id': 'number.opentherm_boiler_temperature_setpoint', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'object_id_base': 'Boiler temperature setpoint', - 'options': dict({ - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Boiler temperature setpoint', - 'platform': 'plugwise', - 'previous_unique_id': None, - 'suggested_object_id': None, - 'supported_features': 0, - 'translation_key': 'boiler_temperature', - 'unique_id': '1cbf783bb11e4a7c8a6843dee3a86927-boiler_temperature', - 'unit_of_measurement': , - }) -# --- -# name: test_anna_number_entities[platforms0-True-anna_heatpump_heating][number.opentherm_boiler_temperature_setpoint-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - : 'temperature', - : 'OpenTherm Maximum boiler temperature setpoint', - : 100.0, - : 0.0, - : , - : 1.0, - : , - }), - 'context': , - 'entity_id': 'number.opentherm_boiler_temperature_setpoint', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': '60.0', - }) -# --- diff --git a/tests/components/plugwise/snapshots/test_sensor.ambr b/tests/components/plugwise/snapshots/test_sensor.ambr index 87fe0b387..8b430581f 100644 --- a/tests/components/plugwise/snapshots/test_sensor.ambr +++ b/tests/components/plugwise/snapshots/test_sensor.ambr @@ -1202,64 +1202,6 @@ 'state': '38.1', }) # --- -# name: test_adam_sensor_snapshot[platforms0-False-m_adam_heating][sensor.opentherm_water_temperature-entry] - EntityRegistryEntrySnapshot({ - 'aliases': list([ - None, - ]), - 'area_id': None, - 'capabilities': dict({ - : , - }), - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': , - 'entity_id': 'sensor.opentherm_water_temperature', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'object_id_base': 'Water temperature', - 'options': dict({ - 'sensor': dict({ - 'suggested_display_precision': 1, - }), - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Water temperature', - 'platform': 'plugwise', - 'previous_unique_id': None, - 'suggested_object_id': None, - 'supported_features': 0, - 'translation_key': 'water_temperature', - 'unique_id': '056ee145a816487eaa69243c3280f8bf-water_temperature', - 'unit_of_measurement': , - }) -# --- -# name: test_adam_sensor_snapshot[platforms0-False-m_adam_heating][sensor.opentherm_water_temperature-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - : 'temperature', - : 'OpenTherm Water temperature', - : , - : , - }), - 'context': , - 'entity_id': 'sensor.opentherm_water_temperature', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': '37.0', - }) -# --- # name: test_adam_sensor_snapshot[platforms0-False-m_adam_heating][sensor.tom_badkamer_battery-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ @@ -3501,64 +3443,6 @@ 'state': '19.3', }) # --- -# name: test_anna_sensor_snapshot[platforms0-True-anna_heatpump_heating][sensor.opentherm_dhw_temperature-entry] - EntityRegistryEntrySnapshot({ - 'aliases': list([ - None, - ]), - 'area_id': None, - 'capabilities': dict({ - : , - }), - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': , - 'entity_id': 'sensor.opentherm_dhw_temperature', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'object_id_base': 'DHW temperature', - 'options': dict({ - 'sensor': dict({ - 'suggested_display_precision': 1, - }), - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'DHW temperature', - 'platform': 'plugwise', - 'previous_unique_id': None, - 'suggested_object_id': None, - 'supported_features': 0, - 'translation_key': 'dhw_temperature', - 'unique_id': '1cbf783bb11e4a7c8a6843dee3a86927-dhw_temperature', - 'unit_of_measurement': , - }) -# --- -# name: test_anna_sensor_snapshot[platforms0-True-anna_heatpump_heating][sensor.opentherm_dhw_temperature-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - : 'temperature', - : 'OpenTherm DHW temperature', - : , - : , - }), - 'context': , - 'entity_id': 'sensor.opentherm_dhw_temperature', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': '46.3', - }) -# --- # name: test_anna_sensor_snapshot[platforms0-True-anna_heatpump_heating][sensor.opentherm_intended_boiler_temperature-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ @@ -3845,64 +3729,6 @@ 'state': '1.57', }) # --- -# name: test_anna_sensor_snapshot[platforms0-True-anna_heatpump_heating][sensor.opentherm_water_temperature-entry] - EntityRegistryEntrySnapshot({ - 'aliases': list([ - None, - ]), - 'area_id': None, - 'capabilities': dict({ - : , - }), - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': , - 'entity_id': 'sensor.opentherm_water_temperature', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'object_id_base': 'Water temperature', - 'options': dict({ - 'sensor': dict({ - 'suggested_display_precision': 1, - }), - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Water temperature', - 'platform': 'plugwise', - 'previous_unique_id': None, - 'suggested_object_id': None, - 'supported_features': 0, - 'translation_key': 'water_temperature', - 'unique_id': '1cbf783bb11e4a7c8a6843dee3a86927-water_temperature', - 'unit_of_measurement': , - }) -# --- -# name: test_anna_sensor_snapshot[platforms0-True-anna_heatpump_heating][sensor.opentherm_water_temperature-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - : 'temperature', - : 'OpenTherm Water temperature', - : , - : , - }), - 'context': , - 'entity_id': 'sensor.opentherm_water_temperature', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': '29.1', - }) -# --- # name: test_anna_sensor_snapshot[platforms0-True-anna_heatpump_heating][sensor.smile_anna_outdoor_temperature-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ diff --git a/tests/components/plugwise/snapshots/test_water_heater.ambr b/tests/components/plugwise/snapshots/test_water_heater.ambr index 29dee55b4..0d4c3a827 100644 --- a/tests/components/plugwise/snapshots/test_water_heater.ambr +++ b/tests/components/plugwise/snapshots/test_water_heater.ambr @@ -1,5 +1,65 @@ # serializer version: 1 # name: test_adam_water_heater_snapshot[platforms0][water_heater.opentherm_boiler_temperature-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': dict({ + : 90.0, + : 20.0, + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'water_heater', + 'entity_category': , + 'entity_id': 'water_heater.opentherm_boiler_temperature', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Boiler temperature', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Boiler temperature', + 'platform': 'plugwise', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': , + 'translation_key': 'boiler_temperature', + 'unique_id': 'e4684553153b44afbef2200885f379dc-boiler_temperature', + 'unit_of_measurement': None, + }) +# --- +# name: test_adam_water_heater_snapshot[platforms0][water_heater.opentherm_boiler_temperature-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : 37.3, + : 'OpenTherm Boiler temperature', + : 90.0, + : 20.0, + : , + : None, + : None, + : 90.0, + }), + 'context': , + 'entity_id': 'water_heater.opentherm_boiler_temperature', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- +# name: test_adam_water_heater_snapshot[platforms0][water_heater.opentherm_dhw_temperature-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ None, @@ -47,14 +107,14 @@ StateSnapshot({ 'attributes': ReadOnlyDict({ : 37.3, - : 'OpenTherm', + : 'OpenTherm DHW temperature', : 60.0, : 40.0, : list([ 'comfort', 'eco', ]), - : 'off', + : 'eco', : , : None, : None, @@ -69,6 +129,66 @@ }) # --- # name: test_anna_water_heater_snapshot[platforms0-False-anna_v4_dhw][water_heater.opentherm_boiler_temperature-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': dict({ + : 100.0, + : 0.0, + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'water_heater', + 'entity_category': , + 'entity_id': 'water_heater.opentherm_boiler_temperature', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Boiler temperature', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Boiler temperature', + 'platform': 'plugwise', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': , + 'translation_key': 'boiler_temperature', + 'unique_id': 'cd0e6156b1f04d5f952349ffbe397481-boiler_temperature', + 'unit_of_measurement': None, + }) +# --- +# name: test_anna_water_heater_snapshot[platforms0-False-anna_v4_dhw][water_heater.opentherm_boiler_temperature-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : 45.0, + : 'OpenTherm Boiler temperature', + : 100.0, + : 0.0, + : , + : None, + : None, + : 70.0, + }), + 'context': , + 'entity_id': 'water_heater.opentherm_boiler_temperature', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- +# name: test_anna_water_heater_snapshot[platforms0-False-anna_v4_dhw][water_heater.opentherm_dhw_temperature-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ None, @@ -116,14 +236,14 @@ StateSnapshot({ 'attributes': ReadOnlyDict({ : 45.0, - : 'OpenTherm', + : 'OpenTherm DHW temperature', : 60.0, : 30.0, : list([ 'comfort', 'eco', ]), - : 'off', + : 'eco', : , : None, : None, From 0713bdf672deb6f0c087717eece097e564e8d2d7 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sat, 27 Jun 2026 11:06:15 +0200 Subject: [PATCH 32/66] Improve typing, test coverage --- custom_components/plugwise/const.py | 5 +--- custom_components/plugwise/water_heater.py | 23 ++++++++----------- .../components/plugwise/test_water_heater.py | 10 ++++++++ 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/custom_components/plugwise/const.py b/custom_components/plugwise/const.py index 0c741b718..90554e7d5 100644 --- a/custom_components/plugwise/const.py +++ b/custom_components/plugwise/const.py @@ -209,7 +209,4 @@ "boiler_temperature", "dhw_temperature", ] -type WaterHeaterOptionsType = Literal[ - "boiler_modes", - "dhw_modes", -] +type WaterHeaterOptionsType = Literal["dhw_modes"] diff --git a/custom_components/plugwise/water_heater.py b/custom_components/plugwise/water_heater.py index b74ec5a9e..55498795a 100644 --- a/custom_components/plugwise/water_heater.py +++ b/custom_components/plugwise/water_heater.py @@ -1,7 +1,7 @@ """Plugwise water heater component for HomeAssistant.""" from dataclasses import dataclass -from typing import Any, cast, override +from typing import Any, override from homeassistant.components.water_heater import ( WaterHeaterEntity, @@ -32,6 +32,7 @@ from .entity import PlugwiseEntity from .util import plugwise_command +PARALLEL_UPDATES = 0 @dataclass(frozen=True, kw_only=True) class PlugwiseWaterHeaterEntityDescription(WaterHeaterEntityDescription): @@ -130,17 +131,12 @@ def current_temperature(self) -> float | None: @property @override - def operation_list(self) -> list[str]: - """Return the list of available operation modes. + def operation_list(self) -> list[str] | None: + """Return the list of available operation modes.""" + if (key := self.entity_description.options_key) is not None: + return self.device.get(key, []) - When no list is available the water_heater only has an "on" mode. - """ - if self.entity_description.options_key is not None: - op_list = self.device.get(self.entity_description.options_key) - if op_list is not None: - return cast(list[str], op_list) - - return [STATE_ON] + return None # pragma: no cover @property @override @@ -152,8 +148,9 @@ def target_temperature(self) -> float | None: @override async def async_set_operation_mode(self, operation_mode: str) -> None: """Set the operation mode.""" - if self.entity_description.options_key is None: - return + if self.operation_list is None: + return # pragma: no cover + list_type: int = len(self.operation_list) await self.coordinator.api.set_dhw_mode(DHW_MODE, self._dev_id, list_type, operation_mode) diff --git a/tests/components/plugwise/test_water_heater.py b/tests/components/plugwise/test_water_heater.py index 5391def73..21db7d29a 100644 --- a/tests/components/plugwise/test_water_heater.py +++ b/tests/components/plugwise/test_water_heater.py @@ -12,6 +12,7 @@ ) from homeassistant.const import ATTR_ENTITY_ID, ATTR_TEMPERATURE from homeassistant.core import HomeAssistant +from homeassistant.exceptions import ServiceNotSupported from homeassistant.helpers import entity_registry as er from syrupy.assertion import SnapshotAssertion @@ -50,6 +51,15 @@ async def test_adam_water_heater_setpoint_change( "e4684553153b44afbef2200885f379dc", "dhw_temperature", 65.0, ) + with pytest.raises(ServiceNotSupported): + await hass.services.async_call( + WATER_HEATER_DOMAIN, + SERVICE_SET_OPERATION_MODE, + {ATTR_ENTITY_ID: "water_heater.opentherm_boiler_temperature", ATTR_OPERATION_MODE: "eco"}, + blocking=True, + ) + assert mock_smile_adam_jip.set_dhw_mode.call_count == 0 + await hass.services.async_call( WATER_HEATER_DOMAIN, SERVICE_SET_OPERATION_MODE, From 086ce2f9004e913ee1cddb609cd9766740fdfffd Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Tue, 30 Jun 2026 18:00:13 +0200 Subject: [PATCH 33/66] Update NL translation --- custom_components/plugwise/translations/nl.json | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/custom_components/plugwise/translations/nl.json b/custom_components/plugwise/translations/nl.json index 0c7687071..6fdfc7d50 100644 --- a/custom_components/plugwise/translations/nl.json +++ b/custom_components/plugwise/translations/nl.json @@ -298,6 +298,17 @@ }, "dhw_temperature": { "name": "SWW temperatuur" + "state_attributes": { + "dhw_modes": { + "state": { + "auto": "Auto", + "boost": "Boost", + "comfort": "Comfort", + "eco": "Eco", + "off": "Uit" + } + } + } } } }, From a5605f74101e2a31713038c1f9b5d65972d5290d Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Tue, 30 Jun 2026 18:44:50 +0200 Subject: [PATCH 34/66] Correct nl.json --- custom_components/plugwise/translations/nl.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/plugwise/translations/nl.json b/custom_components/plugwise/translations/nl.json index 6fdfc7d50..2bccdbeae 100644 --- a/custom_components/plugwise/translations/nl.json +++ b/custom_components/plugwise/translations/nl.json @@ -297,7 +297,7 @@ "name": "Boiler temperatuur" }, "dhw_temperature": { - "name": "SWW temperatuur" + "name": "SWW temperatuur", "state_attributes": { "dhw_modes": { "state": { From 2906fe7beb9dbe58a7d754b17697dce0a72af869 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Wed, 1 Jul 2026 08:22:45 +0200 Subject: [PATCH 35/66] Clean up after rebase --- custom_components/plugwise/water_heater.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/custom_components/plugwise/water_heater.py b/custom_components/plugwise/water_heater.py index 55498795a..5beb8c20b 100644 --- a/custom_components/plugwise/water_heater.py +++ b/custom_components/plugwise/water_heater.py @@ -103,8 +103,6 @@ def __init__( """Initialise the water_heater.""" super().__init__(coordinator, device_id) self.entity_description = description - entity_name = f"{self.device[ATTR_NAME]}".lower() - self._attr_unique_id = f"{device_id}-{entity_name}" temp_data = self.device.get(description.key, {}) if temp_data: self._attr_max_temp = temp_data.get(UPPER_BOUND, 75.0) From d67f05e8145032a82ffabff74e53cbb9145e6ca2 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Fri, 3 Jul 2026 20:04:00 +0200 Subject: [PATCH 36/66] Add async_turn_off()/on() functions --- custom_components/plugwise/water_heater.py | 35 ++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/custom_components/plugwise/water_heater.py b/custom_components/plugwise/water_heater.py index 5beb8c20b..d2c5857e0 100644 --- a/custom_components/plugwise/water_heater.py +++ b/custom_components/plugwise/water_heater.py @@ -10,6 +10,7 @@ ) from homeassistant.const import ( ATTR_TEMPERATURE, + STATE_OFF, STATE_ON, EntityCategory, UnitOfTemperature, @@ -112,6 +113,9 @@ def __init__( self._attr_supported_features |= WaterHeaterEntityFeature.OPERATION_MODE self._attr_temperature_unit = UnitOfTemperature.CELSIUS self._attr_unique_id = f"{device_id}-{description.key}" + self._list_type = 0 + self._mode_off = self.device.get(DHW_MODE) == STATE_OFF + self._operation_mode: str | None = None @property @override @@ -149,8 +153,17 @@ async def async_set_operation_mode(self, operation_mode: str) -> None: if self.operation_list is None: return # pragma: no cover - list_type: int = len(self.operation_list) - await self.coordinator.api.set_dhw_mode(DHW_MODE, self._dev_id, list_type, operation_mode) + self._list_type = len(self.operation_list) + self._operation_mode = operation_mode + if self._operation_mode == STATE_OFF and not self._mode_off: + await self.async_turn_off() + return + + if self._mode_off and self._operation_mode != STATE_OFF: + await self.async_turn_on() + return + + await self.coordinator.api.set_dhw_mode(DHW_MODE, self._dev_id, self._list_type, self._operation_mode) @plugwise_command @override @@ -162,3 +175,21 @@ async def async_set_temperature(self, **kwargs: Any) -> None: self.entity_description.key, float(temperature), ) + + @plugwise_command + @override + async def async_turn_off(self, **kwargs: Any) -> None: + """Turn the water_heater off.""" + await self.coordinator.api.set_dhw_mode( + DHW_MODE, self._dev_id, self._list_type, STATE_OFF + ) + self._mode_off = True + + @plugwise_command + @override + async def async_turn_on(self, **kwargs: Any) -> None: + """Turn the water_heater on and set the operation mode.""" + await self.coordinator.api.set_dhw_mode( + DHW_MODE, self._dev_id, self._list_type, self._operation_mode + ) + self._mode_off = False From ffbda55ef91f9b58fff7e881381dafc7e10cff90 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sat, 4 Jul 2026 08:37:02 +0200 Subject: [PATCH 37/66] Fix typing --- custom_components/plugwise/water_heater.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/plugwise/water_heater.py b/custom_components/plugwise/water_heater.py index d2c5857e0..d90552062 100644 --- a/custom_components/plugwise/water_heater.py +++ b/custom_components/plugwise/water_heater.py @@ -115,7 +115,7 @@ def __init__( self._attr_unique_id = f"{device_id}-{description.key}" self._list_type = 0 self._mode_off = self.device.get(DHW_MODE) == STATE_OFF - self._operation_mode: str | None = None + self._operation_mode: str = STATE_OFF @property @override From 5c54515bcd7fc7929e4103a56b55da14a75dfd81 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sat, 4 Jul 2026 08:50:22 +0200 Subject: [PATCH 38/66] Add Anna-Loria test fixture --- .../anna_loria_cooling_active/data.json | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 tests/components/plugwise/fixtures/anna_loria_cooling_active/data.json diff --git a/tests/components/plugwise/fixtures/anna_loria_cooling_active/data.json b/tests/components/plugwise/fixtures/anna_loria_cooling_active/data.json new file mode 100644 index 000000000..13c3b2432 --- /dev/null +++ b/tests/components/plugwise/fixtures/anna_loria_cooling_active/data.json @@ -0,0 +1,111 @@ +{ + "582dfbdace4d4aeb832923ce7d1ddda0": { + "active_preset": "home", + "available_schedules": [ + "Winter", + "Test ", + "off" + ], + "climate_mode": "auto", + "control_state": "cooling", + "dev_class": "thermostat", + "firmware": "2018-02-08T11:15:53+01:00", + "hardware": "6539-1301-5002", + "location": "15da035090b847e7a21f93e08c015ebc", + "model": "ThermoTouch", + "name": "Anna", + "preset_modes": [ + "away", + "vacation", + "no_frost", + "home", + "asleep" + ], + "select_schedule": "Winter", + "sensors": { + "illuminance": 45.0, + "setpoint_high": 23.5, + "setpoint_low": 4.0, + "temperature": 24.1 + }, + "temperature_offset": { + "lower_bound": -2.0, + "resolution": 0.1, + "setpoint": 0.0, + "upper_bound": 2.0 + }, + "thermostat": { + "lower_bound": 4.0, + "resolution": 0.1, + "setpoint_high": 23.5, + "setpoint_low": 4.0, + "upper_bound": 30.0 + }, + "vendor": "Plugwise" + }, + "9ff0569b4984459fb243af64c0901894": { + "binary_sensors": { + "plugwise_notification": false + }, + "dev_class": "gateway", + "firmware": "4.3.8", + "hardware": "AME Smile 2.0 board", + "location": "674b657c138a41a291d315d7471deb06", + "mac_address": "C493000278E2", + "model": "Gateway", + "model_id": "smile_thermo", + "name": "Smile Anna", + "notifications": {}, + "sensors": { + "outdoor_temperature": 15.5 + }, + "vendor": "Plugwise" + }, + "bfb5ee0a88e14e5f97bfa725a760cc49": { + "available": true, + "binary_sensors": { + "cooling_enabled": true, + "cooling_state": true, + "dhw_state": false, + "flame_state": false, + "heating_state": false + }, + "boiler_temperature": { + "current": 25.3, + "lower_bound": 25.0, + "resolution": 0.01, + "setpoint": 40.0, + "upper_bound": 45.0 + }, + "dev_class": "heater_central", + "dhw_mode": "auto", + "dhw_modes": [ + "off", + "auto", + "boost", + "eco", + "comfort" + ], + "dhw_temperature": { + "current": 52.9, + "lower_bound": 35.0, + "resolution": 0.01, + "setpoint": 53.0, + "upper_bound": 60.0 + }, + "location": "674b657c138a41a291d315d7471deb06", + "model": "Generic heater/cooler", + "model_id": "173", + "name": "OpenTherm", + "sensors": { + "intended_boiler_temperature": 0.0, + "modulation_level": 100, + "outdoor_air_temperature": 17.2, + "return_temperature": 26.3 + }, + "switches": { + "cooling_ena_switch": true + }, + "vendor": "Atlantic" + } +} From ddd2ca5bfdef59c6a85fa03fc54f918b6d53214c Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sat, 4 Jul 2026 08:55:36 +0200 Subject: [PATCH 39/66] Save updated shapshot --- .../plugwise/snapshots/test_water_heater.ambr | 46 +++++++++++-------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/tests/components/plugwise/snapshots/test_water_heater.ambr b/tests/components/plugwise/snapshots/test_water_heater.ambr index 0d4c3a827..0311ec93d 100644 --- a/tests/components/plugwise/snapshots/test_water_heater.ambr +++ b/tests/components/plugwise/snapshots/test_water_heater.ambr @@ -128,15 +128,15 @@ 'state': 'eco', }) # --- -# name: test_anna_water_heater_snapshot[platforms0-False-anna_v4_dhw][water_heater.opentherm_boiler_temperature-entry] +# name: test_anna_water_heater_snapshot[platforms0-False-anna_loria_cooling_active][water_heater.opentherm_boiler_temperature-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ None, ]), 'area_id': None, 'capabilities': dict({ - : 100.0, - : 0.0, + : 45.0, + : 25.0, }), 'config_entry_id': , 'config_subentry_id': , @@ -164,21 +164,21 @@ 'suggested_object_id': None, 'supported_features': , 'translation_key': 'boiler_temperature', - 'unique_id': 'cd0e6156b1f04d5f952349ffbe397481-boiler_temperature', + 'unique_id': 'bfb5ee0a88e14e5f97bfa725a760cc49-boiler_temperature', 'unit_of_measurement': None, }) # --- -# name: test_anna_water_heater_snapshot[platforms0-False-anna_v4_dhw][water_heater.opentherm_boiler_temperature-state] +# name: test_anna_water_heater_snapshot[platforms0-False-anna_loria_cooling_active][water_heater.opentherm_boiler_temperature-state] StateSnapshot({ 'attributes': ReadOnlyDict({ - : 45.0, + : 25.3, : 'OpenTherm Boiler temperature', - : 100.0, - : 0.0, + : 45.0, + : 25.0, : , : None, : None, - : 70.0, + : 40.0, }), 'context': , 'entity_id': 'water_heater.opentherm_boiler_temperature', @@ -188,7 +188,7 @@ 'state': 'on', }) # --- -# name: test_anna_water_heater_snapshot[platforms0-False-anna_v4_dhw][water_heater.opentherm_dhw_temperature-entry] +# name: test_anna_water_heater_snapshot[platforms0-False-anna_loria_cooling_active][water_heater.opentherm_dhw_temperature-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ None, @@ -196,10 +196,13 @@ 'area_id': None, 'capabilities': dict({ : 60.0, - : 30.0, + : 35.0, : list([ - 'comfort', + 'off', + 'auto', + 'boost', 'eco', + 'comfort', ]), }), 'config_entry_id': , @@ -228,32 +231,35 @@ 'suggested_object_id': None, 'supported_features': , 'translation_key': 'dhw_temperature', - 'unique_id': 'cd0e6156b1f04d5f952349ffbe397481-dhw_temperature', + 'unique_id': 'bfb5ee0a88e14e5f97bfa725a760cc49-dhw_temperature', 'unit_of_measurement': None, }) # --- -# name: test_anna_water_heater_snapshot[platforms0-False-anna_v4_dhw][water_heater.opentherm_dhw_temperature-state] +# name: test_anna_water_heater_snapshot[platforms0-False-anna_loria_cooling_active][water_heater.opentherm_dhw_temperature-state] StateSnapshot({ 'attributes': ReadOnlyDict({ - : 45.0, + : 52.9, : 'OpenTherm DHW temperature', : 60.0, - : 30.0, + : 35.0, : list([ - 'comfort', + 'off', + 'auto', + 'boost', 'eco', + 'comfort', ]), - : 'eco', + : 'auto', : , : None, : None, - : 60.0, + : 53.0, }), 'context': , 'entity_id': 'water_heater.opentherm_dhw_temperature', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'eco', + 'state': 'auto', }) # --- From 259ad4db31352ae5edc18cc637e396bb61a4ea8b Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sat, 4 Jul 2026 09:00:17 +0200 Subject: [PATCH 40/66] Add testcase setting dhw_mode to off --- .../components/plugwise/test_water_heater.py | 46 +++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/tests/components/plugwise/test_water_heater.py b/tests/components/plugwise/test_water_heater.py index 21db7d29a..d4c98066f 100644 --- a/tests/components/plugwise/test_water_heater.py +++ b/tests/components/plugwise/test_water_heater.py @@ -1,9 +1,10 @@ """Tests for the Plugwise water_heater platform.""" - -from unittest.mock import MagicMock +from datetime import timedelta +from unittest.mock import MagicMock, patch import pytest +from freezegun.api import FrozenDateTimeFactory from homeassistant.components.water_heater import ( ATTR_OPERATION_MODE, DOMAIN as WATER_HEATER_DOMAIN, @@ -16,7 +17,7 @@ from homeassistant.helpers import entity_registry as er from syrupy.assertion import SnapshotAssertion -from tests.common import MockConfigEntry, snapshot_platform +from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform HA_PLUGWISE_SMILE_ASYNC_UPDATE = ( "homeassistant.components.plugwise.coordinator.Smile.async_update" @@ -84,3 +85,42 @@ async def test_anna_water_heater_snapshot( ) -> None: """Test Anna water_heater snapshot with dhw_state on.""" await snapshot_platform(hass, entity_registry, snapshot, setup_platform.entry_id) + + +@pytest.mark.parametrize("chosen_env", ["anna_loria_cooling_active"], indirect=True) +@pytest.mark.parametrize("cooling_present", [False], indirect=True) +async def test_anna_water_heater_mode_change( + hass: HomeAssistant, + mock_smile_anna: MagicMock, + init_integration: MockConfigEntry, + freezer: FrozenDateTimeFactory, +) -> None: + """Test Anna water_heater dhw_mode changes.""" + await hass.services.async_call( + WATER_HEATER_DOMAIN, + SERVICE_SET_OPERATION_MODE, + {ATTR_ENTITY_ID: "water_heater.opentherm_dhw_temperature", ATTR_OPERATION_MODE: "off"}, + blocking=True, + ) + assert mock_smile_anna.set_dhw_mode.call_count == 1 + mock_smile_anna.set_dhw_mode.assert_called_with( + "dhw_mode", "bfb5ee0a88e14e5f97bfa725a760cc49", 5, "off" + ) + + data = mock_smile_anna.async_update.return_value + data["bfb5ee0a88e14e5f97bfa725a760cc49"]["dhw_mode"] = "off" + with patch(HA_PLUGWISE_SMILE_ASYNC_UPDATE, return_value=data): + freezer.tick(timedelta(minutes=1)) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + await hass.services.async_call( + WATER_HEATER_DOMAIN, + SERVICE_SET_OPERATION_MODE, + {ATTR_ENTITY_ID: "water_heater.opentherm_dhw_temperature", ATTR_OPERATION_MODE: "boost"}, + blocking=True, + ) + assert mock_smile_anna.set_dhw_mode.call_count == 2 + mock_smile_anna.set_dhw_mode.assert_called_with( + "dhw_mode", "bfb5ee0a88e14e5f97bfa725a760cc49", 5, "boost" + ) From 359c2eac0c1ed493bb87462e537ba1a779fd92a2 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sat, 4 Jul 2026 18:51:38 +0200 Subject: [PATCH 41/66] Reorder --- custom_components/plugwise/water_heater.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/custom_components/plugwise/water_heater.py b/custom_components/plugwise/water_heater.py index d90552062..424e32cb0 100644 --- a/custom_components/plugwise/water_heater.py +++ b/custom_components/plugwise/water_heater.py @@ -165,17 +165,6 @@ async def async_set_operation_mode(self, operation_mode: str) -> None: await self.coordinator.api.set_dhw_mode(DHW_MODE, self._dev_id, self._list_type, self._operation_mode) - @plugwise_command - @override - async def async_set_temperature(self, **kwargs: Any) -> None: - """Set new target temperature.""" - if (temperature := kwargs.get(ATTR_TEMPERATURE)) is not None: - await self.coordinator.api.set_number( - self._dev_id, - self.entity_description.key, - float(temperature), - ) - @plugwise_command @override async def async_turn_off(self, **kwargs: Any) -> None: @@ -193,3 +182,14 @@ async def async_turn_on(self, **kwargs: Any) -> None: DHW_MODE, self._dev_id, self._list_type, self._operation_mode ) self._mode_off = False + + @plugwise_command + @override + async def async_set_temperature(self, **kwargs: Any) -> None: + """Set new target temperature.""" + if (temperature := kwargs.get(ATTR_TEMPERATURE)) is not None: + await self.coordinator.api.set_number( + self._dev_id, + self.entity_description.key, + float(temperature), + ) From a172854460060d430e88ffea4792fa5559a6c762 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Mon, 6 Jul 2026 08:09:13 +0200 Subject: [PATCH 42/66] Bump plugwise to v1.13.0 --- custom_components/plugwise/manifest.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/custom_components/plugwise/manifest.json b/custom_components/plugwise/manifest.json index 23e5c8a65..1b35472bf 100644 --- a/custom_components/plugwise/manifest.json +++ b/custom_components/plugwise/manifest.json @@ -7,9 +7,7 @@ "integration_type": "hub", "iot_class": "local_polling", "loggers": ["plugwise"], - "requirements": [ - "plugwise@git+https://github.com/plugwise/python-plugwise.git@water_heater_2" - ], + "requirements": ["plugwise==1.13.0"], "version": "0.65.0", "zeroconf": ["_plugwise._tcp.local."] } From 605da173bdf255fa28714a4c2f7373b6c63a27f4 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Tue, 7 Jul 2026 18:48:14 +0200 Subject: [PATCH 43/66] Save corrected test-fixtures --- tests/components/plugwise/fixtures/m_adam_heating/data.json | 2 +- .../plugwise/fixtures/m_adam_heating_off_schedule/data.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/components/plugwise/fixtures/m_adam_heating/data.json b/tests/components/plugwise/fixtures/m_adam_heating/data.json index ad2fb4df1..4f49075d6 100644 --- a/tests/components/plugwise/fixtures/m_adam_heating/data.json +++ b/tests/components/plugwise/fixtures/m_adam_heating/data.json @@ -14,6 +14,7 @@ "upper_bound": 95.0 }, "dev_class": "heater_central", + "dhw_mode": "eco", "dhw_modes": [ "comfort", "eco" @@ -28,7 +29,6 @@ "location": "bc93488efab249e5bc54fd7e175a6f91", "model": "Generic heater", "name": "OpenTherm", - "select_dhw_mode": "eco", "sensors": { "intended_boiler_temperature": 38.1 } diff --git a/tests/components/plugwise/fixtures/m_adam_heating_off_schedule/data.json b/tests/components/plugwise/fixtures/m_adam_heating_off_schedule/data.json index 9b2b1b245..508ea9aad 100644 --- a/tests/components/plugwise/fixtures/m_adam_heating_off_schedule/data.json +++ b/tests/components/plugwise/fixtures/m_adam_heating_off_schedule/data.json @@ -14,6 +14,7 @@ "upper_bound": 95.0 }, "dev_class": "heater_central", + "dhw_mode": "eco", "dhw_modes": [ "comfort", "eco" @@ -28,7 +29,6 @@ "location": "bc93488efab249e5bc54fd7e175a6f91", "model": "Generic heater", "name": "OpenTherm", - "select_dhw_mode": "eco", "sensors": { "intended_boiler_temperature": 0.0 } From 5b481ebd5a38ba9ec04a4297e427f16c249d2e4d Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Tue, 7 Jul 2026 18:59:38 +0200 Subject: [PATCH 44/66] Correct select determination method --- custom_components/plugwise/select.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/plugwise/select.py b/custom_components/plugwise/select.py index 329e42ae4..431a5af9e 100644 --- a/custom_components/plugwise/select.py +++ b/custom_components/plugwise/select.py @@ -101,7 +101,7 @@ def _add_entities() -> None: for device_id in coordinator.new_devices: device = coordinator.data[device_id] for description in SELECT_TYPES: - if device.get(description.options_key): + if description.key in device: entities.append( PlugwiseSelectEntity(coordinator, device_id, description) ) From b0043452e295d99fe2e1e18a3d969730c163136e Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Tue, 7 Jul 2026 19:11:47 +0200 Subject: [PATCH 45/66] Correct test-asserts --- tests/components/plugwise/test_init.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/components/plugwise/test_init.py b/tests/components/plugwise/test_init.py index 1eeebf2eb..4f13812b5 100644 --- a/tests/components/plugwise/test_init.py +++ b/tests/components/plugwise/test_init.py @@ -318,7 +318,7 @@ async def test_update_device( assert ( len(er.async_entries_for_config_entry(entity_registry, mock_config_entry.entry_id)) - == 52 + == 51 ) assert ( len(dr.async_entries_for_config_entry(device_registry, mock_config_entry.entry_id)) @@ -342,7 +342,7 @@ async def test_update_device( assert ( len(er.async_entries_for_config_entry(entity_registry, mock_config_entry.entry_id)) - == 59 + == 58 ) assert ( len(dr.async_entries_for_config_entry(device_registry, mock_config_entry.entry_id)) @@ -369,7 +369,7 @@ async def test_update_device( assert ( len(er.async_entries_for_config_entry(entity_registry, mock_config_entry.entry_id)) - == 52 + == 51 ) assert ( len(dr.async_entries_for_config_entry(device_registry, mock_config_entry.entry_id)) From 028df64415fac864a2578e256a33f0f76916c207 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Tue, 7 Jul 2026 19:19:40 +0200 Subject: [PATCH 46/66] Change select detection to cater for select_dhw_mode is None --- custom_components/plugwise/select.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/plugwise/select.py b/custom_components/plugwise/select.py index 431a5af9e..6bef99bf4 100644 --- a/custom_components/plugwise/select.py +++ b/custom_components/plugwise/select.py @@ -101,7 +101,7 @@ def _add_entities() -> None: for device_id in coordinator.new_devices: device = coordinator.data[device_id] for description in SELECT_TYPES: - if description.key in device: + if device.get(description.key) is not None: entities.append( PlugwiseSelectEntity(coordinator, device_id, description) ) From e0a9c465044369f23cdb89fdb589fc0004e6ff09 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Fri, 31 Jul 2026 20:09:24 +0200 Subject: [PATCH 47/66] Link to latest plugwise test-version --- custom_components/plugwise/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/plugwise/manifest.json b/custom_components/plugwise/manifest.json index 1b35472bf..bde291ea4 100644 --- a/custom_components/plugwise/manifest.json +++ b/custom_components/plugwise/manifest.json @@ -7,7 +7,7 @@ "integration_type": "hub", "iot_class": "local_polling", "loggers": ["plugwise"], - "requirements": ["plugwise==1.13.0"], + "requirements": ["plugwise@git+https://https://github.com/plugwise/python-plugwise,git@wh-3"], "version": "0.65.0", "zeroconf": ["_plugwise._tcp.local."] } From 578fb5477c86f4ebe4b57f8d9b47664c459852dc Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Fri, 31 Jul 2026 20:12:12 +0200 Subject: [PATCH 48/66] Refresh test-fixtures --- .../fixtures/adam_plus_anna_new/data.json | 14 +++++---- .../fixtures/anna_heatpump_heating/data.json | 11 +++++-- .../anna_loria_cooling_active/data.json | 11 ++++--- .../plugwise/fixtures/anna_p1/data.json | 7 +++-- .../plugwise/fixtures/anna_v4/data.json | 10 +++++-- .../plugwise/fixtures/anna_v4_dhw/data.json | 10 +++++-- .../plugwise/fixtures/legacy_anna/data.json | 13 ++++---- .../fixtures/m_adam_cooling/data.json | 14 +++++---- .../fixtures/m_adam_heating/data.json | 14 +++++---- .../m_adam_heating_off_schedule/data.json | 14 +++++---- .../plugwise/fixtures/m_adam_jip/data.json | 30 +++++++++++++------ .../data.json | 16 +++++----- .../m_anna_heatpump_cooling/data.json | 11 +++++-- 13 files changed, 115 insertions(+), 60 deletions(-) diff --git a/tests/components/plugwise/fixtures/adam_plus_anna_new/data.json b/tests/components/plugwise/fixtures/adam_plus_anna_new/data.json index 1f0aa4196..b8a9161c0 100644 --- a/tests/components/plugwise/fixtures/adam_plus_anna_new/data.json +++ b/tests/components/plugwise/fixtures/adam_plus_anna_new/data.json @@ -23,7 +23,11 @@ "name": "OpenTherm", "select_dhw_mode": "eco", "sensors": { - "intended_boiler_temperature": 22.5 + "intended_boiler_temperature": 22.5, + "water_temperature": 43.0 + }, + "switches": { + "dhw_cm_switch": false } }, "10016900610d4c7481df78c89606ef22": { @@ -298,11 +302,11 @@ "f2bf9048bef64cc5b6d5110154e33c81": { "active_preset": "home", "available_schedules": [ + "off", "Badkamer", "Vakantie", "Weekschema", - "Test", - "off" + "Test" ], "climate_mode": "auto", "control_state": "heating", @@ -347,11 +351,11 @@ "f871b8c4d63549319221e294e4f88074": { "active_preset": "vacation", "available_schedules": [ + "off", "Badkamer", "Vakantie", "Weekschema", - "Test", - "off" + "Test" ], "climate_mode": "heat", "control_state": "idle", diff --git a/tests/components/plugwise/fixtures/anna_heatpump_heating/data.json b/tests/components/plugwise/fixtures/anna_heatpump_heating/data.json index 53b710551..c63972711 100644 --- a/tests/components/plugwise/fixtures/anna_heatpump_heating/data.json +++ b/tests/components/plugwise/fixtures/anna_heatpump_heating/data.json @@ -52,19 +52,24 @@ "model": "Generic heater/cooler", "name": "OpenTherm", "sensors": { + "dhw_temperature": 46.3, "intended_boiler_temperature": 35.0, "modulation_level": 52, "outdoor_air_temperature": 3.0, "return_temperature": 25.1, - "water_pressure": 1.57 + "water_pressure": 1.57, + "water_temperature": 29.1 + }, + "switches": { + "dhw_cm_switch": false }, "vendor": "Techneco" }, "3cb70739631c4d17a86b8b12e8a5161b": { "active_preset": "home", "available_schedules": [ - "standaard", - "off" + "off", + "standaard" ], "climate_mode": "auto", "control_state": "heating", diff --git a/tests/components/plugwise/fixtures/anna_loria_cooling_active/data.json b/tests/components/plugwise/fixtures/anna_loria_cooling_active/data.json index 13c3b2432..1dadad338 100644 --- a/tests/components/plugwise/fixtures/anna_loria_cooling_active/data.json +++ b/tests/components/plugwise/fixtures/anna_loria_cooling_active/data.json @@ -2,9 +2,9 @@ "582dfbdace4d4aeb832923ce7d1ddda0": { "active_preset": "home", "available_schedules": [ + "off", "Winter", - "Test ", - "off" + "Test " ], "climate_mode": "auto", "control_state": "cooling", @@ -98,13 +98,16 @@ "model_id": "173", "name": "OpenTherm", "sensors": { + "dhw_temperature": 52.9, "intended_boiler_temperature": 0.0, "modulation_level": 100, "outdoor_air_temperature": 17.2, - "return_temperature": 26.3 + "return_temperature": 26.3, + "water_temperature": 25.3 }, "switches": { - "cooling_ena_switch": true + "cooling_ena_switch": true, + "dhw_cm_switch": true }, "vendor": "Atlantic" } diff --git a/tests/components/plugwise/fixtures/anna_p1/data.json b/tests/components/plugwise/fixtures/anna_p1/data.json index 4a7f5aa03..cd637d48e 100644 --- a/tests/components/plugwise/fixtures/anna_p1/data.json +++ b/tests/components/plugwise/fixtures/anna_p1/data.json @@ -2,8 +2,8 @@ "1e5e55b958ac445583602f767cb45942": { "active_preset": "home", "available_schedules": [ - "Thermostat schedule", - "off" + "off", + "Thermostat schedule" ], "climate_mode": "heat", "control_state": "idle", @@ -63,6 +63,9 @@ "water_pressure": 6.0, "water_temperature": 35.0 }, + "switches": { + "dhw_cm_switch": true + }, "vendor": "Intergas" }, "53130847be2f436cb946b78dedb9053a": { diff --git a/tests/components/plugwise/fixtures/anna_v4/data.json b/tests/components/plugwise/fixtures/anna_v4/data.json index cecb3e0a8..e2c75ed6c 100644 --- a/tests/components/plugwise/fixtures/anna_v4/data.json +++ b/tests/components/plugwise/fixtures/anna_v4/data.json @@ -2,9 +2,9 @@ "01b85360fdd243d0aaad4d6ac2a5ba7e": { "active_preset": "home", "available_schedules": [ + "off", "Standaard", - "Thuiswerken", - "off" + "Thuiswerken" ], "climate_mode": "heat", "control_state": "heating", @@ -94,7 +94,11 @@ "intended_boiler_temperature": 39.9, "modulation_level": 0.0, "return_temperature": 32.0, - "water_pressure": 2.2 + "water_pressure": 2.2, + "water_temperature": 45.0 + }, + "switches": { + "dhw_cm_switch": false }, "vendor": "Bosch Thermotechniek B.V." } diff --git a/tests/components/plugwise/fixtures/anna_v4_dhw/data.json b/tests/components/plugwise/fixtures/anna_v4_dhw/data.json index 01c6bb25d..0a8fb6035 100644 --- a/tests/components/plugwise/fixtures/anna_v4_dhw/data.json +++ b/tests/components/plugwise/fixtures/anna_v4_dhw/data.json @@ -2,9 +2,9 @@ "01b85360fdd243d0aaad4d6ac2a5ba7e": { "active_preset": "home", "available_schedules": [ + "off", "Standaard", - "Thuiswerken", - "off" + "Thuiswerken" ], "climate_mode": "heat", "control_state": "idle", @@ -94,7 +94,11 @@ "intended_boiler_temperature": 39.9, "modulation_level": 0.0, "return_temperature": 32.0, - "water_pressure": 2.2 + "water_pressure": 2.2, + "water_temperature": 45.0 + }, + "switches": { + "dhw_cm_switch": false }, "vendor": "Bosch Thermotechniek B.V." } diff --git a/tests/components/plugwise/fixtures/legacy_anna/data.json b/tests/components/plugwise/fixtures/legacy_anna/data.json index f4a30b8fa..0947da8c0 100644 --- a/tests/components/plugwise/fixtures/legacy_anna/data.json +++ b/tests/components/plugwise/fixtures/legacy_anna/data.json @@ -13,14 +13,15 @@ "flame_state": true, "heating_state": true }, - "dev_class": "heater_central", - "location": "0000aaaa0000aaaa0000aaaa0000aa00", - "maximum_boiler_temperature": { + "boiler_temperature": { + "current": 23.6, "lower_bound": 50.0, "resolution": 1.0, "setpoint": 50.0, "upper_bound": 90.0 }, + "dev_class": "heater_central", + "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Generic heater", "name": "OpenTherm", "sensors": { @@ -35,7 +36,9 @@ }, "0d266432d64443e283b5d708ae98b455": { "active_preset": "home", - "available_schedules": [], + "available_schedules": [ + "off" + ], "climate_mode": "heat", "control_state": "heating", "dev_class": "thermostat", @@ -51,7 +54,7 @@ "home", "no_frost" ], - "select_schedule": null, + "select_schedule": "off", "sensors": { "illuminance": 150.8, "setpoint": 20.5, diff --git a/tests/components/plugwise/fixtures/m_adam_cooling/data.json b/tests/components/plugwise/fixtures/m_adam_cooling/data.json index 6aaec3e90..539853029 100644 --- a/tests/components/plugwise/fixtures/m_adam_cooling/data.json +++ b/tests/components/plugwise/fixtures/m_adam_cooling/data.json @@ -24,7 +24,11 @@ "name": "OpenTherm", "select_dhw_mode": "eco", "sensors": { - "intended_boiler_temperature": 17.5 + "intended_boiler_temperature": 17.5, + "water_temperature": 19.0 + }, + "switches": { + "dhw_cm_switch": false } }, "14df5c4dc8cb4ba69f9d1ac0eaf7c5c6": { @@ -209,11 +213,11 @@ "f2bf9048bef64cc5b6d5110154e33c81": { "active_preset": "home", "available_schedules": [ + "off", "Badkamer", "Vakantie", "Weekschema", - "Test", - "off" + "Test" ], "climate_mode": "cool", "control_state": "cooling", @@ -258,11 +262,11 @@ "f871b8c4d63549319221e294e4f88074": { "active_preset": "vacation", "available_schedules": [ + "off", "Badkamer", "Vakantie", "Weekschema", - "Test", - "off" + "Test" ], "climate_mode": "auto", "control_state": "cooling", diff --git a/tests/components/plugwise/fixtures/m_adam_heating/data.json b/tests/components/plugwise/fixtures/m_adam_heating/data.json index 4f49075d6..2f9688f9c 100644 --- a/tests/components/plugwise/fixtures/m_adam_heating/data.json +++ b/tests/components/plugwise/fixtures/m_adam_heating/data.json @@ -30,7 +30,11 @@ "model": "Generic heater", "name": "OpenTherm", "sensors": { - "intended_boiler_temperature": 38.1 + "intended_boiler_temperature": 38.1, + "water_temperature": 37.0 + }, + "switches": { + "dhw_cm_switch": false } }, "14df5c4dc8cb4ba69f9d1ac0eaf7c5c6": { @@ -214,11 +218,11 @@ "f2bf9048bef64cc5b6d5110154e33c81": { "active_preset": "home", "available_schedules": [ + "off", "Badkamer", "Vakantie", "Weekschema", - "Test", - "off" + "Test" ], "climate_mode": "heat", "control_state": "preheating", @@ -263,11 +267,11 @@ "f871b8c4d63549319221e294e4f88074": { "active_preset": "vacation", "available_schedules": [ + "off", "Badkamer", "Vakantie", "Weekschema", - "Test", - "off" + "Test" ], "climate_mode": "auto", "control_state": "idle", diff --git a/tests/components/plugwise/fixtures/m_adam_heating_off_schedule/data.json b/tests/components/plugwise/fixtures/m_adam_heating_off_schedule/data.json index 508ea9aad..9e034f415 100644 --- a/tests/components/plugwise/fixtures/m_adam_heating_off_schedule/data.json +++ b/tests/components/plugwise/fixtures/m_adam_heating_off_schedule/data.json @@ -30,7 +30,11 @@ "model": "Generic heater", "name": "OpenTherm", "sensors": { - "intended_boiler_temperature": 0.0 + "intended_boiler_temperature": 0.0, + "water_temperature": 37.0 + }, + "switches": { + "dhw_cm_switch": false } }, "14df5c4dc8cb4ba69f9d1ac0eaf7c5c6": { @@ -214,11 +218,11 @@ "f2bf9048bef64cc5b6d5110154e33c81": { "active_preset": "home", "available_schedules": [ + "off", "Badkamer", "Vakantie", "Weekschema", - "Test", - "off" + "Test" ], "climate_mode": "off", "control_state": "idle", @@ -263,11 +267,11 @@ "f871b8c4d63549319221e294e4f88074": { "active_preset": "vacation", "available_schedules": [ + "off", "Badkamer", "Vakantie", "Weekschema", - "Test", - "off" + "Test" ], "climate_mode": "off", "control_state": "idle", diff --git a/tests/components/plugwise/fixtures/m_adam_jip/data.json b/tests/components/plugwise/fixtures/m_adam_jip/data.json index 28867a99d..793498bb1 100644 --- a/tests/components/plugwise/fixtures/m_adam_jip/data.json +++ b/tests/components/plugwise/fixtures/m_adam_jip/data.json @@ -1,7 +1,9 @@ { "06aecb3d00354375924f50c47af36bd2": { "active_preset": "no_frost", - "available_schedules": [], + "available_schedules": [ + "off" + ], "climate_mode": "off", "dev_class": "climate", "model": "ThermoZone", @@ -13,7 +15,7 @@ "vacation", "no_frost" ], - "select_schedule": null, + "select_schedule": "off", "select_zone_profile": "active", "sensors": { "temperature": 24.2 @@ -41,7 +43,9 @@ }, "13228dab8ce04617af318a2888b3c548": { "active_preset": "home", - "available_schedules": [], + "available_schedules": [ + "off" + ], "climate_mode": "heat", "control_state": "idle", "dev_class": "climate", @@ -54,7 +58,7 @@ "vacation", "no_frost" ], - "select_schedule": null, + "select_schedule": "off", "select_zone_profile": "active", "sensors": { "temperature": 27.4 @@ -281,7 +285,9 @@ }, "d27aede973b54be484f6842d1b2802ad": { "active_preset": "home", - "available_schedules": [], + "available_schedules": [ + "off" + ], "climate_mode": "heat", "control_state": "idle", "dev_class": "climate", @@ -294,7 +300,7 @@ "vacation", "no_frost" ], - "select_schedule": null, + "select_schedule": "off", "select_zone_profile": "active", "sensors": { "temperature": 30.0 @@ -346,7 +352,9 @@ }, "d58fec52899f4f1c92e4f8fad6d8c48c": { "active_preset": "home", - "available_schedules": [], + "available_schedules": [ + "off" + ], "climate_mode": "heat", "control_state": "idle", "dev_class": "climate", @@ -359,7 +367,7 @@ "vacation", "no_frost" ], - "select_schedule": null, + "select_schedule": "off", "select_zone_profile": "active", "sensors": { "temperature": 30.0 @@ -420,7 +428,11 @@ "intended_boiler_temperature": 0.0, "modulation_level": 0.0, "return_temperature": 37.1, - "water_pressure": 1.4 + "water_pressure": 1.4, + "water_temperature": 37.3 + }, + "switches": { + "dhw_cm_switch": false }, "vendor": "Remeha B.V." }, diff --git a/tests/components/plugwise/fixtures/m_adam_multiple_devices_per_zone/data.json b/tests/components/plugwise/fixtures/m_adam_multiple_devices_per_zone/data.json index dff7c2466..b1529e121 100644 --- a/tests/components/plugwise/fixtures/m_adam_multiple_devices_per_zone/data.json +++ b/tests/components/plugwise/fixtures/m_adam_multiple_devices_per_zone/data.json @@ -23,12 +23,12 @@ "08963fec7c53423ca5680aa4cb502c63": { "active_preset": "away", "available_schedules": [ + "off", "CV Roan", "Bios Schema met Film Avond", "GF7 Woonkamer", "Badkamer Schema", - "CV Jessie", - "off" + "CV Jessie" ], "climate_mode": "auto", "control_state": "idle", @@ -64,12 +64,12 @@ "12493538af164a409c6a1c79e38afe1c": { "active_preset": "away", "available_schedules": [ + "off", "CV Roan", "Bios Schema met Film Avond", "GF7 Woonkamer", "Badkamer Schema", - "CV Jessie", - "off" + "CV Jessie" ], "climate_mode": "heat", "control_state": "idle", @@ -278,12 +278,12 @@ "82fa13f017d240daa0d0ea1775420f24": { "active_preset": "asleep", "available_schedules": [ + "off", "CV Roan", "Bios Schema met Film Avond", "GF7 Woonkamer", "Badkamer Schema", - "CV Jessie", - "off" + "CV Jessie" ], "climate_mode": "auto", "control_state": "idle", @@ -433,12 +433,12 @@ "c50f167537524366a5af7aa3942feb1e": { "active_preset": "home", "available_schedules": [ + "off", "CV Roan", "Bios Schema met Film Avond", "GF7 Woonkamer", "Badkamer Schema", - "CV Jessie", - "off" + "CV Jessie" ], "climate_mode": "auto", "control_state": "heating", diff --git a/tests/components/plugwise/fixtures/m_anna_heatpump_cooling/data.json b/tests/components/plugwise/fixtures/m_anna_heatpump_cooling/data.json index 018610533..9b421f792 100644 --- a/tests/components/plugwise/fixtures/m_anna_heatpump_cooling/data.json +++ b/tests/components/plugwise/fixtures/m_anna_heatpump_cooling/data.json @@ -52,19 +52,24 @@ "model": "Generic heater/cooler", "name": "OpenTherm", "sensors": { + "dhw_temperature": 41.5, "intended_boiler_temperature": 0.0, "modulation_level": 40, "outdoor_air_temperature": 28.0, "return_temperature": 23.8, - "water_pressure": 1.57 + "water_pressure": 1.57, + "water_temperature": 22.7 + }, + "switches": { + "dhw_cm_switch": false }, "vendor": "Techneco" }, "3cb70739631c4d17a86b8b12e8a5161b": { "active_preset": "home", "available_schedules": [ - "standaard", - "off" + "off", + "standaard" ], "climate_mode": "auto", "control_state": "cooling", From 7e5126f7b85db5f0e2d3658234eae0c33cd95504 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Fri, 31 Jul 2026 20:16:14 +0200 Subject: [PATCH 49/66] Fix manifest.json --- custom_components/plugwise/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/plugwise/manifest.json b/custom_components/plugwise/manifest.json index bde291ea4..67d1ba4fe 100644 --- a/custom_components/plugwise/manifest.json +++ b/custom_components/plugwise/manifest.json @@ -7,7 +7,7 @@ "integration_type": "hub", "iot_class": "local_polling", "loggers": ["plugwise"], - "requirements": ["plugwise@git+https://https://github.com/plugwise/python-plugwise,git@wh-3"], + "requirements": ["plugwise@git+https://github.com/plugwise/python-plugwise.git@wh-3"], "version": "0.65.0", "zeroconf": ["_plugwise._tcp.local."] } From 773429b45098deaf21ab567fe9be618b5be0a52b Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Fri, 31 Jul 2026 20:20:55 +0200 Subject: [PATCH 50/66] Increase len-asserts --- tests/components/plugwise/test_init.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/components/plugwise/test_init.py b/tests/components/plugwise/test_init.py index 4f13812b5..1eeebf2eb 100644 --- a/tests/components/plugwise/test_init.py +++ b/tests/components/plugwise/test_init.py @@ -318,7 +318,7 @@ async def test_update_device( assert ( len(er.async_entries_for_config_entry(entity_registry, mock_config_entry.entry_id)) - == 51 + == 52 ) assert ( len(dr.async_entries_for_config_entry(device_registry, mock_config_entry.entry_id)) @@ -342,7 +342,7 @@ async def test_update_device( assert ( len(er.async_entries_for_config_entry(entity_registry, mock_config_entry.entry_id)) - == 58 + == 59 ) assert ( len(dr.async_entries_for_config_entry(device_registry, mock_config_entry.entry_id)) @@ -369,7 +369,7 @@ async def test_update_device( assert ( len(er.async_entries_for_config_entry(entity_registry, mock_config_entry.entry_id)) - == 51 + == 52 ) assert ( len(dr.async_entries_for_config_entry(device_registry, mock_config_entry.entry_id)) From c370f3f512a7bd09aec4004ceef9b5ce2d6a3bc0 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Fri, 31 Jul 2026 20:23:11 +0200 Subject: [PATCH 51/66] Update legacy_anna no active schedule test --- tests/components/plugwise/test_select.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/components/plugwise/test_select.py b/tests/components/plugwise/test_select.py index 29d43c337..4ca25fda0 100644 --- a/tests/components/plugwise/test_select.py +++ b/tests/components/plugwise/test_select.py @@ -129,7 +129,8 @@ async def test_legacy_anna_select_entities( init_integration: MockConfigEntry, ) -> None: """Test no select-entity for a legacy Anna without schedule.""" - assert not hass.states.get("select.anna_thermostat_schedule") + assert (state := hass.states.get("select.anna_thermostat_schedule")) + assert state.state == "off" @pytest.mark.usefixtures("mock_smile_anna") From 8b677141e833fd9504935c851a0324aaec5ec66f Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sat, 1 Aug 2026 08:51:14 +0200 Subject: [PATCH 52/66] Update water_heater.py --- custom_components/plugwise/water_heater.py | 56 +++++++++------------- 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/custom_components/plugwise/water_heater.py b/custom_components/plugwise/water_heater.py index 424e32cb0..7ecc886b9 100644 --- a/custom_components/plugwise/water_heater.py +++ b/custom_components/plugwise/water_heater.py @@ -1,9 +1,10 @@ """Plugwise water heater component for HomeAssistant.""" from dataclasses import dataclass -from typing import Any, override +from typing import Any, cast, override from homeassistant.components.water_heater import ( + STATE_ECO, WaterHeaterEntity, WaterHeaterEntityDescription, WaterHeaterEntityFeature, @@ -104,18 +105,20 @@ def __init__( """Initialise the water_heater.""" super().__init__(coordinator, device_id) self.entity_description = description - temp_data = self.device.get(description.key, {}) - if temp_data: - self._attr_max_temp = temp_data.get(UPPER_BOUND, 75.0) - self._attr_min_temp = temp_data.get(LOWER_BOUND, 40.0) + self._attr_max_temp = self.device[description.key][UPPER_BOUND] + self._attr_min_temp = self.device[description.key][LOWER_BOUND] self._attr_supported_features = WaterHeaterEntityFeature.TARGET_TEMPERATURE if description.options_key is not None: self._attr_supported_features |= WaterHeaterEntityFeature.OPERATION_MODE + self._attr_target_temperature_step = max( + self.device[description.key]["resolution"], 0.5 + ) self._attr_temperature_unit = UnitOfTemperature.CELSIUS self._attr_unique_id = f"{device_id}-{description.key}" - self._list_type = 0 - self._mode_off = self.device.get(DHW_MODE) == STATE_OFF - self._operation_mode: str = STATE_OFF + dhw_modes = self.device.get(DHW_MODES, []) + self._dhw_modes_count = len(dhw_modes) + if description.options_key is not None and STATE_OFF in dhw_modes: + self._attr_supported_features |= WaterHeaterEntityFeature.ON_OFF @property @override @@ -129,7 +132,7 @@ def current_operation(self) -> str | None: @override def current_temperature(self) -> float | None: """Return the current water temperature.""" - return self.device.get(self.entity_description.key, {}).get("current") + return self.device[self.entity_description.key].get("current") @property @override @@ -144,52 +147,37 @@ def operation_list(self) -> list[str] | None: @override def target_temperature(self) -> float | None: """Return the water temperature we try to reach.""" - return self.device.get(self.entity_description.key, {}).get("setpoint") + return self.device[self.entity_description.key].get("setpoint") @plugwise_command @override async def async_set_operation_mode(self, operation_mode: str) -> None: """Set the operation mode.""" - if self.operation_list is None: - return # pragma: no cover - - self._list_type = len(self.operation_list) - self._operation_mode = operation_mode - if self._operation_mode == STATE_OFF and not self._mode_off: - await self.async_turn_off() - return - - if self._mode_off and self._operation_mode != STATE_OFF: - await self.async_turn_on() - return - - await self.coordinator.api.set_dhw_mode(DHW_MODE, self._dev_id, self._list_type, self._operation_mode) + await self.coordinator.api.set_dhw_mode(DHW_MODE, self._dev_id, operation_mode, self._dhw_modes_count,) @plugwise_command @override async def async_turn_off(self, **kwargs: Any) -> None: """Turn the water_heater off.""" await self.coordinator.api.set_dhw_mode( - DHW_MODE, self._dev_id, self._list_type, STATE_OFF + DHW_MODE, self._dev_id, STATE_OFF, self._dhw_modes_count, ) - self._mode_off = True @plugwise_command @override async def async_turn_on(self, **kwargs: Any) -> None: """Turn the water_heater on and set the operation mode.""" await self.coordinator.api.set_dhw_mode( - DHW_MODE, self._dev_id, self._list_type, self._operation_mode + DHW_MODE, self._dev_id, STATE_ECO self._dhw_modes_count, ) - self._mode_off = False @plugwise_command @override async def async_set_temperature(self, **kwargs: Any) -> None: """Set new target temperature.""" - if (temperature := kwargs.get(ATTR_TEMPERATURE)) is not None: - await self.coordinator.api.set_number( - self._dev_id, - self.entity_description.key, - float(temperature), - ) + temperature = cast(float, kwargs.get(ATTR_TEMPERATURE)) + await self.coordinator.api.set_number( + self._dev_id, + self.entity_description.key, + temperature, + ) From 98c22aa780cdfba0ce76910d1577c5b083799ac0 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sat, 1 Aug 2026 08:54:08 +0200 Subject: [PATCH 53/66] Climate: adapt set_schedule_state() calls --- custom_components/plugwise/climate.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/custom_components/plugwise/climate.py b/custom_components/plugwise/climate.py index a7395a662..f426138d3 100644 --- a/custom_components/plugwise/climate.py +++ b/custom_components/plugwise/climate.py @@ -339,7 +339,7 @@ async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None: if hvac_mode == HVACMode.AUTO: _check_for_schedule(schedule_is_active, self._last_active_schedule) await self._api.set_schedule_state( - self._location, STATE_ON, desired_schedule + self._location, desired_schedule, STATE_ON ) await self._api.set_regulation_mode(self._previous_action_mode) return @@ -347,7 +347,7 @@ async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None: # Transition to manual mode if schedule_is_active: await self._api.set_schedule_state( - self._location, STATE_OFF, current_schedule + self._location, current_schedule, STATE_OFF, ) self._last_active_schedule = current_schedule regulation = self._regulation_mode_for_hvac(hvac_mode) @@ -357,14 +357,14 @@ async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None: # Common - transition from auto = schedule off if self.hvac_mode == HVACMode.AUTO: await self._api.set_schedule_state( - self._location, STATE_OFF, current_schedule + self._location, current_schedule, STATE_OFF, ) self._last_active_schedule = current_schedule return # Common - transition to auto = schedule on _check_for_schedule(schedule_is_active, self._last_active_schedule) - await self._api.set_schedule_state(self._location, STATE_ON, desired_schedule) + await self._api.set_schedule_state(self._location, desired_schedule, STATE_ON) @plugwise_command @override From ef2b13fb1ba34c2bf03de3fec1015d092b4ac887 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sat, 1 Aug 2026 08:56:02 +0200 Subject: [PATCH 54/66] Adapt test_climate --- tests/components/plugwise/test_climate.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/components/plugwise/test_climate.py b/tests/components/plugwise/test_climate.py index 05020fd1f..300a52c30 100644 --- a/tests/components/plugwise/test_climate.py +++ b/tests/components/plugwise/test_climate.py @@ -111,7 +111,7 @@ async def test_adam_climate_entity_climate_changes( ) assert mock_smile_adam.set_schedule_state.call_count == 2 mock_smile_adam.set_schedule_state.assert_called_with( - "c50f167537524366a5af7aa3942feb1e", STATE_OFF, "GF7 Woonkamer", + "c50f167537524366a5af7aa3942feb1e", "GF7 Woonkamer", STATE_OFF, ) with pytest.raises( @@ -231,7 +231,7 @@ async def test_adam_restore_state_climate( ) # Verify set_schedule_state was called with the restored schedule mock_smile_adam_heat_cool.set_schedule_state.assert_called_with( - "f871b8c4d63549319221e294e4f88074", STATE_ON, "Badkamer" + "f871b8c4d63549319221e294e4f88074", "Badkamer", STATE_ON ) assert mock_smile_adam_heat_cool.set_schedule_state.call_count == 1 @@ -327,7 +327,7 @@ async def test_adam_off_regulation_mode_change( blocking=True, ) mock_smile_adam_heat_cool.set_schedule_state.assert_called_with( - "f871b8c4d63549319221e294e4f88074", STATE_OFF, "Badkamer" + "f871b8c4d63549319221e294e4f88074", "Badkamer", STATE_OFF ) @@ -462,7 +462,7 @@ async def test_adam_3_climate_entity_attributes( ) # And set_schedule_state was called with the restored last_active_schedule mock_smile_adam_heat_cool.set_schedule_state.assert_called_with( - "f871b8c4d63549319221e294e4f88074", STATE_ON, "Badkamer", + "f871b8c4d63549319221e294e4f88074", "Badkamer", STATE_ON, ) async def test_adam_climate_off_mode_change( @@ -587,7 +587,7 @@ async def test_anna_climate_entity_climate_changes( ) assert mock_smile_anna.set_schedule_state.call_count == 1 mock_smile_anna.set_schedule_state.assert_called_with( - "c784ee9fdab44e1395b8dee7d7a497d5", STATE_OFF, "standaard", + "c784ee9fdab44e1395b8dee7d7a497d5", "standaard", STATE_OFF, ) data = mock_smile_anna.async_update.return_value @@ -605,7 +605,7 @@ async def test_anna_climate_entity_climate_changes( ) assert mock_smile_anna.set_schedule_state.call_count == 2 mock_smile_anna.set_schedule_state.assert_called_with( - "c784ee9fdab44e1395b8dee7d7a497d5", STATE_ON, "standaard", + "c784ee9fdab44e1395b8dee7d7a497d5", "standaard", STATE_ON, ) # Mock user deleting last schedule from app or browser From a374c337bf4c208346d8959c205f4b3de6820e1f Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sat, 1 Aug 2026 08:58:12 +0200 Subject: [PATCH 55/66] Fix typo --- custom_components/plugwise/water_heater.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/plugwise/water_heater.py b/custom_components/plugwise/water_heater.py index 7ecc886b9..282c59b71 100644 --- a/custom_components/plugwise/water_heater.py +++ b/custom_components/plugwise/water_heater.py @@ -168,7 +168,7 @@ async def async_turn_off(self, **kwargs: Any) -> None: async def async_turn_on(self, **kwargs: Any) -> None: """Turn the water_heater on and set the operation mode.""" await self.coordinator.api.set_dhw_mode( - DHW_MODE, self._dev_id, STATE_ECO self._dhw_modes_count, + DHW_MODE, self._dev_id, STATE_ECO, self._dhw_modes_count, ) @plugwise_command From a936de57f7493790ec17f48872447fd629cefde4 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sat, 1 Aug 2026 09:00:59 +0200 Subject: [PATCH 56/66] Adapt test_water_heater.py --- tests/components/plugwise/test_water_heater.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/components/plugwise/test_water_heater.py b/tests/components/plugwise/test_water_heater.py index d4c98066f..5c09b674d 100644 --- a/tests/components/plugwise/test_water_heater.py +++ b/tests/components/plugwise/test_water_heater.py @@ -69,7 +69,7 @@ async def test_adam_water_heater_setpoint_change( ) assert mock_smile_adam_jip.set_dhw_mode.call_count == 1 mock_smile_adam_jip.set_dhw_mode.assert_called_with( - "dhw_mode", "e4684553153b44afbef2200885f379dc", 2, "eco" + "dhw_mode", "e4684553153b44afbef2200885f379dc", "eco", 2, ) @pytest.mark.usefixtures("mock_smile_anna") @@ -104,7 +104,7 @@ async def test_anna_water_heater_mode_change( ) assert mock_smile_anna.set_dhw_mode.call_count == 1 mock_smile_anna.set_dhw_mode.assert_called_with( - "dhw_mode", "bfb5ee0a88e14e5f97bfa725a760cc49", 5, "off" + "dhw_mode", "bfb5ee0a88e14e5f97bfa725a760cc49", "off", 5, ) data = mock_smile_anna.async_update.return_value @@ -122,5 +122,5 @@ async def test_anna_water_heater_mode_change( ) assert mock_smile_anna.set_dhw_mode.call_count == 2 mock_smile_anna.set_dhw_mode.assert_called_with( - "dhw_mode", "bfb5ee0a88e14e5f97bfa725a760cc49", 5, "boost" + "dhw_mode", "bfb5ee0a88e14e5f97bfa725a760cc49", "boost", 5, ) From 9fffc12567299ceb01228712cf0c644f03f84c1f Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sat, 1 Aug 2026 09:05:16 +0200 Subject: [PATCH 57/66] Save updated test-snapshots --- .../plugwise/snapshots/test_diagnostics.ambr | 8 +- .../plugwise/snapshots/test_select.ambr | 24 +-- .../plugwise/snapshots/test_sensor.ambr | 174 ++++++++++++++++++ .../plugwise/snapshots/test_water_heater.ambr | 12 +- 4 files changed, 200 insertions(+), 18 deletions(-) diff --git a/tests/components/plugwise/snapshots/test_diagnostics.ambr b/tests/components/plugwise/snapshots/test_diagnostics.ambr index c37b77e23..3e3f6fc6e 100644 --- a/tests/components/plugwise/snapshots/test_diagnostics.ambr +++ b/tests/components/plugwise/snapshots/test_diagnostics.ambr @@ -25,12 +25,12 @@ '08963fec7c53423ca5680aa4cb502c63': dict({ 'active_preset': 'away', 'available_schedules': list([ + 'off', 'CV Roan', 'Bios Schema met Film Avond', 'GF7 Woonkamer', 'Badkamer Schema', 'CV Jessie', - 'off', ]), 'climate_mode': 'auto', 'control_state': 'idle', @@ -67,12 +67,12 @@ '12493538af164a409c6a1c79e38afe1c': dict({ 'active_preset': 'away', 'available_schedules': list([ + 'off', 'CV Roan', 'Bios Schema met Film Avond', 'GF7 Woonkamer', 'Badkamer Schema', 'CV Jessie', - 'off', ]), 'climate_mode': 'heat', 'control_state': 'idle', @@ -283,12 +283,12 @@ '82fa13f017d240daa0d0ea1775420f24': dict({ 'active_preset': 'asleep', 'available_schedules': list([ + 'off', 'CV Roan', 'Bios Schema met Film Avond', 'GF7 Woonkamer', 'Badkamer Schema', 'CV Jessie', - 'off', ]), 'climate_mode': 'auto', 'control_state': 'idle', @@ -438,12 +438,12 @@ 'c50f167537524366a5af7aa3942feb1e': dict({ 'active_preset': 'home', 'available_schedules': list([ + 'off', 'CV Roan', 'Bios Schema met Film Avond', 'GF7 Woonkamer', 'Badkamer Schema', 'CV Jessie', - 'off', ]), 'climate_mode': 'auto', 'control_state': 'heating', diff --git a/tests/components/plugwise/snapshots/test_select.ambr b/tests/components/plugwise/snapshots/test_select.ambr index f9427f3b9..e433084ff 100644 --- a/tests/components/plugwise/snapshots/test_select.ambr +++ b/tests/components/plugwise/snapshots/test_select.ambr @@ -133,11 +133,11 @@ 'area_id': None, 'capabilities': dict({ : list([ + 'off', 'Badkamer', 'Vakantie', 'Weekschema', 'Test', - 'off', ]), }), 'config_entry_id': , @@ -175,11 +175,11 @@ 'attributes': ReadOnlyDict({ : 'Bathroom Thermostat schedule', : list([ + 'off', 'Badkamer', 'Vakantie', 'Weekschema', 'Test', - 'off', ]), }), 'context': , @@ -259,11 +259,11 @@ 'area_id': None, 'capabilities': dict({ : list([ + 'off', 'Badkamer', 'Vakantie', 'Weekschema', 'Test', - 'off', ]), }), 'config_entry_id': , @@ -301,11 +301,11 @@ 'attributes': ReadOnlyDict({ : 'Living room Thermostat schedule', : list([ + 'off', 'Badkamer', 'Vakantie', 'Weekschema', 'Test', - 'off', ]), }), 'context': , @@ -444,12 +444,12 @@ 'area_id': None, 'capabilities': dict({ : list([ + 'off', 'CV Roan', 'Bios Schema met Film Avond', 'GF7 Woonkamer', 'Badkamer Schema', 'CV Jessie', - 'off', ]), }), 'config_entry_id': , @@ -487,12 +487,12 @@ 'attributes': ReadOnlyDict({ : 'Badkamer Thermostat schedule', : list([ + 'off', 'CV Roan', 'Bios Schema met Film Avond', 'GF7 Woonkamer', 'Badkamer Schema', 'CV Jessie', - 'off', ]), }), 'context': , @@ -511,12 +511,12 @@ 'area_id': None, 'capabilities': dict({ : list([ + 'off', 'CV Roan', 'Bios Schema met Film Avond', 'GF7 Woonkamer', 'Badkamer Schema', 'CV Jessie', - 'off', ]), }), 'config_entry_id': , @@ -554,12 +554,12 @@ 'attributes': ReadOnlyDict({ : 'Bios Thermostat schedule', : list([ + 'off', 'CV Roan', 'Bios Schema met Film Avond', 'GF7 Woonkamer', 'Badkamer Schema', 'CV Jessie', - 'off', ]), }), 'context': , @@ -578,12 +578,12 @@ 'area_id': None, 'capabilities': dict({ : list([ + 'off', 'CV Roan', 'Bios Schema met Film Avond', 'GF7 Woonkamer', 'Badkamer Schema', 'CV Jessie', - 'off', ]), }), 'config_entry_id': , @@ -621,12 +621,12 @@ 'attributes': ReadOnlyDict({ : 'Jessie Thermostat schedule', : list([ + 'off', 'CV Roan', 'Bios Schema met Film Avond', 'GF7 Woonkamer', 'Badkamer Schema', 'CV Jessie', - 'off', ]), }), 'context': , @@ -645,12 +645,12 @@ 'area_id': None, 'capabilities': dict({ : list([ + 'off', 'CV Roan', 'Bios Schema met Film Avond', 'GF7 Woonkamer', 'Badkamer Schema', 'CV Jessie', - 'off', ]), }), 'config_entry_id': , @@ -688,12 +688,12 @@ 'attributes': ReadOnlyDict({ : 'Woonkamer Thermostat schedule', : list([ + 'off', 'CV Roan', 'Bios Schema met Film Avond', 'GF7 Woonkamer', 'Badkamer Schema', 'CV Jessie', - 'off', ]), }), 'context': , diff --git a/tests/components/plugwise/snapshots/test_sensor.ambr b/tests/components/plugwise/snapshots/test_sensor.ambr index 8b430581f..87fe0b387 100644 --- a/tests/components/plugwise/snapshots/test_sensor.ambr +++ b/tests/components/plugwise/snapshots/test_sensor.ambr @@ -1202,6 +1202,64 @@ 'state': '38.1', }) # --- +# name: test_adam_sensor_snapshot[platforms0-False-m_adam_heating][sensor.opentherm_water_temperature-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': dict({ + : , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.opentherm_water_temperature', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Water temperature', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 1, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Water temperature', + 'platform': 'plugwise', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'water_temperature', + 'unique_id': '056ee145a816487eaa69243c3280f8bf-water_temperature', + 'unit_of_measurement': , + }) +# --- +# name: test_adam_sensor_snapshot[platforms0-False-m_adam_heating][sensor.opentherm_water_temperature-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : 'temperature', + : 'OpenTherm Water temperature', + : , + : , + }), + 'context': , + 'entity_id': 'sensor.opentherm_water_temperature', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '37.0', + }) +# --- # name: test_adam_sensor_snapshot[platforms0-False-m_adam_heating][sensor.tom_badkamer_battery-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ @@ -3443,6 +3501,64 @@ 'state': '19.3', }) # --- +# name: test_anna_sensor_snapshot[platforms0-True-anna_heatpump_heating][sensor.opentherm_dhw_temperature-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': dict({ + : , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.opentherm_dhw_temperature', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'DHW temperature', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 1, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'DHW temperature', + 'platform': 'plugwise', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'dhw_temperature', + 'unique_id': '1cbf783bb11e4a7c8a6843dee3a86927-dhw_temperature', + 'unit_of_measurement': , + }) +# --- +# name: test_anna_sensor_snapshot[platforms0-True-anna_heatpump_heating][sensor.opentherm_dhw_temperature-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : 'temperature', + : 'OpenTherm DHW temperature', + : , + : , + }), + 'context': , + 'entity_id': 'sensor.opentherm_dhw_temperature', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '46.3', + }) +# --- # name: test_anna_sensor_snapshot[platforms0-True-anna_heatpump_heating][sensor.opentherm_intended_boiler_temperature-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ @@ -3729,6 +3845,64 @@ 'state': '1.57', }) # --- +# name: test_anna_sensor_snapshot[platforms0-True-anna_heatpump_heating][sensor.opentherm_water_temperature-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': dict({ + : , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.opentherm_water_temperature', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Water temperature', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 1, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Water temperature', + 'platform': 'plugwise', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'water_temperature', + 'unique_id': '1cbf783bb11e4a7c8a6843dee3a86927-water_temperature', + 'unit_of_measurement': , + }) +# --- +# name: test_anna_sensor_snapshot[platforms0-True-anna_heatpump_heating][sensor.opentherm_water_temperature-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : 'temperature', + : 'OpenTherm Water temperature', + : , + : , + }), + 'context': , + 'entity_id': 'sensor.opentherm_water_temperature', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '29.1', + }) +# --- # name: test_anna_sensor_snapshot[platforms0-True-anna_heatpump_heating][sensor.smile_anna_outdoor_temperature-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ diff --git a/tests/components/plugwise/snapshots/test_water_heater.ambr b/tests/components/plugwise/snapshots/test_water_heater.ambr index 0311ec93d..89b422488 100644 --- a/tests/components/plugwise/snapshots/test_water_heater.ambr +++ b/tests/components/plugwise/snapshots/test_water_heater.ambr @@ -8,6 +8,7 @@ 'capabilities': dict({ : 90.0, : 20.0, + : 0.5, }), 'config_entry_id': , 'config_subentry_id': , @@ -49,6 +50,7 @@ : , : None, : None, + : 0.5, : 90.0, }), 'context': , @@ -72,6 +74,7 @@ 'comfort', 'eco', ]), + : 0.5, }), 'config_entry_id': , 'config_subentry_id': , @@ -118,6 +121,7 @@ : , : None, : None, + : 0.5, : 60.0, }), 'context': , @@ -137,6 +141,7 @@ 'capabilities': dict({ : 45.0, : 25.0, + : 0.5, }), 'config_entry_id': , 'config_subentry_id': , @@ -178,6 +183,7 @@ : , : None, : None, + : 0.5, : 40.0, }), 'context': , @@ -204,6 +210,7 @@ 'eco', 'comfort', ]), + : 0.5, }), 'config_entry_id': , 'config_subentry_id': , @@ -229,7 +236,7 @@ 'platform': 'plugwise', 'previous_unique_id': None, 'suggested_object_id': None, - 'supported_features': , + 'supported_features': , 'translation_key': 'dhw_temperature', 'unique_id': 'bfb5ee0a88e14e5f97bfa725a760cc49-dhw_temperature', 'unit_of_measurement': None, @@ -250,9 +257,10 @@ 'comfort', ]), : 'auto', - : , + : , : None, : None, + : 0.5, : 53.0, }), 'context': , From 9fec4f083c72cfdd2385473f4567b2e7de78c213 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sat, 1 Aug 2026 09:10:10 +0200 Subject: [PATCH 58/66] Ruff fix --- custom_components/plugwise/manifest.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/custom_components/plugwise/manifest.json b/custom_components/plugwise/manifest.json index 67d1ba4fe..916164dfb 100644 --- a/custom_components/plugwise/manifest.json +++ b/custom_components/plugwise/manifest.json @@ -7,7 +7,9 @@ "integration_type": "hub", "iot_class": "local_polling", "loggers": ["plugwise"], - "requirements": ["plugwise@git+https://github.com/plugwise/python-plugwise.git@wh-3"], + "requirements": [ + "plugwise@git+https://github.com/plugwise/python-plugwise.git@wh-3" + ], "version": "0.65.0", "zeroconf": ["_plugwise._tcp.local."] } From 1f0acee4d8c277575e6622c13662a6f44f0fd04d Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sat, 1 Aug 2026 11:22:56 +0200 Subject: [PATCH 59/66] Update translations, update water_heater tests --- .../plugwise/translations/en.json | 4 +- .../plugwise/translations/nl.json | 4 +- .../components/plugwise/test_water_heater.py | 85 +++++++++++++++---- 3 files changed, 74 insertions(+), 19 deletions(-) diff --git a/custom_components/plugwise/translations/en.json b/custom_components/plugwise/translations/en.json index d3436c798..88caca2e6 100644 --- a/custom_components/plugwise/translations/en.json +++ b/custom_components/plugwise/translations/en.json @@ -294,10 +294,10 @@ }, "water_heater": { "boiler_temperature": { - "name": "Boiler temperature" + "name": "Boiler" }, "dhw_temperature": { - "name": "DHW temperature", + "name": "Domestic hot water", "state_attributes": { "dhw_modes": { "state": { diff --git a/custom_components/plugwise/translations/nl.json b/custom_components/plugwise/translations/nl.json index 2bccdbeae..327de0716 100644 --- a/custom_components/plugwise/translations/nl.json +++ b/custom_components/plugwise/translations/nl.json @@ -294,10 +294,10 @@ }, "water_heater": { "boiler_temperature": { - "name": "Boiler temperatuur" + "name": "Boiler" }, "dhw_temperature": { - "name": "SWW temperatuur", + "name": "Sanitair warm water", "state_attributes": { "dhw_modes": { "state": { diff --git a/tests/components/plugwise/test_water_heater.py b/tests/components/plugwise/test_water_heater.py index 5c09b674d..a145bdf5a 100644 --- a/tests/components/plugwise/test_water_heater.py +++ b/tests/components/plugwise/test_water_heater.py @@ -1,21 +1,24 @@ """Tests for the Plugwise water_heater platform.""" + from datetime import timedelta from unittest.mock import MagicMock, patch +from freezegun.api import FrozenDateTimeFactory import pytest +from syrupy.assertion import SnapshotAssertion -from freezegun.api import FrozenDateTimeFactory from homeassistant.components.water_heater import ( ATTR_OPERATION_MODE, DOMAIN as WATER_HEATER_DOMAIN, SERVICE_SET_OPERATION_MODE, SERVICE_SET_TEMPERATURE, + SERVICE_TURN_OFF, + SERVICE_TURN_ON, ) from homeassistant.const import ATTR_ENTITY_ID, ATTR_TEMPERATURE from homeassistant.core import HomeAssistant from homeassistant.exceptions import ServiceNotSupported from homeassistant.helpers import entity_registry as er -from syrupy.assertion import SnapshotAssertion from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform @@ -24,11 +27,11 @@ ) -@pytest.mark.usefixtures("mock_smile_adam_jip") @pytest.mark.parametrize("platforms", [(WATER_HEATER_DOMAIN,)]) @pytest.mark.usefixtures("entity_registry_enabled_by_default") async def test_adam_water_heater_snapshot( hass: HomeAssistant, + mock_smile_adam_jip: MagicMock, snapshot: SnapshotAssertion, entity_registry: er.EntityRegistry, setup_platform: MockConfigEntry, @@ -38,25 +41,51 @@ async def test_adam_water_heater_snapshot( async def test_adam_water_heater_setpoint_change( - hass: HomeAssistant, mock_smile_adam_jip: MagicMock, init_integration: MockConfigEntry + hass: HomeAssistant, + mock_smile_adam_jip: MagicMock, + init_integration: MockConfigEntry, ) -> None: """Test Adam water_heater setpoint-change.""" await hass.services.async_call( WATER_HEATER_DOMAIN, SERVICE_SET_TEMPERATURE, - {ATTR_ENTITY_ID: "water_heater.opentherm_dhw_temperature", ATTR_TEMPERATURE: 65}, + { + ATTR_ENTITY_ID: "water_heater.opentherm_domestic_hot_water", + ATTR_TEMPERATURE: 65, + }, blocking=True, ) assert mock_smile_adam_jip.set_number.call_count == 1 mock_smile_adam_jip.set_number.assert_called_with( - "e4684553153b44afbef2200885f379dc", "dhw_temperature", 65.0, + "e4684553153b44afbef2200885f379dc", + "dhw_temperature", + 65.0, + ) + + await hass.services.async_call( + WATER_HEATER_DOMAIN, + SERVICE_SET_TEMPERATURE, + { + ATTR_ENTITY_ID: "water_heater.opentherm_boiler", + ATTR_TEMPERATURE: 85, + }, + blocking=True, + ) + assert mock_smile_adam_jip.set_number.call_count == 2 + mock_smile_adam_jip.set_number.assert_called_with( + "e4684553153b44afbef2200885f379dc", + "boiler_temperature", + 85.0, ) with pytest.raises(ServiceNotSupported): await hass.services.async_call( WATER_HEATER_DOMAIN, SERVICE_SET_OPERATION_MODE, - {ATTR_ENTITY_ID: "water_heater.opentherm_boiler_temperature", ATTR_OPERATION_MODE: "eco"}, + { + ATTR_ENTITY_ID: "water_heater.opentherm_boiler", + ATTR_OPERATION_MODE: "eco", + }, blocking=True, ) assert mock_smile_adam_jip.set_dhw_mode.call_count == 0 @@ -64,7 +93,10 @@ async def test_adam_water_heater_setpoint_change( await hass.services.async_call( WATER_HEATER_DOMAIN, SERVICE_SET_OPERATION_MODE, - {ATTR_ENTITY_ID: "water_heater.opentherm_dhw_temperature", ATTR_OPERATION_MODE: "eco"}, + { + ATTR_ENTITY_ID: "water_heater.opentherm_domestic_hot_water", + ATTR_OPERATION_MODE: "eco", + }, blocking=True, ) assert mock_smile_adam_jip.set_dhw_mode.call_count == 1 @@ -72,13 +104,14 @@ async def test_adam_water_heater_setpoint_change( "dhw_mode", "e4684553153b44afbef2200885f379dc", "eco", 2, ) -@pytest.mark.usefixtures("mock_smile_anna") -@pytest.mark.parametrize("chosen_env", ["anna_v4_dhw"], indirect=True) + +@pytest.mark.parametrize("chosen_env", ["anna_loria_cooling_active"], indirect=True) @pytest.mark.parametrize("cooling_present", [False], indirect=True) @pytest.mark.parametrize("platforms", [(WATER_HEATER_DOMAIN,)]) @pytest.mark.usefixtures("entity_registry_enabled_by_default") async def test_anna_water_heater_snapshot( hass: HomeAssistant, + mock_smile_anna: MagicMock, snapshot: SnapshotAssertion, entity_registry: er.EntityRegistry, setup_platform: MockConfigEntry, @@ -98,8 +131,10 @@ async def test_anna_water_heater_mode_change( """Test Anna water_heater dhw_mode changes.""" await hass.services.async_call( WATER_HEATER_DOMAIN, - SERVICE_SET_OPERATION_MODE, - {ATTR_ENTITY_ID: "water_heater.opentherm_dhw_temperature", ATTR_OPERATION_MODE: "off"}, + SERVICE_TURN_OFF, + { + ATTR_ENTITY_ID: "water_heater.opentherm_domestic_hot_water", + }, blocking=True, ) assert mock_smile_anna.set_dhw_mode.call_count == 1 @@ -116,11 +151,31 @@ async def test_anna_water_heater_mode_change( await hass.services.async_call( WATER_HEATER_DOMAIN, - SERVICE_SET_OPERATION_MODE, - {ATTR_ENTITY_ID: "water_heater.opentherm_dhw_temperature", ATTR_OPERATION_MODE: "boost"}, + SERVICE_TURN_ON, + { + ATTR_ENTITY_ID: "water_heater.opentherm_domestic_hot_water", + }, blocking=True, ) assert mock_smile_anna.set_dhw_mode.call_count == 2 mock_smile_anna.set_dhw_mode.assert_called_with( - "dhw_mode", "bfb5ee0a88e14e5f97bfa725a760cc49", "boost", 5, + "dhw_mode", "bfb5ee0a88e14e5f97bfa725a760cc49", "eco", 5, + ) + + await hass.services.async_call( + WATER_HEATER_DOMAIN, + SERVICE_SET_OPERATION_MODE, + { + ATTR_ENTITY_ID: "water_heater.opentherm_domestic_hot_water", + ATTR_OPERATION_MODE: "boost", + }, + blocking=True, + ) + assert mock_smile_anna.set_dhw_mode.call_count == 3 + mock_smile_anna.set_dhw_mode.assert_called_with( + "dhw_mode", + "bfb5ee0a88e14e5f97bfa725a760cc49", + "boost", + 5, ) + From 94bd1cb00b435332412c975c8bb231b5ef7305ed Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sat, 1 Aug 2026 12:05:13 +0200 Subject: [PATCH 60/66] Save updated snapshot --- .../plugwise/snapshots/test_water_heater.ambr | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/tests/components/plugwise/snapshots/test_water_heater.ambr b/tests/components/plugwise/snapshots/test_water_heater.ambr index 89b422488..8ed967085 100644 --- a/tests/components/plugwise/snapshots/test_water_heater.ambr +++ b/tests/components/plugwise/snapshots/test_water_heater.ambr @@ -1,5 +1,5 @@ # serializer version: 1 -# name: test_adam_water_heater_snapshot[platforms0][water_heater.opentherm_boiler_temperature-entry] +# name: test_adam_water_heater_snapshot[platforms0][water_heater.opentherm_boiler-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ None, @@ -17,7 +17,7 @@ 'disabled_by': None, 'domain': 'water_heater', 'entity_category': , - 'entity_id': 'water_heater.opentherm_boiler_temperature', + 'entity_id': 'water_heater.opentherm_boiler', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -25,12 +25,12 @@ 'labels': set({ }), 'name': None, - 'object_id_base': 'Boiler temperature', + 'object_id_base': 'Boiler', 'options': dict({ }), 'original_device_class': None, 'original_icon': None, - 'original_name': 'Boiler temperature', + 'original_name': 'Boiler', 'platform': 'plugwise', 'previous_unique_id': None, 'suggested_object_id': None, @@ -40,11 +40,11 @@ 'unit_of_measurement': None, }) # --- -# name: test_adam_water_heater_snapshot[platforms0][water_heater.opentherm_boiler_temperature-state] +# name: test_adam_water_heater_snapshot[platforms0][water_heater.opentherm_boiler-state] StateSnapshot({ 'attributes': ReadOnlyDict({ : 37.3, - : 'OpenTherm Boiler temperature', + : 'OpenTherm Boiler', : 90.0, : 20.0, : , @@ -54,14 +54,14 @@ : 90.0, }), 'context': , - 'entity_id': 'water_heater.opentherm_boiler_temperature', + 'entity_id': 'water_heater.opentherm_boiler', 'last_changed': , 'last_reported': , 'last_updated': , 'state': 'on', }) # --- -# name: test_adam_water_heater_snapshot[platforms0][water_heater.opentherm_dhw_temperature-entry] +# name: test_adam_water_heater_snapshot[platforms0][water_heater.opentherm_domestic_hot_water-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ None, @@ -83,7 +83,7 @@ 'disabled_by': None, 'domain': 'water_heater', 'entity_category': , - 'entity_id': 'water_heater.opentherm_dhw_temperature', + 'entity_id': 'water_heater.opentherm_domestic_hot_water', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -91,12 +91,12 @@ 'labels': set({ }), 'name': None, - 'object_id_base': 'DHW temperature', + 'object_id_base': 'Domestic hot water', 'options': dict({ }), 'original_device_class': None, 'original_icon': None, - 'original_name': 'DHW temperature', + 'original_name': 'Domestic hot water', 'platform': 'plugwise', 'previous_unique_id': None, 'suggested_object_id': None, @@ -106,11 +106,11 @@ 'unit_of_measurement': None, }) # --- -# name: test_adam_water_heater_snapshot[platforms0][water_heater.opentherm_dhw_temperature-state] +# name: test_adam_water_heater_snapshot[platforms0][water_heater.opentherm_domestic_hot_water-state] StateSnapshot({ 'attributes': ReadOnlyDict({ : 37.3, - : 'OpenTherm DHW temperature', + : 'OpenTherm Domestic hot water', : 60.0, : 40.0, : list([ @@ -125,14 +125,14 @@ : 60.0, }), 'context': , - 'entity_id': 'water_heater.opentherm_dhw_temperature', + 'entity_id': 'water_heater.opentherm_domestic_hot_water', 'last_changed': , 'last_reported': , 'last_updated': , 'state': 'eco', }) # --- -# name: test_anna_water_heater_snapshot[platforms0-False-anna_loria_cooling_active][water_heater.opentherm_boiler_temperature-entry] +# name: test_anna_water_heater_snapshot[platforms0-False-anna_loria_cooling_active][water_heater.opentherm_boiler-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ None, @@ -150,7 +150,7 @@ 'disabled_by': None, 'domain': 'water_heater', 'entity_category': , - 'entity_id': 'water_heater.opentherm_boiler_temperature', + 'entity_id': 'water_heater.opentherm_boiler', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -158,12 +158,12 @@ 'labels': set({ }), 'name': None, - 'object_id_base': 'Boiler temperature', + 'object_id_base': 'Boiler', 'options': dict({ }), 'original_device_class': None, 'original_icon': None, - 'original_name': 'Boiler temperature', + 'original_name': 'Boiler', 'platform': 'plugwise', 'previous_unique_id': None, 'suggested_object_id': None, @@ -173,11 +173,11 @@ 'unit_of_measurement': None, }) # --- -# name: test_anna_water_heater_snapshot[platforms0-False-anna_loria_cooling_active][water_heater.opentherm_boiler_temperature-state] +# name: test_anna_water_heater_snapshot[platforms0-False-anna_loria_cooling_active][water_heater.opentherm_boiler-state] StateSnapshot({ 'attributes': ReadOnlyDict({ : 25.3, - : 'OpenTherm Boiler temperature', + : 'OpenTherm Boiler', : 45.0, : 25.0, : , @@ -187,14 +187,14 @@ : 40.0, }), 'context': , - 'entity_id': 'water_heater.opentherm_boiler_temperature', + 'entity_id': 'water_heater.opentherm_boiler', 'last_changed': , 'last_reported': , 'last_updated': , 'state': 'on', }) # --- -# name: test_anna_water_heater_snapshot[platforms0-False-anna_loria_cooling_active][water_heater.opentherm_dhw_temperature-entry] +# name: test_anna_water_heater_snapshot[platforms0-False-anna_loria_cooling_active][water_heater.opentherm_domestic_hot_water-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ None, @@ -219,7 +219,7 @@ 'disabled_by': None, 'domain': 'water_heater', 'entity_category': , - 'entity_id': 'water_heater.opentherm_dhw_temperature', + 'entity_id': 'water_heater.opentherm_domestic_hot_water', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -227,12 +227,12 @@ 'labels': set({ }), 'name': None, - 'object_id_base': 'DHW temperature', + 'object_id_base': 'Domestic hot water', 'options': dict({ }), 'original_device_class': None, 'original_icon': None, - 'original_name': 'DHW temperature', + 'original_name': 'Domestic hot water', 'platform': 'plugwise', 'previous_unique_id': None, 'suggested_object_id': None, @@ -242,11 +242,11 @@ 'unit_of_measurement': None, }) # --- -# name: test_anna_water_heater_snapshot[platforms0-False-anna_loria_cooling_active][water_heater.opentherm_dhw_temperature-state] +# name: test_anna_water_heater_snapshot[platforms0-False-anna_loria_cooling_active][water_heater.opentherm_domestic_hot_water-state] StateSnapshot({ 'attributes': ReadOnlyDict({ : 52.9, - : 'OpenTherm DHW temperature', + : 'OpenTherm Domestic hot water', : 60.0, : 35.0, : list([ @@ -264,7 +264,7 @@ : 53.0, }), 'context': , - 'entity_id': 'water_heater.opentherm_dhw_temperature', + 'entity_id': 'water_heater.opentherm_domestic_hot_water', 'last_changed': , 'last_reported': , 'last_updated': , From 5d16b3853815b1ca6505f4fcae51bdd496f32124 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sat, 1 Aug 2026 12:14:04 +0200 Subject: [PATCH 61/66] Ruff fixes --- tests/components/plugwise/test_water_heater.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/components/plugwise/test_water_heater.py b/tests/components/plugwise/test_water_heater.py index a145bdf5a..a4eddb7b1 100644 --- a/tests/components/plugwise/test_water_heater.py +++ b/tests/components/plugwise/test_water_heater.py @@ -3,10 +3,9 @@ from datetime import timedelta from unittest.mock import MagicMock, patch -from freezegun.api import FrozenDateTimeFactory import pytest -from syrupy.assertion import SnapshotAssertion +from freezegun.api import FrozenDateTimeFactory from homeassistant.components.water_heater import ( ATTR_OPERATION_MODE, DOMAIN as WATER_HEATER_DOMAIN, @@ -19,6 +18,7 @@ from homeassistant.core import HomeAssistant from homeassistant.exceptions import ServiceNotSupported from homeassistant.helpers import entity_registry as er +from syrupy.assertion import SnapshotAssertion from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform From 51a68a8ddfad5fdf90a44a0a30a37f0b54391b87 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Mon, 3 Aug 2026 08:07:41 +0200 Subject: [PATCH 62/66] Climate: line up changes with Core PR --- custom_components/plugwise/climate.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/custom_components/plugwise/climate.py b/custom_components/plugwise/climate.py index f426138d3..3e355d133 100644 --- a/custom_components/plugwise/climate.py +++ b/custom_components/plugwise/climate.py @@ -89,9 +89,9 @@ def _add_entities() -> None: entry.async_on_unload(coordinator.async_add_listener(_add_entities)) -def _check_for_schedule(active: bool, last_active: str | None) -> None: +def _check_for_schedule(active: bool, last_active: str) -> None: """Raise a HAError when no thermostat schedule has been set.""" - if not active and last_active is None: + if not active and last_active == STATE_OFF: raise HomeAssistantError( translation_domain=DOMAIN, translation_key=ERROR_NO_SCHEDULE, @@ -131,7 +131,7 @@ def __init__( self._api = coordinator.api gateway_id: str = self._api.gateway_id self._gateway_data = coordinator.data[gateway_id] - self._last_active_schedule: str | None = None + self._last_active_schedule = STATE_OFF self._location = device_id if (location := self.device.get(LOCATION)) is not None: self._location = location @@ -170,7 +170,7 @@ async def async_added_to_hass(self) -> None: extra_data = await self.async_get_last_extra_data() if extra_data is not None: data = extra_data.as_dict() - self._last_active_schedule = data.get("last_active_schedule") + self._last_active_schedule = data.get("last_active_schedule") or STATE_OFF self._previous_action_mode = ( data.get("previous_action_mode") or HVACAction.HEATING.value ) @@ -244,7 +244,7 @@ def hvac_modes(self) -> list[HVACMode]: if REGULATION_MODES in self._gateway_data: hvac_modes.append(HVACMode.OFF) - if self.device.get(AVAILABLE_SCHEDULES, []): + if self.device[AVAILABLE_SCHEDULES] != [STATE_OFF]: hvac_modes.append(HVACMode.AUTO) if self._api.cooling_present: @@ -329,8 +329,8 @@ async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None: await self._api.set_regulation_mode(hvac_mode.value) return - current_schedule = self.device.get("select_schedule") - schedule_is_active = current_schedule not in (None, "off") + current_schedule = self.device["select_schedule"] + schedule_is_active = current_schedule != STATE_OFF desired_schedule = ( current_schedule if schedule_is_active else self._last_active_schedule ) From 42ac39ebfa470a63a4d53d06f39ae9f7a7dc0666 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Mon, 3 Aug 2026 08:14:29 +0200 Subject: [PATCH 63/66] Adapt climate tests --- tests/components/plugwise/test_climate.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/components/plugwise/test_climate.py b/tests/components/plugwise/test_climate.py index 300a52c30..764e23b12 100644 --- a/tests/components/plugwise/test_climate.py +++ b/tests/components/plugwise/test_climate.py @@ -159,7 +159,7 @@ async def test_adam_restore_state_climate( ( State("climate.living_room", "heat"), PlugwiseClimateExtraStoredData( - last_active_schedule=None, + last_active_schedule=STATE_OFF, previous_action_mode="heating", ).as_dict(), ), @@ -610,8 +610,8 @@ async def test_anna_climate_entity_climate_changes( # Mock user deleting last schedule from app or browser data = mock_smile_anna.async_update.return_value - data["3cb70739631c4d17a86b8b12e8a5161b"]["available_schedules"] = [] - data["3cb70739631c4d17a86b8b12e8a5161b"]["select_schedule"] = None + data["3cb70739631c4d17a86b8b12e8a5161b"]["available_schedules"] = [STATE_OFF] + data["3cb70739631c4d17a86b8b12e8a5161b"]["select_schedule"] = STATE_OFF data["3cb70739631c4d17a86b8b12e8a5161b"]["climate_mode"] = "heat_cool" with patch(HA_PLUGWISE_SMILE_ASYNC_UPDATE, return_value=data): freezer.tick(timedelta(minutes=1)) From 9001a7e1a48f6583a62f48acfed6181a06fccb4b Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Mon, 3 Aug 2026 08:18:52 +0200 Subject: [PATCH 64/66] Correct fixture --- .../fixtures/m_adam_multiple_devices_per_zone/data.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/components/plugwise/fixtures/m_adam_multiple_devices_per_zone/data.json b/tests/components/plugwise/fixtures/m_adam_multiple_devices_per_zone/data.json index b1529e121..096a42917 100644 --- a/tests/components/plugwise/fixtures/m_adam_multiple_devices_per_zone/data.json +++ b/tests/components/plugwise/fixtures/m_adam_multiple_devices_per_zone/data.json @@ -128,7 +128,7 @@ }, "446ac08dd04d4eff8ac57489757b7314": { "active_preset": "no_frost", - "available_schedules": [], + "available_schedules": ["off"], "climate_mode": "heat", "control_state": "idle", "dev_class": "climate", @@ -141,7 +141,7 @@ "vacation", "no_frost" ], - "select_schedule": null, + "select_schedule": "off", "sensors": { "temperature": 15.6 }, From df9389e3c6a61498f5afa20a82f38cbc3ab119ad Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Mon, 3 Aug 2026 08:21:37 +0200 Subject: [PATCH 65/66] Save test snapshot updates --- .../plugwise/snapshots/test_diagnostics.ambr | 3 +- .../plugwise/snapshots/test_select.ambr | 57 +++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/tests/components/plugwise/snapshots/test_diagnostics.ambr b/tests/components/plugwise/snapshots/test_diagnostics.ambr index 3e3f6fc6e..fa79f8117 100644 --- a/tests/components/plugwise/snapshots/test_diagnostics.ambr +++ b/tests/components/plugwise/snapshots/test_diagnostics.ambr @@ -132,6 +132,7 @@ '446ac08dd04d4eff8ac57489757b7314': dict({ 'active_preset': 'no_frost', 'available_schedules': list([ + 'off', ]), 'climate_mode': 'heat', 'control_state': 'idle', @@ -145,7 +146,7 @@ 'vacation', 'no_frost', ]), - 'select_schedule': None, + 'select_schedule': 'off', 'sensors': dict({ 'temperature': 15.6, }), diff --git a/tests/components/plugwise/snapshots/test_select.ambr b/tests/components/plugwise/snapshots/test_select.ambr index e433084ff..4e31d6aa9 100644 --- a/tests/components/plugwise/snapshots/test_select.ambr +++ b/tests/components/plugwise/snapshots/test_select.ambr @@ -570,6 +570,63 @@ 'state': 'off', }) # --- +# name: test_adam_select_entities[platforms0][select.garage_thermostat_schedule-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': dict({ + : list([ + 'off', + ]), + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'select', + 'entity_category': None, + 'entity_id': 'select.garage_thermostat_schedule', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Thermostat schedule', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Thermostat schedule', + 'platform': 'plugwise', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'select_schedule', + 'unique_id': '446ac08dd04d4eff8ac57489757b7314-select_schedule', + 'unit_of_measurement': None, + }) +# --- +# name: test_adam_select_entities[platforms0][select.garage_thermostat_schedule-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : 'Garage Thermostat schedule', + : list([ + 'off', + ]), + }), + 'context': , + 'entity_id': 'select.garage_thermostat_schedule', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- # name: test_adam_select_entities[platforms0][select.jessie_thermostat_schedule-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ From a9e2f5137dd3b04dfae9f83670ca1f2b47174af1 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Tue, 4 Aug 2026 19:44:30 +0200 Subject: [PATCH 66/66] Link to plugwise v1.14.5 --- custom_components/plugwise/manifest.json | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/custom_components/plugwise/manifest.json b/custom_components/plugwise/manifest.json index 916164dfb..74ce43628 100644 --- a/custom_components/plugwise/manifest.json +++ b/custom_components/plugwise/manifest.json @@ -7,9 +7,7 @@ "integration_type": "hub", "iot_class": "local_polling", "loggers": ["plugwise"], - "requirements": [ - "plugwise@git+https://github.com/plugwise/python-plugwise.git@wh-3" - ], - "version": "0.65.0", + "requirements": ["plugwise==1.14.5"], + "version": "0.65.1", "zeroconf": ["_plugwise._tcp.local."] }