From 23327beacb8e2deda2ff9b760095c2e1799cbdc3 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Tue, 28 Oct 2025 19:43:28 +0100 Subject: [PATCH 01/40] Add detection of Anna P1 --- plugwise/__init__.py | 6 ++++++ plugwise/constants.py | 2 ++ 2 files changed, 8 insertions(+) diff --git a/plugwise/__init__.py b/plugwise/__init__.py index 2b89b065f..da4a1b58d 100644 --- a/plugwise/__init__.py +++ b/plugwise/__init__.py @@ -196,6 +196,12 @@ async def _smile_detect( self.smile.hostname = gateway.find("hostname").text self.smile.mac_address = gateway.find("mac_address").text self.smile.model_id = gateway.find("vendor_model").text + if (elec_measurement := gateway.find( + "gateway_environment/electricity_consumption_tariff_structure" + )) and elec_measurement.text: + parts = model.split("_") + if len(parts) == 3: + model = parts[0] + parts[1] + "_power" + parts[2] else: model = await self._smile_detect_legacy(result, dsmrmain, model) diff --git a/plugwise/constants.py b/plugwise/constants.py index 1af524900..1a9a2286a 100644 --- a/plugwise/constants.py +++ b/plugwise/constants.py @@ -34,6 +34,7 @@ ADAM: Final = "Adam" ANNA: Final = "Smile Anna" +ANNA_P1: Final = "Smile Anna P1" DEFAULT_TIMEOUT: Final = 10 DEFAULT_LEGACY_TIMEOUT: Final = 30 DEFAULT_USERNAME: Final = "smile" @@ -220,6 +221,7 @@ "smile_thermo_v1": SMILE(THERMOSTAT, ANNA), "smile_thermo_v3": SMILE(THERMOSTAT, ANNA), "smile_thermo_v4": SMILE(THERMOSTAT, ANNA), + "smile_thermo_power_v4": SMILE("thermostat_power", ANNA_P1), "stretch_v2": SMILE(STRETCH, "Stretch"), "stretch_v3": SMILE(STRETCH, "Stretch"), } From c24c9cb0199368aaa6dfd7404bd9e782c9fc4a85 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Wed, 29 Oct 2025 15:04:44 +0100 Subject: [PATCH 02/40] Improve --- plugwise/__init__.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/plugwise/__init__.py b/plugwise/__init__.py index da4a1b58d..590be7108 100644 --- a/plugwise/__init__.py +++ b/plugwise/__init__.py @@ -189,19 +189,24 @@ async def _smile_detect( """ model: str = "Unknown" if (gateway := result.find("./gateway")) is not None: - if (v_model := gateway.find("vendor_model")) is not None: - model = v_model.text + if (vendor_model := gateway.find("vendor_model")) is not None: + model = vendor_model.text + if ( + elec_measurement := gateway.find( + "gateway_environment/electricity_consumption_tariff_structure" + ) + ) and elec_measurement.text: + parts = model.split("_") + if len(parts) == 2: # expecting smile_thermo + model = parts[0] + parts[1] + "_power" + + self.smile.model_id = model + self.smile.version = parse(gateway.find("firmware_version").text) self.smile.hw_version = gateway.find("hardware_version").text self.smile.hostname = gateway.find("hostname").text self.smile.mac_address = gateway.find("mac_address").text - self.smile.model_id = gateway.find("vendor_model").text - if (elec_measurement := gateway.find( - "gateway_environment/electricity_consumption_tariff_structure" - )) and elec_measurement.text: - parts = model.split("_") - if len(parts) == 3: - model = parts[0] + parts[1] + "_power" + parts[2] + else: model = await self._smile_detect_legacy(result, dsmrmain, model) @@ -243,7 +248,7 @@ async def _smile_detect( if self.smile.type == "stretch": self._stretch_v2 = int(version_major) == 2 - if self.smile.type == "thermostat": + if self.smile.type in ("thermostat", "thermostat_power"): self._is_thermostat = True # For Adam, Anna, determine the system capabilities: # Find the connected heating/cooling device (heater_central), From 2ae44f928440ec86f460f8eed09c74f104a5d7a8 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Thu, 30 Oct 2025 10:47:37 +0100 Subject: [PATCH 03/40] Show model_id for legacy gataways --- plugwise/__init__.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/plugwise/__init__.py b/plugwise/__init__.py index 590be7108..f1e44a3f6 100644 --- a/plugwise/__init__.py +++ b/plugwise/__init__.py @@ -197,11 +197,9 @@ async def _smile_detect( ) ) and elec_measurement.text: parts = model.split("_") - if len(parts) == 2: # expecting smile_thermo + if len(parts) == 2: # looking for "smile_thermo" model = parts[0] + parts[1] + "_power" - self.smile.model_id = model - self.smile.version = parse(gateway.find("firmware_version").text) self.smile.hw_version = gateway.find("hardware_version").text self.smile.hostname = gateway.find("hostname").text @@ -242,6 +240,7 @@ async def _smile_detect( raise UnsupportedDeviceError # pragma: no cover self.smile.model = "Gateway" + self.smile.model_id = model self.smile.name = SMILES[self._target_smile].smile_name self.smile.type = SMILES[self._target_smile].smile_type From cc542495d42ee939af35aa159f90ed54320bedb1 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Fri, 31 Oct 2025 19:06:21 +0100 Subject: [PATCH 04/40] Ruffed --- plugwise/helper.py | 1 - plugwise/smile.py | 4 +--- tests/test_anna.py | 4 +++- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/plugwise/helper.py b/plugwise/helper.py index 0d7355ee0..687fbb926 100644 --- a/plugwise/helper.py +++ b/plugwise/helper.py @@ -925,7 +925,6 @@ def _schedules(self, location: str) -> tuple[list[str], str]: if selected == NONE: selected = OFF - return available, selected def _thermostat_uri(self, loc_id: str) -> str: diff --git a/plugwise/smile.py b/plugwise/smile.py index bfeb61817..362a2316d 100644 --- a/plugwise/smile.py +++ b/plugwise/smile.py @@ -361,9 +361,7 @@ async def set_schedule_state( await self.call_request(uri, method="put", data=data) self._schedule_old_states[loc_id][name] = new_state - def determine_contexts( - self, loc_id: str, state: str, sched_id: str - ) -> str: + def determine_contexts(self, loc_id: str, state: str, sched_id: str) -> str: """Helper-function for set_schedule_state().""" locator = f'.//*[@id="{sched_id}"]/contexts' contexts = self._domain_objects.find(locator) diff --git a/tests/test_anna.py b/tests/test_anna.py index 6b5c65729..389845ad1 100644 --- a/tests/test_anna.py +++ b/tests/test_anna.py @@ -359,7 +359,9 @@ async def test_connect_anna_elga_2_schedule_off(self): assert self.entity_items == 65 result = await self.tinker_thermostat( - api, "d3ce834534114348be628b61b26d9220", good_schedules=["Thermostat schedule", "off"] + api, + "d3ce834534114348be628b61b26d9220", + good_schedules=["Thermostat schedule", "off"], ) assert result await api.close_connection() From 2751642632de5f3f3af386f4ee3160f02a29a048 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sat, 1 Nov 2025 15:56:27 +0100 Subject: [PATCH 05/40] Change anna_p1 indication, collect smartmeter data when available --- plugwise/__init__.py | 19 +++++++++++-------- plugwise/constants.py | 1 - plugwise/helper.py | 2 +- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/plugwise/__init__.py b/plugwise/__init__.py index f1e44a3f6..4c103a6a2 100644 --- a/plugwise/__init__.py +++ b/plugwise/__init__.py @@ -75,6 +75,7 @@ def __init__( self._stretch_v2 = False self._target_smile: str = NONE self.smile: Munch = Munch() + self.smile.anna_p1 = False self.smile.hostname = NONE self.smile.hw_version = None self.smile.legacy = False @@ -191,20 +192,20 @@ async def _smile_detect( if (gateway := result.find("./gateway")) is not None: if (vendor_model := gateway.find("vendor_model")) is not None: model = vendor_model.text + elec_measurement = gateway.find( + "gateway_environment/electricity_consumption_tariff_structure" + ) if ( - elec_measurement := gateway.find( - "gateway_environment/electricity_consumption_tariff_structure" - ) - ) and elec_measurement.text: - parts = model.split("_") - if len(parts) == 2: # looking for "smile_thermo" - model = parts[0] + parts[1] + "_power" + elec_measurement is not None + and elec_measurement.text + and model == "smile_thermo" + ): + self.smile.anna_p1 = True self.smile.version = parse(gateway.find("firmware_version").text) self.smile.hw_version = gateway.find("hardware_version").text self.smile.hostname = gateway.find("hostname").text self.smile.mac_address = gateway.find("mac_address").text - else: model = await self._smile_detect_legacy(result, dsmrmain, model) @@ -243,6 +244,8 @@ async def _smile_detect( self.smile.model_id = model self.smile.name = SMILES[self._target_smile].smile_name self.smile.type = SMILES[self._target_smile].smile_type + if self.smile.name == "Smile Anna" and self.smile.anna_p1: + self.smile.name == "Smile Anna P1" if self.smile.type == "stretch": self._stretch_v2 = int(version_major) == 2 diff --git a/plugwise/constants.py b/plugwise/constants.py index 1a9a2286a..82db53377 100644 --- a/plugwise/constants.py +++ b/plugwise/constants.py @@ -221,7 +221,6 @@ "smile_thermo_v1": SMILE(THERMOSTAT, ANNA), "smile_thermo_v3": SMILE(THERMOSTAT, ANNA), "smile_thermo_v4": SMILE(THERMOSTAT, ANNA), - "smile_thermo_power_v4": SMILE("thermostat_power", ANNA_P1), "stretch_v2": SMILE(STRETCH, "Stretch"), "stretch_v3": SMILE(STRETCH, "Stretch"), } diff --git a/plugwise/helper.py b/plugwise/helper.py index 687fbb926..8ce4f27a0 100644 --- a/plugwise/helper.py +++ b/plugwise/helper.py @@ -150,7 +150,7 @@ def _all_appliances(self) -> None: self._create_gw_entities(appl) - if self.smile.type == "power": + if self.smile.type == "power" or self.smile.anna_p1: self._get_p1_smartmeter_info() # Sort the gw_entities From c7ab8988ec554aa8dabc4722f569f543e8a25c89 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sat, 1 Nov 2025 17:18:34 +0100 Subject: [PATCH 06/40] Add Anna_P1 userdata --- userdata/anna_p1/core.domain_objects.xml | 1508 ++++++++++++++++++++++ 1 file changed, 1508 insertions(+) create mode 100644 userdata/anna_p1/core.domain_objects.xml diff --git a/userdata/anna_p1/core.domain_objects.xml b/userdata/anna_p1/core.domain_objects.xml new file mode 100644 index 000000000..6fdbc7e92 --- /dev/null +++ b/userdata/anna_p1/core.domain_objects.xml @@ -0,0 +1,1508 @@ + + + + + 2021-12-18T11:59:13.471+01:00 + 2025-11-01T16:31:22.561+01:00 + + + + + + high_economy + off + small + underfloor_and_radiator + 120 + off + 24 + 10 + 0.7 + 0.7 + 1.5 + 75 + 55 + 0 + 20 + 7 + + + + Plugwise + ThermoExtension + 6539-1301-2304 + 2018-02-08T11:15:57+01:00 + 2021-12-18T11:59:05.771+01:00 + 2021-12-28T05:55:47.320+01:00 + + + + + + + + Plugwise + Gateway + AME Smile 2.0 board + + 2021-12-18T11:58:59.088+01:00 + 2022-06-22T02:59:00.904+02:00 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Thermostat schedule + Provides a week schedule for a Location. +