diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bf45d22c..c0d25a49b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## Ongoing + +- Collect wifi_mac_address [#904](https://github.com/plugwise/python-plugwise/issues/904) + ## v1.14.6 - Bugfixes: fix domestic hot water comfort switching, dhw modes selection issues reported in Core issue [#178699](https://github.com/home-assistant/core/issues/178699) via PR [#914](https://github.com/plugwise/python-plugwise/pull/914) diff --git a/Q&Dtesting/test_adam.py b/Q&Dtesting/test_adam.py new file mode 100644 index 000000000..21d599bcd --- /dev/null +++ b/Q&Dtesting/test_adam.py @@ -0,0 +1,125 @@ +"""Test Plugwise module Adam related functionality.""" + +import pytest + +from .test_init import TestPlugwise + +SMILE_TYPE = "adam" + +# Reoccuring constants +BADKAMER_SCHEMA = "Badkamer Schema" +CV_JESSIE = "CV Jessie" +GF7_WOONKAMER = "GF7 Woonkamer" +WERKDAG_SCHEMA = "Werkdag schema" + + +class TestPlugwiseAdam(TestPlugwise): # pylint: disable=attribute-defined-outside-init + """Tests for Adam.""" + + @pytest.mark.asyncio + async def test_connect_adam_bad_thermostat(self, caplog): + """Test Adam with missing thermostat data.""" + self.smile_setup = "adam_bad_thermostat" + + testdata = await self.load_testdata(SMILE_TYPE, self.smile_setup) + server, api, client = await self.connect_wrapper(raise_timeout=True) + await self.device_test(api, "2023-12-17 00:00:01", testdata) + + await api.close_connection() + await self.disconnect(server, client) + + @pytest.mark.asyncio + async def test_connect_adam_plus_anna_new(self): + """Test extended Adam (firmware 3.9) with Anna, Emma, Jip, and a switch-group setup.""" + self.smile_setup = "adam_plus_anna_new" + + testdata = await self.load_testdata(SMILE_TYPE, self.smile_setup) + server, api, client = await self.connect_wrapper() + await self.device_test(api, "2025-10-12 00:00:01", testdata) + + await api.close_connection() + await self.disconnect(server, client) + + @pytest.mark.asyncio + async def test_connect_adam_plus_anna_new_regulation_off(self): + """Test regultaion_mode off with control_state key missing for Adam.""" + self.smile_setup = "adam_plus_anna_new_regulation_off" + + testdata = await self.load_testdata(SMILE_TYPE, self.smile_setup) + server, api, client = await self.connect_wrapper() + await self.device_test(api, "2023-12-17 00:00:01", testdata) + + await api.close_connection() + await self.disconnect(server, client) + + @pytest.mark.asyncio + async def test_connect_adam_zone_per_device(self): + """Test an extensive setup of Adam with a zone per device.""" + self.smile_setup = "adam_zone_per_device" + + testdata = await self.load_testdata(SMILE_TYPE, self.smile_setup) + server, api, client = await self.connect_wrapper() + await self.device_test(api, "2022-05-16 00:00:01", testdata) + + await api.close_connection() + await self.disconnect(server, client) + + @pytest.mark.asyncio + async def test_connect_adam_multiple_devices_per_zone(self): + """Test an extensive setup of Adam with multiple devices per zone.""" + self.smile_setup = "adam_multiple_devices_per_zone" + + testdata = await self.load_testdata(SMILE_TYPE, self.smile_setup) + server, api, client = await self.connect_wrapper() + await self.device_test(api, "2022-05-16 00:00:01", testdata) + + await api.close_connection() + await self.disconnect(server, client) + + @pytest.mark.asyncio + async def test_adam_heatpump_cooling(self): + """Test Adam with heatpump in cooling mode and idle.""" + self.smile_setup = "adam_heatpump_cooling" + + testdata = await self.load_testdata(SMILE_TYPE, self.smile_setup) + server, api, client = await self.connect_wrapper() + await self.device_test(api, "2022-01-02 00:00:01", testdata) + + await api.close_connection() + await self.disconnect(server, client) + + @pytest.mark.asyncio + async def test_connect_adam_onoff_cooling_fake_firmware(self): + """Test an Adam with a fake OnOff cooling device in cooling mode.""" + self.smile_setup = "adam_onoff_cooling_fake_firmware" + + testdata = await self.load_testdata(SMILE_TYPE, self.smile_setup) + server, api, client = await self.connect_wrapper() + await self.device_test(api, "2022-01-02 00:00:01", testdata) + + await api.close_connection() + await self.disconnect(server, client) + + @pytest.mark.asyncio + async def test_connect_adam_plus_anna(self): + """Test Adam (firmware 3.0) with Anna setup.""" + self.smile_setup = "adam_plus_anna" + + testdata = await self.load_testdata(SMILE_TYPE, self.smile_setup) + server, api, client = await self.connect_wrapper() + await self.device_test(api, "2020-03-22 00:00:01", testdata) + + await api.close_connection() + await self.disconnect(server, client) + + @pytest.mark.asyncio + async def test_adam_plus_jip(self): + """Test Adam with Jip setup.""" + self.smile_setup = "adam_jip" + + testdata = await self.load_testdata(SMILE_TYPE, self.smile_setup) + server, api, client = await self.connect_wrapper() + await self.device_test(api, "2021-06-20 00:00:01", testdata) + + await api.close_connection() + await self.disconnect(server, client) diff --git a/Q&Dtesting/test_anna.py b/Q&Dtesting/test_anna.py new file mode 100644 index 000000000..7e1b3a180 --- /dev/null +++ b/Q&Dtesting/test_anna.py @@ -0,0 +1,223 @@ +"""Test Plugwise module Anna related functionality.""" + +import pytest + +from .test_init import TestPlugwise + +SMILE_TYPE = "anna" +# Reoccuring constants +THERMOSTAT_SCHEDULE = "Thermostat schedule" + + +class TestPlugwiseAnna(TestPlugwise): # pylint: disable=attribute-defined-outside-init + """Tests for Anna standalone, i.e. not combined with Adam.""" + + @pytest.mark.asyncio + async def test_connect_anna_v4(self): + """Test an Anna firmware 4 setup.""" + self.smile_setup = "anna_v4" + + testdata = await self.load_testdata(SMILE_TYPE, self.smile_setup) + server, api, client = await self.connect_wrapper() + await self.device_test(api, "2020-04-05 00:00:01", testdata) + + await api.close_connection() + await self.disconnect(server, client) + + @pytest.mark.asyncio + async def test_connect_anna_v4_dhw(self): + """Test an Anna firmware 4 setup for domestic hot water.""" + self.smile_setup = "anna_v4_dhw" + + testdata = await self.load_testdata(SMILE_TYPE, self.smile_setup) + server, api, client = await self.connect_wrapper() + await self.device_test(api, "2020-04-05 00:00:01", testdata) + + await api.close_connection() + await self.disconnect(server, client) + + @pytest.mark.asyncio + async def test_connect_anna_v4_no_tag(self): + """Test an Anna firmware 4 setup - missing tag (issue).""" + self.smile_setup = "anna_v4_no_tag" + + testdata = await self.load_testdata(SMILE_TYPE, self.smile_setup) + server, api, client = await self.connect_wrapper() + await self.device_test(api, "2020-04-05 00:00:01", testdata) + + await api.close_connection() + await self.disconnect(server, client) + + @pytest.mark.asyncio + async def test_connect_anna_without_boiler_fw441(self): + """Test an Anna with firmware 4.4, without a boiler.""" + self.smile_setup = "anna_without_boiler_fw441" + + testdata = await self.load_testdata(SMILE_TYPE, self.smile_setup) + server, api, client = await self.connect_wrapper() + await self.device_test(api, "2022-05-16 00:00:01", testdata) + + await api.close_connection() + await self.disconnect(server, client) + + @pytest.mark.asyncio + async def test_connect_anna_heatpump_heating(self): + """Test an Anna with Elga, cooling-mode off, in heating mode.""" + + self.smile_setup = "anna_heatpump_heating" + + testdata = await self.load_testdata(SMILE_TYPE, self.smile_setup) + server, api, client = await self.connect_wrapper() + await self.device_test(api, "2020-04-12 00:00:01", testdata) + + await api.close_connection() + await self.disconnect(server, client) + + @pytest.mark.asyncio + async def test_connect_anna_heatpump_cooling(self): + """Test an Anna with Elga setup in cooling mode. + + This test also covers the situation that the operation-mode it switched + from heating to cooling due to the outdoor temperature rising above the + cooling_activation_outdoor_temperature threshold. + """ + self.smile_setup = "anna_heatpump_cooling" + + testdata = await self.load_testdata(SMILE_TYPE, self.smile_setup) + server, api, client = await self.connect_wrapper() + await self.device_test(api, "2020-04-19 00:00:01", testdata) + + await api.close_connection() + await self.disconnect(server, client) + + @pytest.mark.asyncio + async def test_connect_anna_heatpump_cooling_fake_firmware(self): + """Test an Anna with a fake Loria/Thermastate setup in cooling mode. + + The Anna + Elga firmware has been amended with the point_log cooling_enabled and + gateway/features/cooling keys. + This test also covers the situation that the operation-mode it switched + from heating to cooling due to the outdoor temperature rising above the + cooling_activation_outdoor_temperature threshold. + """ + self.smile_setup = "anna_heatpump_cooling_fake_firmware" + + testdata = await self.load_testdata(SMILE_TYPE, self.smile_setup) + server, api, client = await self.connect_wrapper() + await self.device_test(api, "2020-04-19 00:00:01", testdata) + + await api.close_connection() + await self.disconnect(server, client) + + @pytest.mark.asyncio + async def test_connect_anna_elga_no_cooling(self): + """Test an Anna with Elga, cooling-mode not used, in heating mode.""" + + self.smile_setup = "anna_elga_no_cooling" + + testdata = await self.load_testdata(SMILE_TYPE, self.smile_setup) + server, api, client = await self.connect_wrapper() + await self.device_test(api, "2020-04-12 00:00:01", testdata) + + await api.close_connection() + await self.disconnect(server, client) + + @pytest.mark.asyncio + async def test_connect_anna_elga_2(self): + """Test a 2nd Anna with Elga setup, cooling off, in idle mode (with missing outdoor temperature - solved).""" + self.smile_setup = "anna_elga_2" + + testdata = await self.load_testdata(SMILE_TYPE, self.smile_setup) + server, api, client = await self.connect_wrapper() + await self.device_test(api, "2022-03-13 00:00:01", testdata) + + await api.close_connection() + await self.disconnect(server, client) + + @pytest.mark.asyncio + async def test_connect_anna_elga_2_schedule_off(self): + """Test Anna with Elga setup, cooling off, in idle mode, modified to schedule off.""" + self.smile_setup = "anna_elga_2_schedule_off" + + testdata = await self.load_testdata(SMILE_TYPE, self.smile_setup) + server, api, client = await self.connect_wrapper() + await self.device_test(api, "2022-03-13 00:00:01", testdata) + + await api.close_connection() + await self.disconnect(server, client) + + @pytest.mark.asyncio + async def test_connect_anna_elga_2_cooling(self): + """Test a 2nd Anna with Elga setup with cooling active. + + This testcase also covers testing of the generation of a cooling-based + schedule, opposite the generation of a heating-based schedule. + """ + self.smile_setup = "anna_elga_2_cooling" + + testdata = await self.load_testdata(SMILE_TYPE, self.smile_setup) + server, api, client = await self.connect_wrapper() + await self.device_test(api, "2022-03-10 00:00:01", testdata) + + await api.close_connection() + await self.disconnect(server, client) + + @pytest.mark.asyncio + async def test_connect_anna_loria_heating_idle(self): + """Test an Anna with a Loria in heating mode - state idle.""" + self.smile_setup = "anna_loria_heating_idle" + + testdata = await self.load_testdata(SMILE_TYPE, self.smile_setup) + server, api, client = await self.connect_wrapper() + await self.device_test(api, "2022-05-16 00:00:01", testdata) + + await api.close_connection() + await self.disconnect(server, client) + + @pytest.mark.asyncio + async def test_connect_anna_loria_cooling_active(self): + """Test an Anna with a Loria in heating mode - state idle.""" + self.smile_setup = "anna_loria_cooling_active" + + testdata = await self.load_testdata(SMILE_TYPE, self.smile_setup) + server, api, client = await self.connect_wrapper() + await self.device_test(api, "2022-05-16 00:00:01", testdata) + + await api.close_connection() + await self.disconnect(server, client) + + @pytest.mark.asyncio + async def test_connect_anna_loria_driessens(self): + """Test an Anna with a Loria in heating mode - state idle.""" + self.smile_setup = "anna_loria_driessens" + + testdata = await self.load_testdata(SMILE_TYPE, self.smile_setup) + server, api, client = await self.connect_wrapper() + await self.device_test(api, "2022-05-16 00:00:01", testdata) + + await api.close_connection() + await self.disconnect(server, client) + + @pytest.mark.asyncio + async def test_connect_anna_p1(self): + """Test an Anna v4 connected to a P1 port.""" + self.smile_setup = "anna_p1" + + testdata = await self.load_testdata(SMILE_TYPE, self.smile_setup) + server, api, client = await self.connect_wrapper() + await self.device_test(api, "2025-11-02 00:00:01", testdata) + + await api.close_connection() + await self.disconnect(server, client) + + @pytest.mark.asyncio + async def test_connect_anna_v4_no_modules(self): + """Test an Anna v4 with removed Anna and OpenTherm device.""" + self.smile_setup = "anna_v4_no_modules" + + testdata = await self.load_testdata(SMILE_TYPE, self.smile_setup) + server, api, client = await self.connect_wrapper() + await self.device_test(api, "2022-05-16 00:00:01", testdata) + + await api.close_connection() + await self.disconnect(server, client) diff --git a/Q&Dtesting/test_p1.py b/Q&Dtesting/test_p1.py new file mode 100644 index 000000000..39cb1be0f --- /dev/null +++ b/Q&Dtesting/test_p1.py @@ -0,0 +1,35 @@ +"""Test Plugwise module P1 related functionality.""" + +import pytest + +from .test_init import TestPlugwise + +SMILE_TYPE = "p1" + + +class TestPlugwiseP1(TestPlugwise): # pylint: disable=attribute-defined-outside-init + """Tests for P1.""" + + @pytest.mark.asyncio + async def test_connect_p1v4_442_single(self): + """Test a P1 firmware 4.4 single-phase setup.""" + self.smile_setup = "p1v4_442_single" + + testdata = await self.load_testdata(SMILE_TYPE, self.smile_setup) + server, api, client = await self.connect_wrapper() + await self.device_test(api, "2022-05-16 00:00:01", testdata) + + await api.close_connection() + await self.disconnect(server, client) + + @pytest.mark.asyncio + async def test_connect_p1v4_442_triple(self): + """Test a P1 firmware 4 3-phase setup.""" + self.smile_setup = "p1v4_442_triple" + + testdata = await self.load_testdata(SMILE_TYPE, self.smile_setup) + server, api, client = await self.connect_wrapper() + await self.device_test(api, "2022-05-16 00:00:01", testdata) + + await api.close_connection() + await self.disconnect(server, client) diff --git a/fixtures/adam_bad_thermostat/data.json b/fixtures/adam_bad_thermostat/data.json index 5f9b19376..6f1b9a182 100644 --- a/fixtures/adam_bad_thermostat/data.json +++ b/fixtures/adam_bad_thermostat/data.json @@ -139,6 +139,7 @@ "outdoor_temperature": 15.6 }, "vendor": "Plugwise", + "wifi_mac_address": "C493004A803C", "zigbee_mac_address": "000D6F000DB9F188" } } diff --git a/fixtures/adam_plus_anna_new/data.json b/fixtures/adam_plus_anna_new/data.json index b8a9161c0..f1ced6539 100644 --- a/fixtures/adam_plus_anna_new/data.json +++ b/fixtures/adam_plus_anna_new/data.json @@ -233,6 +233,7 @@ "outdoor_temperature": 15.1 }, "vendor": "Plugwise", + "wifi_mac_address": "D40FB201CBA0", "zigbee_mac_address": "000D6F000D5ACBA0" }, "da575e9e09b947e281fb6e3ebce3b174": { diff --git a/fixtures/adam_plus_anna_new_regulation_off/data.json b/fixtures/adam_plus_anna_new_regulation_off/data.json index cdbfc278e..fcfef409b 100644 --- a/fixtures/adam_plus_anna_new_regulation_off/data.json +++ b/fixtures/adam_plus_anna_new_regulation_off/data.json @@ -206,6 +206,7 @@ "outdoor_temperature": 9.19 }, "vendor": "Plugwise", + "wifi_mac_address": "012345679892", "zigbee_mac_address": "000D6F000D5A168D" }, "e2f4322d57924fa090fbbc48b3a140dc": { diff --git a/fixtures/anna_elga_2/data.json b/fixtures/anna_elga_2/data.json index 3e3a0b873..a2a591f4d 100644 --- a/fixtures/anna_elga_2/data.json +++ b/fixtures/anna_elga_2/data.json @@ -94,6 +94,7 @@ "sensors": { "outdoor_temperature": 6.38 }, - "vendor": "Plugwise" + "vendor": "Plugwise", + "wifi_mac_address": "C4930002FE77" } } diff --git a/fixtures/anna_loria_driessens/data.json b/fixtures/anna_loria_driessens/data.json index 38e330e10..41b4d2d4b 100644 --- a/fixtures/anna_loria_driessens/data.json +++ b/fixtures/anna_loria_driessens/data.json @@ -15,7 +15,8 @@ "sensors": { "outdoor_temperature": 6.81 }, - "vendor": "Plugwise" + "vendor": "Plugwise", + "wifi_mac_address": "D40FB2011557" }, "9fb768d699e44c7fb5cc50309dc4e7d4": { "active_preset": "home", diff --git a/fixtures/anna_p1/data.json b/fixtures/anna_p1/data.json index cd637d48e..cacbc7e46 100644 --- a/fixtures/anna_p1/data.json +++ b/fixtures/anna_p1/data.json @@ -84,7 +84,8 @@ "sensors": { "outdoor_temperature": 11.8 }, - "vendor": "Plugwise" + "vendor": "Plugwise", + "wifi_mac_address": "C4930002ABCE" }, "da7be222ab3b420c927f3e49fade0304": { "available": true, diff --git a/fixtures/anna_without_boiler_fw441/data.json b/fixtures/anna_without_boiler_fw441/data.json index cc1f3bdff..5dbecb4dd 100644 --- a/fixtures/anna_without_boiler_fw441/data.json +++ b/fixtures/anna_without_boiler_fw441/data.json @@ -57,7 +57,8 @@ "sensors": { "outdoor_temperature": 8.31 }, - "vendor": "Plugwise" + "vendor": "Plugwise", + "wifi_mac_address": "D40FB200FA1D" }, "c46b4794d28149699eacf053deedd003": { "binary_sensors": { diff --git a/fixtures/m_adam_cooling/data.json b/fixtures/m_adam_cooling/data.json index 539853029..f451a7b74 100644 --- a/fixtures/m_adam_cooling/data.json +++ b/fixtures/m_adam_cooling/data.json @@ -144,6 +144,7 @@ "outdoor_temperature": 29.65 }, "vendor": "Plugwise", + "wifi_mac_address": "D40FB201CBA0", "zigbee_mac_address": "000D6F000D5ACBA0" }, "da575e9e09b947e281fb6e3ebce3b174": { diff --git a/fixtures/m_adam_heating/data.json b/fixtures/m_adam_heating/data.json index 2f9688f9c..3fc2e27ad 100644 --- a/fixtures/m_adam_heating/data.json +++ b/fixtures/m_adam_heating/data.json @@ -149,6 +149,7 @@ "outdoor_temperature": -1.25 }, "vendor": "Plugwise", + "wifi_mac_address": "D40FB201CBA0", "zigbee_mac_address": "000D6F000D5ACBA0" }, "da575e9e09b947e281fb6e3ebce3b174": { diff --git a/fixtures/m_adam_heating_off_schedule/data.json b/fixtures/m_adam_heating_off_schedule/data.json index 9e034f415..dcaad4e62 100644 --- a/fixtures/m_adam_heating_off_schedule/data.json +++ b/fixtures/m_adam_heating_off_schedule/data.json @@ -149,6 +149,7 @@ "outdoor_temperature": -1.25 }, "vendor": "Plugwise", + "wifi_mac_address": "D40FB201CBA0", "zigbee_mac_address": "000D6F000D5ACBA0" }, "da575e9e09b947e281fb6e3ebce3b174": { diff --git a/fixtures/p1v4_442_single/data.json b/fixtures/p1v4_442_single/data.json index 6dfcd7ee0..f457c6c09 100644 --- a/fixtures/p1v4_442_single/data.json +++ b/fixtures/p1v4_442_single/data.json @@ -12,7 +12,8 @@ "model_id": "smile", "name": "Smile P1", "notifications": {}, - "vendor": "Plugwise" + "vendor": "Plugwise", + "wifi_mac_address": "012345670002" }, "ba4de7613517478da82dd9b6abea36af": { "available": true, diff --git a/fixtures/p1v4_442_triple/data.json b/fixtures/p1v4_442_triple/data.json index 943325d14..c5989ce4b 100644 --- a/fixtures/p1v4_442_triple/data.json +++ b/fixtures/p1v4_442_triple/data.json @@ -16,7 +16,8 @@ "warning": "The Smile P1 is not connected to a smart meter." } }, - "vendor": "Plugwise" + "vendor": "Plugwise", + "wifi_mac_address": "012345670002" }, "b82b6b3322484f2ea4e25e0bd5f3d61f": { "available": true, diff --git a/plugwise/__init__.py b/plugwise/__init__.py index 2165322c3..7110fdf09 100644 --- a/plugwise/__init__.py +++ b/plugwise/__init__.py @@ -85,6 +85,7 @@ def __init__( self.smile.name = NONE self.smile.type = NONE self.smile.version = Version("0.0.0") + self.smile.wifi_mac_address = None self.smile.zigbee_mac_address = None @property @@ -197,26 +198,10 @@ async def _collect_smile_data( self, dsmrmain: etree.Element, result: etree.Element ) -> str: """Collect smile/gateway data.""" - model: str = "Unknown" if (gateway := result.find("./gateway")) is not None: - 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 - if (vendor_model := gateway.find("vendor_model")) is not None: - model = vendor_model.text - - # Check for Anna P1 function - elec_point_meters = result.findall( - "./location/logs/point_log/electricity_point_meter" - ) - if model == "smile_thermo": - for meter in elec_point_meters: - if meter.get("id"): - self.smile.anna_p1 = True - break + model = self._collect_gateway_data(gateway, result) else: - model = await self._smile_detect_legacy(result, dsmrmain, model) + model = await self._smile_detect_legacy(result, dsmrmain, "Unknown") if model == "Unknown" or self.smile.version == Version( "0.0.0" @@ -230,6 +215,29 @@ async def _collect_smile_data( return model + def _collect_gateway_data( + self, gateway: etree.Element, result: etree.Element + ) -> str: + """Collect data from a current-generation gateway.""" + 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 + if (wifi_mac := gateway.find("wifi_mac_address")) is not None: + self.smile.wifi_mac_address = wifi_mac.text + + model: str = gateway.findtext("vendor_model", "Unknown") + if model == "smile_thermo": + has_anna_p1 = any( + meter.get("id") + for meter in result.findall( + "./location/logs/point_log/electricity_point_meter" + ) + ) + if has_anna_p1: + self.smile.anna_p1 = True + return model + def _process_for_thermostat(self, result: etree.Element) -> None: """Extra processing for thermostats.""" if self.smile.type != "thermostat": diff --git a/plugwise/common.py b/plugwise/common.py index f698a4920..0f40b4e1b 100644 --- a/plugwise/common.py +++ b/plugwise/common.py @@ -160,6 +160,7 @@ def _create_gw_entities(self, appl: Munch) -> None: "model_id": appl.model_id, "name": appl.name, "vendor": appl.vendor_name, + "wifi_mac_address": appl.wifi_mac_address, "zigbee_mac_address": appl.zigbee_mac, }.items(): if value is not None or key == "location": diff --git a/plugwise/constants.py b/plugwise/constants.py index ccd1ca422..d251f76ba 100644 --- a/plugwise/constants.py +++ b/plugwise/constants.py @@ -298,6 +298,7 @@ "model_id", "name", "vendor", + "wifi_mac_address", "zigbee_mac_address", ] @@ -551,6 +552,7 @@ class GwEntityData(TypedDict, total=False): model_id: str | None name: str vendor: str + wifi_mac_address: str zigbee_mac_address: str # For temporary use diff --git a/plugwise/helper.py b/plugwise/helper.py index 820deafab..76b213c35 100644 --- a/plugwise/helper.py +++ b/plugwise/helper.py @@ -127,6 +127,7 @@ def _get_appliances(self) -> None: appl.module_id = None appl.name = appliance.find("name").text appl.pwclass = appliance.find("type").text + appl.wifi_mac_address = None appl.zigbee_mac = None appl.vendor_name = None @@ -191,6 +192,7 @@ def _get_p1_smartmeter_info(self) -> None: appl.name = "P1" appl.pwclass = "smartmeter" appl.vendor_name = module_data["vendor_name"] + appl.wifi_mac_address = None appl.zigbee_mac = None # Replace the entity_id of the gateway by the smartmeter location_id @@ -289,6 +291,7 @@ def _appl_gateway_info(self, appl: Munch, appliance: etree.Element) -> Munch: appl.model_id = self.smile.model_id appl.name = self.smile.name appl.vendor_name = "Plugwise" + appl.wifi_mac_address = self.smile.wifi_mac_address # Adam: collect the ZigBee MAC address of the Smile if self.check_name(ADAM): diff --git a/plugwise/legacy/helper.py b/plugwise/legacy/helper.py index 61cce5c35..22358bda6 100644 --- a/plugwise/legacy/helper.py +++ b/plugwise/legacy/helper.py @@ -110,6 +110,7 @@ def _get_appliances(self) -> None: appl.model_id = None appl.name = appliance.find("name").text appl.vendor_name = None + appl.wifi_mac_address = None appl.zigbee_mac = None # Skip thermostats that have this key, should be an orphaned device (Core #81712) @@ -241,6 +242,7 @@ def _p1_smartmeter_info_finder(self, appl: Munch) -> None: appl.model_id = None appl.name = "P1" appl.pwclass = "smartmeter" + appl.wifi_mac_address = None appl.zigbee_mac = None location = self._locations.find(f'./location[@id="{loc_id}"]') appl = self._energy_entity_info_finder(location, appl) diff --git a/tests/data/adam/adam_bad_thermostat.json b/tests/data/adam/adam_bad_thermostat.json index 9fe15acb4..2ef25b842 100644 --- a/tests/data/adam/adam_bad_thermostat.json +++ b/tests/data/adam/adam_bad_thermostat.json @@ -139,6 +139,7 @@ "outdoor_temperature": 15.6 }, "vendor": "Plugwise", + "wifi_mac_address": "C493004A803C", "zigbee_mac_address": "000D6F000DB9F188" } } diff --git a/tests/data/adam/adam_plus_anna_new.json b/tests/data/adam/adam_plus_anna_new.json index 996ec742b..49a921433 100644 --- a/tests/data/adam/adam_plus_anna_new.json +++ b/tests/data/adam/adam_plus_anna_new.json @@ -233,6 +233,7 @@ "outdoor_temperature": 15.1 }, "vendor": "Plugwise", + "wifi_mac_address": "D40FB201CBA0", "zigbee_mac_address": "000D6F000D5ACBA0" }, "da575e9e09b947e281fb6e3ebce3b174": { diff --git a/tests/data/adam/adam_plus_anna_new_regulation_off.json b/tests/data/adam/adam_plus_anna_new_regulation_off.json index 50ffeadc7..25c0c695c 100644 --- a/tests/data/adam/adam_plus_anna_new_regulation_off.json +++ b/tests/data/adam/adam_plus_anna_new_regulation_off.json @@ -206,6 +206,7 @@ "outdoor_temperature": 9.19 }, "vendor": "Plugwise", + "wifi_mac_address": "012345679892", "zigbee_mac_address": "000D6F000D5A168D" }, "e2f4322d57924fa090fbbc48b3a140dc": { diff --git a/tests/data/anna/anna_elga_2.json b/tests/data/anna/anna_elga_2.json index 3e3a0b873..a2a591f4d 100644 --- a/tests/data/anna/anna_elga_2.json +++ b/tests/data/anna/anna_elga_2.json @@ -94,6 +94,7 @@ "sensors": { "outdoor_temperature": 6.38 }, - "vendor": "Plugwise" + "vendor": "Plugwise", + "wifi_mac_address": "C4930002FE77" } } diff --git a/tests/data/anna/anna_loria_driessens.json b/tests/data/anna/anna_loria_driessens.json index 1378b2d45..cbf087e31 100644 --- a/tests/data/anna/anna_loria_driessens.json +++ b/tests/data/anna/anna_loria_driessens.json @@ -15,7 +15,8 @@ "sensors": { "outdoor_temperature": 6.81 }, - "vendor": "Plugwise" + "vendor": "Plugwise", + "wifi_mac_address": "D40FB2011557" }, "9fb768d699e44c7fb5cc50309dc4e7d4": { "active_preset": "home", diff --git a/tests/data/anna/anna_p1.json b/tests/data/anna/anna_p1.json index cd637d48e..cacbc7e46 100644 --- a/tests/data/anna/anna_p1.json +++ b/tests/data/anna/anna_p1.json @@ -84,7 +84,8 @@ "sensors": { "outdoor_temperature": 11.8 }, - "vendor": "Plugwise" + "vendor": "Plugwise", + "wifi_mac_address": "C4930002ABCE" }, "da7be222ab3b420c927f3e49fade0304": { "available": true, diff --git a/tests/data/anna/anna_without_boiler_fw441.json b/tests/data/anna/anna_without_boiler_fw441.json index cc1f3bdff..5dbecb4dd 100644 --- a/tests/data/anna/anna_without_boiler_fw441.json +++ b/tests/data/anna/anna_without_boiler_fw441.json @@ -57,7 +57,8 @@ "sensors": { "outdoor_temperature": 8.31 }, - "vendor": "Plugwise" + "vendor": "Plugwise", + "wifi_mac_address": "D40FB200FA1D" }, "c46b4794d28149699eacf053deedd003": { "binary_sensors": { diff --git a/tests/data/p1/p1v4_442_single.json b/tests/data/p1/p1v4_442_single.json index 6dfcd7ee0..f457c6c09 100644 --- a/tests/data/p1/p1v4_442_single.json +++ b/tests/data/p1/p1v4_442_single.json @@ -12,7 +12,8 @@ "model_id": "smile", "name": "Smile P1", "notifications": {}, - "vendor": "Plugwise" + "vendor": "Plugwise", + "wifi_mac_address": "012345670002" }, "ba4de7613517478da82dd9b6abea36af": { "available": true, diff --git a/tests/data/p1/p1v4_442_triple.json b/tests/data/p1/p1v4_442_triple.json index 943325d14..c5989ce4b 100644 --- a/tests/data/p1/p1v4_442_triple.json +++ b/tests/data/p1/p1v4_442_triple.json @@ -16,7 +16,8 @@ "warning": "The Smile P1 is not connected to a smart meter." } }, - "vendor": "Plugwise" + "vendor": "Plugwise", + "wifi_mac_address": "012345670002" }, "b82b6b3322484f2ea4e25e0bd5f3d61f": { "available": true, diff --git a/tests/test_adam.py b/tests/test_adam.py index 3cd9d1d41..34c680026 100644 --- a/tests/test_adam.py +++ b/tests/test_adam.py @@ -47,7 +47,7 @@ async def test_connect_adam_plus_anna_new(self): test_items = await self.device_test(api, "2025-10-12 00:00:01", testdata) assert api.gateway_id == "da224107914542988a88561b4452b0f6" - assert self.entity_items == 234 + assert self.entity_items == 235 assert test_items == self.entity_items assert self.entity_list == [ "da224107914542988a88561b4452b0f6", diff --git a/tests/test_anna.py b/tests/test_anna.py index ff390da68..1b3dc21be 100644 --- a/tests/test_anna.py +++ b/tests/test_anna.py @@ -158,7 +158,7 @@ async def test_connect_anna_without_boiler_fw441(self): ) await self.device_test(api, "2022-05-16 00:00:01", testdata) - assert self.entity_items == 41 + assert self.entity_items == 42 assert not self.notifications result = await self.tinker_thermostat( @@ -336,7 +336,7 @@ async def test_connect_anna_elga_2(self): ) await self.device_test(api, "2022-03-13 00:00:01", testdata) - assert self.entity_items == 63 + assert self.entity_items == 64 assert api.gateway_id == "fb49af122f6e4b0f91267e1cf7666d6f" assert self.cooling_present assert not self._cooling_enabled @@ -532,7 +532,7 @@ async def test_connect_anna_loria_driessens(self): ) await self.device_test(api, "2022-05-16 00:00:01", testdata) - assert self.entity_items == 70 + assert self.entity_items == 71 assert self.cooling_present assert not self._cooling_enabled @@ -555,7 +555,7 @@ async def test_connect_anna_p1(self): ) await self.device_test(api, "2025-11-02 00:00:01", testdata) - assert self.entity_items == 78 + assert self.entity_items == 79 await api.close_connection() await self.disconnect(server, client) diff --git a/tests/test_p1.py b/tests/test_p1.py index 1c459d216..80af2b91a 100644 --- a/tests/test_p1.py +++ b/tests/test_p1.py @@ -28,7 +28,7 @@ async def test_connect_p1v4_442_single(self): await self.device_test(api, "2022-05-16 00:00:01", testdata) assert api.gateway_id == "a455b61e52394b2db5081ce025a430f3" - assert self.entity_items == 33 + assert self.entity_items == 34 assert not self.notifications # Now change some data and change directory reading xml from @@ -78,7 +78,7 @@ async def test_connect_p1v4_442_triple(self): await self.device_test(api, "2022-05-16 00:00:01", testdata) assert api.gateway_id == "03e65b16e4b247a29ae0d75a78cb492e" - assert self.entity_items == 42 + assert self.entity_items == 43 assert self.notifications await api.close_connection()