From 0d6d8c4d4d25fd7b9fa6c6e3aeaec070b92d776b Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sat, 28 Jun 2025 17:34:13 +0200 Subject: [PATCH 01/13] Link to plugwise v1.7.7 --- 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 cc7819379..718a6462c 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.7.6"], + "requirements": ["plugwise==1.7.7"], "version": "0.57.4", "zeroconf": ["_plugwise._tcp.local."] } From 3c2b2c71b248c3df6c59ef2a24b7b6558f0c0c8f Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sat, 28 Jun 2025 17:43:44 +0200 Subject: [PATCH 02/13] And adapt --- custom_components/plugwise/__init__.py | 12 +-- custom_components/plugwise/climate.py | 4 +- custom_components/plugwise/config_flow.py | 10 +-- custom_components/plugwise/coordinator.py | 4 +- custom_components/plugwise/entity.py | 2 +- tests/components/plugwise/conftest.py | 94 +++++++++++------------ 6 files changed, 63 insertions(+), 63 deletions(-) diff --git a/custom_components/plugwise/__init__.py b/custom_components/plugwise/__init__.py index 5c6070980..3d509da98 100644 --- a/custom_components/plugwise/__init__.py +++ b/custom_components/plugwise/__init__.py @@ -50,10 +50,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: PlugwiseConfigEntry) -> config_entry_id=entry.entry_id, identifiers={(DOMAIN, str(coordinator.api.gateway_id))}, manufacturer="Plugwise", - model=coordinator.api.smile_model, - model_id=coordinator.api.smile_model_id, - name=coordinator.api.smile_name, - sw_version=str(coordinator.api.smile_version), + model=coordinator.api.smile.model, + model_id=coordinator.api.smile.model_id, + name=coordinator.api.smile.name, + sw_version=str(coordinator.api.smile.version), ) # required for adding the entity-less P1 Gateway async def delete_notification( @@ -62,7 +62,7 @@ async def delete_notification( """Service: delete the Plugwise Notification.""" LOGGER.debug( "Service delete PW Notification called for %s", - coordinator.api.smile_name, + coordinator.api.smile.name, ) try: await coordinator.api.delete_notification() @@ -70,7 +70,7 @@ async def delete_notification( except PlugwiseError: LOGGER.debug( "Failed to delete the Plugwise Notification for %s", - coordinator.api.smile_name, + coordinator.api.smile.name, ) await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) diff --git a/custom_components/plugwise/climate.py b/custom_components/plugwise/climate.py index 72fa54b69..7d889b8a8 100644 --- a/custom_components/plugwise/climate.py +++ b/custom_components/plugwise/climate.py @@ -73,7 +73,7 @@ def _add_entities() -> None: return entities: list[PlugwiseClimateEntity] = [] - gateway_name = coordinator.api.smile_name + gateway_name = coordinator.api.smile.name for device_id in coordinator.new_devices: device = coordinator.data[device_id] if gateway_name == "Adam": @@ -139,7 +139,7 @@ def __init__( self._attr_supported_features = ClimateEntityFeature.TARGET_TEMPERATURE if ( self.coordinator.api.cooling_present - and coordinator.api.smile_name != "Adam" + and coordinator.api.smile.name != "Adam" ): self._attr_supported_features = ( ClimateEntityFeature.TARGET_TEMPERATURE_RANGE diff --git a/custom_components/plugwise/config_flow.py b/custom_components/plugwise/config_flow.py index f080902db..9a14e7fa1 100644 --- a/custom_components/plugwise/config_flow.py +++ b/custom_components/plugwise/config_flow.py @@ -245,10 +245,10 @@ async def async_step_user( api, errors = await verify_connection(self.hass, user_input) if api: await self.async_set_unique_id( - api.smile_hostname or api.gateway_id, raise_on_progress=False + api.smile.hostname or api.gateway_id, raise_on_progress=False ) self._abort_if_unique_id_configured() - return self.async_create_entry(title=api.smile_name, data=user_input) + return self.async_create_entry(title=api.smile.name, data=user_input) configure_input = self.discovery_info or user_input return self.async_show_form( @@ -278,7 +278,7 @@ async def async_step_reconfigure( api, errors = await verify_connection(self.hass, full_input) if api: await self.async_set_unique_id( - api.smile_hostname or api.gateway_id, raise_on_progress=False + api.smile.hostname or api.gateway_id, raise_on_progress=False ) self._abort_if_unique_id_mismatch(reason="not_the_same_smile") return self.async_update_reload_and_abort( @@ -317,7 +317,7 @@ def __init__(self, config_entry: ConfigEntry) -> None: self.options = deepcopy(dict(config_entry.options)) def _create_options_schema(self, coordinator: PlugwiseDataUpdateCoordinator) -> vol.Schema: - interval = DEFAULT_SCAN_INTERVAL[coordinator.api.smile_type] # pw-beta options + interval = DEFAULT_SCAN_INTERVAL[coordinator.api.smile.type] # pw-beta options schema = { vol.Optional( CONF_SCAN_INTERVAL, @@ -325,7 +325,7 @@ def _create_options_schema(self, coordinator: PlugwiseDataUpdateCoordinator) -> ): vol.All(cv.positive_int, vol.Clamp(min=10)), } # pw-beta - if coordinator.api.smile_type == THERMOSTAT: + if coordinator.api.smile.type == THERMOSTAT: schema.update({ vol.Optional( CONF_HOMEKIT_EMULATION, diff --git a/custom_components/plugwise/coordinator.py b/custom_components/plugwise/coordinator.py index a2973dc7c..7a5fc1dc9 100644 --- a/custom_components/plugwise/coordinator.py +++ b/custom_components/plugwise/coordinator.py @@ -83,7 +83,7 @@ async def _connect(self) -> None: self._connected = isinstance(version, Version) if self._connected: self.update_interval = DEFAULT_SCAN_INTERVAL.get( - self.api.smile_type, timedelta(seconds=60) + self.api.smile.type, timedelta(seconds=60) ) # pw-beta options scan-interval if (custom_time := self.config_entry.options.get(CONF_SCAN_INTERVAL)) is not None: self.update_interval = timedelta( @@ -125,7 +125,7 @@ async def _async_update_data(self) -> dict[str, GwEntityData]: translation_key="unsupported_firmware", ) from err - LOGGER.debug(f"{self.api.smile_name} data: %s", data) + LOGGER.debug(f"{self.api.smile.name} data: %s", data) await self._async_add_remove_devices(data) return data diff --git a/custom_components/plugwise/entity.py b/custom_components/plugwise/entity.py index 5ffbc5cf5..17705b13a 100644 --- a/custom_components/plugwise/entity.py +++ b/custom_components/plugwise/entity.py @@ -60,7 +60,7 @@ def __init__( manufacturer=data.get(VENDOR), model=data.get(MODEL), model_id=data.get(MODEL_ID), - name=coordinator.api.smile_name, + name=coordinator.api.smile.name, sw_version=data.get(FIRMWARE), hw_version=data.get(HARDWARE), ) diff --git a/tests/components/plugwise/conftest.py b/tests/components/plugwise/conftest.py index 1148b7942..b9775e68b 100644 --- a/tests/components/plugwise/conftest.py +++ b/tests/components/plugwise/conftest.py @@ -105,11 +105,11 @@ def mock_smile_config_flow() -> Generator[MagicMock]: smile = smile_mock.return_value smile.connect.return_value = Version("4.3.2") - smile.smile_hostname = "smile12345" - smile.smile_model = "Test Model" - smile.smile_model_id = "Test Model ID" - smile.smile_name = "Test Smile Name" - smile.smile_version = "4.3.2" + smile.smile.hostname = "smile12345" + smile.smile.model = "Test Model" + smile.smile.model_id = "Test Model ID" + smile.smile.name = "Test Smile Name" + smile.smile.version = "4.3.2" yield smile @@ -136,12 +136,12 @@ def mock_smile_adam() -> Generator[MagicMock]: smile.gateway_id = "fe799307f1624099878210aa0b9f1475" smile.heater_id = "90986d591dcd426cae3ec3e8111ff730" smile.reboot = True - smile.smile_hostname = "smile98765" - smile.smile_model = "Gateway" - smile.smile_model_id = "smile_open_therm" - smile.smile_name = "Adam" - smile.smile_type = "thermostat" - smile.smile_version = "3.0.15" + smile.smile.hostname = "smile98765" + smile.smile.model = "Gateway" + smile.smile.model_id = "smile_open_therm" + smile.smile.name = "Adam" + smile.smile.type = "thermostat" + smile.smile.version = "3.0.15" yield smile @@ -161,12 +161,12 @@ def mock_smile_adam_heat_cool(chosen_env: str, cooling_present: bool) -> Generat smile.gateway_id = "da224107914542988a88561b4452b0f6" smile.heater_id = "056ee145a816487eaa69243c3280f8bf" smile.reboot = True - smile.smile_version = "3.6.4" - smile.smile_type = "thermostat" - smile.smile_hostname = "smile98765" - smile.smile_model = "Gateway" - smile.smile_model_id = "smile_open_therm" - smile.smile_name = "Adam" + smile.smile.version = "3.6.4" + smile.smile.type = "thermostat" + smile.smile.hostname = "smile98765" + smile.smile.model = "Gateway" + smile.smile.model_id = "smile_open_therm" + smile.smile.name = "Adam" yield smile @@ -187,12 +187,12 @@ def mock_smile_adam_4() -> Generator[MagicMock]: smile.gateway_id = "b5c2386c6f6342669e50fe49dd05b188" smile.heater_id = "e4684553153b44afbef2200885f379dc" smile.reboot = True - smile.smile_hostname = "smile98765" - smile.smile_model = "Gateway" - smile.smile_model_id = "smile_open_therm" - smile.smile_name = "Adam" - smile.smile_type = "thermostat" - smile.smile_version = "3.2.8" + smile.smile.hostname = "smile98765" + smile.smile.model = "Gateway" + smile.smile.model_id = "smile_open_therm" + smile.smile.name = "Adam" + smile.smile.type = "thermostat" + smile.smile.version = "3.2.8" yield smile @@ -212,12 +212,12 @@ def mock_smile_anna(chosen_env: str, cooling_present: bool) -> Generator[MagicMo smile.gateway_id = "015ae9ea3f964e668e490fa39da3870b" smile.heater_id = "1cbf783bb11e4a7c8a6843dee3a86927" smile.reboot = True - smile.smile_version = "4.0.15" - smile.smile_type = "thermostat" - smile.smile_hostname = "smile98765" - smile.smile_model = "Gateway" - smile.smile_model_id = "smile_thermo" - smile.smile_name = "Smile Anna" + smile.smile.version = "4.0.15" + smile.smile.type = "thermostat" + smile.smile.hostname = "smile98765" + smile.smile.model = "Gateway" + smile.smile.model_id = "smile_thermo" + smile.smile.name = "Smile Anna" yield smile @@ -236,12 +236,12 @@ def mock_smile_p1(chosen_env: str, gateway_id: str) -> Generator[MagicMock]: smile.gateway_id = gateway_id smile.heater_id = None smile.reboot = True - smile.smile_hostname = "smile98765" - smile.smile_model = "Gateway" - smile.smile_model_id = "smile" - smile.smile_name = "Smile P1" - smile.smile_type = "power" - smile.smile_version = "4.4.2" + smile.smile.hostname = "smile98765" + smile.smile.model = "Gateway" + smile.smile.model_id = "smile" + smile.smile.name = "Smile P1" + smile.smile.type = "power" + smile.smile.version = "4.4.2" yield smile @@ -261,12 +261,12 @@ def mock_smile_legacy_anna() -> Generator[MagicMock]: smile.gateway_id = "0000aaaa0000aaaa0000aaaa0000aa00" smile.heater_id = "04e4cbfe7f4340f090f85ec3b9e6a950" smile.reboot = False - smile.smile_hostname = "smile98765" - smile.smile_model = "Gateway" - smile.smile_model_id = None - smile.smile_name = "Smile Anna" - smile.smile_type = "thermostat" - smile.smile_version = "1.8.22" + smile.smile.hostname = "smile98765" + smile.smile.model = "Gateway" + smile.smile.model_id = None + smile.smile.name = "Smile Anna" + smile.smile.type = "thermostat" + smile.smile.version = "1.8.22" yield smile @@ -286,12 +286,12 @@ def mock_stretch() -> Generator[MagicMock]: smile.gateway_id = "259882df3c05415b99c2d962534ce820" smile.heater_id = None smile.reboot = False - smile.smile_hostname = "stretch98765" - smile.smile_model = "Gateway" - smile.smile_model_id = None - smile.smile_name = "Stretch" - smile.smile_type = "stretch" - smile.smile_version = "3.1.11" + smile.smile.hostname = "stretch98765" + smile.smile.model = "Gateway" + smile.smile.model_id = None + smile.smile.name = "Stretch" + smile.smile.type = "stretch" + smile.smile.version = "3.1.11" yield smile From bdccca645cc96654cb3987746a0dd7e7d7a12ca2 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sat, 28 Jun 2025 17:54:59 +0200 Subject: [PATCH 03/13] Refresh test-fixtures --- .../m_adam_multiple_devices_per_zone/data.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) 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 7c38b1b21..06459a117 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 @@ -531,6 +531,19 @@ "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A11" }, + "e8ef2a01ed3b4139a53bf749204fe6b4": { + "dev_class": "switching", + "members": [ + "02cf28bfec924855854c544690a609ef", + "4a810418d5394b3f82727340b91ba740" + ], + "model": "Switchgroup", + "name": "Test", + "switches": { + "relay": true + }, + "vendor": "Plugwise" + }, "f1fee6043d3642a9b0a65297455f008e": { "available": true, "binary_sensors": { From a7ce5c1e9f3725e00707228cc50b4ed77d4aca2e Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sat, 28 Jun 2025 18:00:59 +0200 Subject: [PATCH 04/13] api.smile is now a Munch, define as such --- tests/components/plugwise/conftest.py | 9 +++++++++ tests/components/plugwise/test_config_flow.py | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/components/plugwise/conftest.py b/tests/components/plugwise/conftest.py index b9775e68b..4b65a70b5 100644 --- a/tests/components/plugwise/conftest.py +++ b/tests/components/plugwise/conftest.py @@ -17,6 +17,7 @@ CONF_USERNAME, ) from homeassistant.core import HomeAssistant +from munch import Munch from packaging.version import Version from tests.common import MockConfigEntry, load_fixture @@ -105,6 +106,7 @@ def mock_smile_config_flow() -> Generator[MagicMock]: smile = smile_mock.return_value smile.connect.return_value = Version("4.3.2") + smile.smile = Munch() smile.smile.hostname = "smile12345" smile.smile.model = "Test Model" smile.smile.model_id = "Test Model ID" @@ -136,6 +138,7 @@ def mock_smile_adam() -> Generator[MagicMock]: smile.gateway_id = "fe799307f1624099878210aa0b9f1475" smile.heater_id = "90986d591dcd426cae3ec3e8111ff730" smile.reboot = True + smile.smile = Munch() smile.smile.hostname = "smile98765" smile.smile.model = "Gateway" smile.smile.model_id = "smile_open_therm" @@ -161,6 +164,7 @@ def mock_smile_adam_heat_cool(chosen_env: str, cooling_present: bool) -> Generat smile.gateway_id = "da224107914542988a88561b4452b0f6" smile.heater_id = "056ee145a816487eaa69243c3280f8bf" smile.reboot = True + smile.smile = Munch() smile.smile.version = "3.6.4" smile.smile.type = "thermostat" smile.smile.hostname = "smile98765" @@ -187,6 +191,7 @@ def mock_smile_adam_4() -> Generator[MagicMock]: smile.gateway_id = "b5c2386c6f6342669e50fe49dd05b188" smile.heater_id = "e4684553153b44afbef2200885f379dc" smile.reboot = True + smile.smile = Munch() smile.smile.hostname = "smile98765" smile.smile.model = "Gateway" smile.smile.model_id = "smile_open_therm" @@ -212,6 +217,7 @@ def mock_smile_anna(chosen_env: str, cooling_present: bool) -> Generator[MagicMo smile.gateway_id = "015ae9ea3f964e668e490fa39da3870b" smile.heater_id = "1cbf783bb11e4a7c8a6843dee3a86927" smile.reboot = True + smile.smile = Munch() smile.smile.version = "4.0.15" smile.smile.type = "thermostat" smile.smile.hostname = "smile98765" @@ -236,6 +242,7 @@ def mock_smile_p1(chosen_env: str, gateway_id: str) -> Generator[MagicMock]: smile.gateway_id = gateway_id smile.heater_id = None smile.reboot = True + smile.smile = Munch() smile.smile.hostname = "smile98765" smile.smile.model = "Gateway" smile.smile.model_id = "smile" @@ -261,6 +268,7 @@ def mock_smile_legacy_anna() -> Generator[MagicMock]: smile.gateway_id = "0000aaaa0000aaaa0000aaaa0000aa00" smile.heater_id = "04e4cbfe7f4340f090f85ec3b9e6a950" smile.reboot = False + smile.smile = Munch() smile.smile.hostname = "smile98765" smile.smile.model = "Gateway" smile.smile.model_id = None @@ -286,6 +294,7 @@ def mock_stretch() -> Generator[MagicMock]: smile.gateway_id = "259882df3c05415b99c2d962534ce820" smile.heater_id = None smile.reboot = False + smile.smile = Munch() smile.smile.hostname = "stretch98765" smile.smile.model = "Gateway" smile.smile.model_id = None diff --git a/tests/components/plugwise/test_config_flow.py b/tests/components/plugwise/test_config_flow.py index 9db611514..777d2c282 100644 --- a/tests/components/plugwise/test_config_flow.py +++ b/tests/components/plugwise/test_config_flow.py @@ -504,7 +504,7 @@ async def test_reconfigure_flow_other_smile( mock_config_entry: MockConfigEntry, ) -> None: """Test reconfigure flow aborts on other Smile ID.""" - mock_smile_adam.smile_hostname = TEST_SMILE_ID + mock_smile_adam.smile.hostname = TEST_SMILE_ID result = await _start_reconfigure_flow(hass, mock_config_entry, TEST_HOST) From 8221159af5ef8644c8da3f42019e3b4d891901a5 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sat, 28 Jun 2025 18:12:05 +0200 Subject: [PATCH 05/13] Update diagnostics snapshot file --- .../plugwise/snapshots/test_diagnostics.ambr | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/components/plugwise/snapshots/test_diagnostics.ambr b/tests/components/plugwise/snapshots/test_diagnostics.ambr index 92ed327b8..4aa367bc1 100644 --- a/tests/components/plugwise/snapshots/test_diagnostics.ambr +++ b/tests/components/plugwise/snapshots/test_diagnostics.ambr @@ -579,6 +579,19 @@ 'vendor': 'Plugwise', 'zigbee_mac_address': 'ABCD012345670A11', }), + 'e8ef2a01ed3b4139a53bf749204fe6b4': dict({ + 'dev_class': 'switching', + 'members': list([ + '02cf28bfec924855854c544690a609ef', + '4a810418d5394b3f82727340b91ba740', + ]), + 'model': 'Switchgroup', + 'name': 'Test', + 'switches': dict({ + 'relay': True, + }), + 'vendor': 'Plugwise', + }), 'f1fee6043d3642a9b0a65297455f008e': dict({ 'available': True, 'binary_sensors': dict({ From a478547b06d9d258fc0fedb57de0bb268eb39469 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sat, 28 Jun 2025 18:53:43 +0200 Subject: [PATCH 06/13] Update CHANGELOG --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d8128116..0740b07c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ Versions from 0.40 and up +## v0.57.5 + +- Bump plugwise to [v1.7.7](https://github.com/plugwise/python-plugwise/releases/tag/v1.7.7) and adapt + ## v0.57.4 - Maintenance chores on CI From 36c3b0047c53f7e6925dc1cf310af4074f1998ee Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sat, 28 Jun 2025 18:54:34 +0200 Subject: [PATCH 07/13] Bump to v0.57.5a0 test-version --- custom_components/plugwise/manifest.json | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/plugwise/manifest.json b/custom_components/plugwise/manifest.json index 718a6462c..8cf329ec2 100644 --- a/custom_components/plugwise/manifest.json +++ b/custom_components/plugwise/manifest.json @@ -8,6 +8,6 @@ "iot_class": "local_polling", "loggers": ["plugwise"], "requirements": ["plugwise==1.7.7"], - "version": "0.57.4", + "version": "0.57.5", "zeroconf": ["_plugwise._tcp.local."] } diff --git a/pyproject.toml b/pyproject.toml index f4db6c427..4091ac66f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "plugwise-beta" -version = "0.57.4" +version = "0.57.5a0" description = "Plugwise beta custom-component" readme = "README.md" requires-python = ">=3.13" From 21d64984d3d1379432c75fd3955b294629991297 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Tue, 24 Jun 2025 15:45:20 +0200 Subject: [PATCH 08/13] Implement improvement suggestions from SonarCloud --- custom_components/plugwise/coordinator.py | 28 +++++++++++------------ tests/components/plugwise/test_init.py | 4 ++-- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/custom_components/plugwise/coordinator.py b/custom_components/plugwise/coordinator.py index 7a5fc1dc9..ec17d4e02 100644 --- a/custom_components/plugwise/coordinator.py +++ b/custom_components/plugwise/coordinator.py @@ -154,17 +154,17 @@ async def _async_remove_devices(self, data: dict[str, GwEntityData]) -> None: # Then remove the connected orphaned device(s) for device_entry in device_list: for identifier in device_entry.identifiers: - if identifier[0] == DOMAIN: - if ( - device_entry.via_device_id == via_device_id - and identifier[1] not in data - ): - device_reg.async_update_device( - device_entry.id, remove_config_entry_id=self.config_entry.entry_id - ) - LOGGER.debug( - "Removed %s device/zone %s %s from device_registry", - DOMAIN, - device_entry.model, - identifier[1], - ) + if ( + identifier[0] == DOMAIN + and device_entry.via_device_id == via_device_id + and identifier[1] not in data + ): + device_reg.async_update_device( + device_entry.id, remove_config_entry_id=self.config_entry.entry_id + ) + LOGGER.debug( + "Removed %s device/zone %s %s from device_registry", + DOMAIN, + device_entry.model, + identifier[1], + ) diff --git a/tests/components/plugwise/test_init.py b/tests/components/plugwise/test_init.py index 5133a0839..a307b7b78 100644 --- a/tests/components/plugwise/test_init.py +++ b/tests/components/plugwise/test_init.py @@ -328,7 +328,7 @@ async def test_update_device( == 9 ) item_list: list[str] = [] - for device_entry in list(device_registry.devices.values()): + for device_entry in device_registry.devices.values(): item_list.extend(x[1] for x in device_entry.identifiers) assert "01234567890abcdefghijklmnopqrstu" in item_list @@ -355,6 +355,6 @@ async def test_update_device( == 8 ) item_list: list[str] = [] - for device_entry in list(device_registry.devices.values()): + for device_entry in device_registry.devices.values(): item_list.extend(x[1] for x in device_entry.identifiers) assert "1772a4ea304041adb83f357b751341ff" not in item_list From baab238cb1e6ac3e3964fc65fb4b404bf5eaf833 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sat, 28 Jun 2025 19:05:27 +0200 Subject: [PATCH 09/13] Update CHANGELOG --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0740b07c8..f4e4415c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ Versions from 0.40 and up ## v0.57.5 -- Bump plugwise to [v1.7.7](https://github.com/plugwise/python-plugwise/releases/tag/v1.7.7) and adapt +- Bump plugwise to [v1.7.7](https://github.com/plugwise/python-plugwise/releases/tag/v1.7.7) and adapt, small improvements ## v0.57.4 From fa2cb515fe02a1ac6fb3a4e060b3aaac01f3bbaf Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sun, 29 Jun 2025 07:32:50 +0200 Subject: [PATCH 10/13] Change smile to api to avoid smile.smile.x naming --- tests/components/plugwise/conftest.py | 256 +++++++++++++------------- 1 file changed, 128 insertions(+), 128 deletions(-) diff --git a/tests/components/plugwise/conftest.py b/tests/components/plugwise/conftest.py index 4b65a70b5..7d21ee985 100644 --- a/tests/components/plugwise/conftest.py +++ b/tests/components/plugwise/conftest.py @@ -102,18 +102,18 @@ def mock_smile_config_flow() -> Generator[MagicMock]: with patch( "homeassistant.components.plugwise.config_flow.Smile", autospec=True, - ) as smile_mock: - smile = smile_mock.return_value + ) as api_mock: + api = api_mock.return_value - smile.connect.return_value = Version("4.3.2") - smile.smile = Munch() - smile.smile.hostname = "smile12345" - smile.smile.model = "Test Model" - smile.smile.model_id = "Test Model ID" - smile.smile.name = "Test Smile Name" - smile.smile.version = "4.3.2" + api.connect.return_value = Version("4.3.2") + api.smile = Munch() + api.smile.hostname = "smile12345" + api.smile.model = "Test Model" + api.smile.model_id = "Test Model ID" + api.smile.name = "Test Smile Name" + api.smile.version = "4.3.2" - yield smile + yield api @pytest.fixture @@ -124,29 +124,29 @@ def mock_smile_adam() -> Generator[MagicMock]: with ( patch( "homeassistant.components.plugwise.coordinator.Smile", autospec=True - ) as smile_mock, + ) as api_mock, patch( "homeassistant.components.plugwise.config_flow.Smile", - new=smile_mock, + new=api_mock, ), ): - smile = smile_mock.return_value + api = api_mock.return_value - smile.async_update.return_value = data - smile.cooling_present = False - smile.connect.return_value = Version("3.0.15") - smile.gateway_id = "fe799307f1624099878210aa0b9f1475" - smile.heater_id = "90986d591dcd426cae3ec3e8111ff730" - smile.reboot = True - smile.smile = Munch() - smile.smile.hostname = "smile98765" - smile.smile.model = "Gateway" - smile.smile.model_id = "smile_open_therm" - smile.smile.name = "Adam" - smile.smile.type = "thermostat" - smile.smile.version = "3.0.15" + api.async_update.return_value = data + api.cooling_present = False + api.connect.return_value = Version("3.0.15") + api.gateway_id = "fe799307f1624099878210aa0b9f1475" + api.heater_id = "90986d591dcd426cae3ec3e8111ff730" + api.reboot = True + api.smile = Munch() + api.smile.hostname = "smile98765" + api.smile.model = "Gateway" + api.smile.model_id = "smile_open_therm" + api.smile.name = "Adam" + api.smile.type = "thermostat" + api.smile.version = "3.0.15" - yield smile + yield api @pytest.fixture @@ -155,24 +155,24 @@ def mock_smile_adam_heat_cool(chosen_env: str, cooling_present: bool) -> Generat data = _read_json(chosen_env, "data") with patch( "homeassistant.components.plugwise.coordinator.Smile", autospec=True - ) as smile_mock: - smile = smile_mock.return_value - - smile.async_update.return_value = data - smile.connect.return_value = Version("3.6.4") - smile.cooling_present = cooling_present - smile.gateway_id = "da224107914542988a88561b4452b0f6" - smile.heater_id = "056ee145a816487eaa69243c3280f8bf" - smile.reboot = True - smile.smile = Munch() - smile.smile.version = "3.6.4" - smile.smile.type = "thermostat" - smile.smile.hostname = "smile98765" - smile.smile.model = "Gateway" - smile.smile.model_id = "smile_open_therm" - smile.smile.name = "Adam" - - yield smile + ) as api_mock: + api = api_mock.return_value + + api.async_update.return_value = data + api.connect.return_value = Version("3.6.4") + api.cooling_present = cooling_present + api.gateway_id = "da224107914542988a88561b4452b0f6" + api.heater_id = "056ee145a816487eaa69243c3280f8bf" + api.reboot = True + api.smile = Munch() + api.smile.version = "3.6.4" + api.smile.type = "thermostat" + api.smile.hostname = "smile98765" + api.smile.model = "Gateway" + api.smile.model_id = "smile_open_therm" + api.smile.name = "Adam" + + yield api @pytest.fixture @@ -182,24 +182,24 @@ def mock_smile_adam_4() -> Generator[MagicMock]: data = _read_json(chosen_env, "data") with patch( "homeassistant.components.plugwise.coordinator.Smile", autospec=True - ) as smile_mock: - smile = smile_mock.return_value - - smile.async_update.return_value = data - smile.connect.return_value = Version("3.2.8") - smile.cooling_present = False - smile.gateway_id = "b5c2386c6f6342669e50fe49dd05b188" - smile.heater_id = "e4684553153b44afbef2200885f379dc" - smile.reboot = True - smile.smile = Munch() - smile.smile.hostname = "smile98765" - smile.smile.model = "Gateway" - smile.smile.model_id = "smile_open_therm" - smile.smile.name = "Adam" - smile.smile.type = "thermostat" - smile.smile.version = "3.2.8" - - yield smile + ) as api_mock: + api = api_mock.return_value + + api.async_update.return_value = data + api.connect.return_value = Version("3.2.8") + api.cooling_present = False + api.gateway_id = "b5c2386c6f6342669e50fe49dd05b188" + api.heater_id = "e4684553153b44afbef2200885f379dc" + api.reboot = True + api.smile = Munch() + api.smile.hostname = "smile98765" + api.smile.model = "Gateway" + api.smile.model_id = "smile_open_therm" + api.smile.name = "Adam" + api.smile.type = "thermostat" + api.smile.version = "3.2.8" + + yield api @pytest.fixture @@ -208,24 +208,24 @@ def mock_smile_anna(chosen_env: str, cooling_present: bool) -> Generator[MagicMo data = _read_json(chosen_env, "data") with patch( "homeassistant.components.plugwise.coordinator.Smile", autospec=True - ) as smile_mock: - smile = smile_mock.return_value - - smile.async_update.return_value = data - smile.connect.return_value = Version("4.0.15") - smile.cooling_present = cooling_present - smile.gateway_id = "015ae9ea3f964e668e490fa39da3870b" - smile.heater_id = "1cbf783bb11e4a7c8a6843dee3a86927" - smile.reboot = True - smile.smile = Munch() - smile.smile.version = "4.0.15" - smile.smile.type = "thermostat" - smile.smile.hostname = "smile98765" - smile.smile.model = "Gateway" - smile.smile.model_id = "smile_thermo" - smile.smile.name = "Smile Anna" - - yield smile + ) as api_mock: + api = api_mock.return_value + + api.async_update.return_value = data + api.connect.return_value = Version("4.0.15") + api.cooling_present = cooling_present + api.gateway_id = "015ae9ea3f964e668e490fa39da3870b" + api.heater_id = "1cbf783bb11e4a7c8a6843dee3a86927" + api.reboot = True + api.smile = Munch() + api.smile.version = "4.0.15" + api.smile.type = "thermostat" + api.smile.hostname = "smile98765" + api.smile.model = "Gateway" + api.smile.model_id = "smile_thermo" + api.smile.name = "Smile Anna" + + yield api @pytest.fixture @@ -234,23 +234,23 @@ def mock_smile_p1(chosen_env: str, gateway_id: str) -> Generator[MagicMock]: data = _read_json(chosen_env, "data") with patch( "homeassistant.components.plugwise.coordinator.Smile", autospec=True - ) as smile_mock: - smile = smile_mock.return_value + ) as api_mock: + api = api_mock.return_value - smile.async_update.return_value = data - smile.connect.return_value = Version("4.4.2") - smile.gateway_id = gateway_id - smile.heater_id = None - smile.reboot = True - smile.smile = Munch() - smile.smile.hostname = "smile98765" - smile.smile.model = "Gateway" - smile.smile.model_id = "smile" - smile.smile.name = "Smile P1" - smile.smile.type = "power" - smile.smile.version = "4.4.2" + api.async_update.return_value = data + api.connect.return_value = Version("4.4.2") + api.gateway_id = gateway_id + api.heater_id = None + api.reboot = True + api.smile = Munch() + api.smile.hostname = "smile98765" + api.smile.model = "Gateway" + api.smile.model_id = "smile" + api.smile.name = "Smile P1" + api.smile.type = "power" + api.smile.version = "4.4.2" - yield smile + yield api @pytest.fixture @@ -260,23 +260,23 @@ def mock_smile_legacy_anna() -> Generator[MagicMock]: data = _read_json(chosen_env, "data") with patch( "homeassistant.components.plugwise.coordinator.Smile", autospec=True - ) as smile_mock: - smile = smile_mock.return_value + ) as api_mock: + api = api_mock.return_value - smile.async_update.return_value = data - smile.connect.return_value = Version("1.8.22") - smile.gateway_id = "0000aaaa0000aaaa0000aaaa0000aa00" - smile.heater_id = "04e4cbfe7f4340f090f85ec3b9e6a950" - smile.reboot = False - smile.smile = Munch() - smile.smile.hostname = "smile98765" - smile.smile.model = "Gateway" - smile.smile.model_id = None - smile.smile.name = "Smile Anna" - smile.smile.type = "thermostat" - smile.smile.version = "1.8.22" + api.async_update.return_value = data + api.connect.return_value = Version("1.8.22") + api.gateway_id = "0000aaaa0000aaaa0000aaaa0000aa00" + api.heater_id = "04e4cbfe7f4340f090f85ec3b9e6a950" + api.reboot = False + api.smile = Munch() + api.smile.hostname = "smile98765" + api.smile.model = "Gateway" + api.smile.model_id = None + api.smile.name = "Smile Anna" + api.smile.type = "thermostat" + api.smile.version = "1.8.22" - yield smile + yield api @pytest.fixture @@ -286,23 +286,23 @@ def mock_stretch() -> Generator[MagicMock]: data = _read_json(chosen_env, "data") with patch( "homeassistant.components.plugwise.coordinator.Smile", autospec=True - ) as smile_mock: - smile = smile_mock.return_value - - smile.async_update.return_value = data - smile.connect.return_value = Version("3.1.11") - smile.gateway_id = "259882df3c05415b99c2d962534ce820" - smile.heater_id = None - smile.reboot = False - smile.smile = Munch() - smile.smile.hostname = "stretch98765" - smile.smile.model = "Gateway" - smile.smile.model_id = None - smile.smile.name = "Stretch" - smile.smile.type = "stretch" - smile.smile.version = "3.1.11" - - yield smile + ) as api_mock: + api = api_mock.return_value + + api.async_update.return_value = data + api.connect.return_value = Version("3.1.11") + api.gateway_id = "259882df3c05415b99c2d962534ce820" + api.heater_id = None + api.reboot = False + api.smile = Munch() + api.smile.hostname = "stretch98765" + api.smile.model = "Gateway" + api.smile.model_id = None + api.smile.name = "Stretch" + api.smile.type = "stretch" + api.smile.version = "3.1.11" + + yield api @pytest.fixture From 600e0930ac5c3439ae626560ec148c0ead517dbe Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sun, 29 Jun 2025 07:44:33 +0200 Subject: [PATCH 11/13] Set to v0.57.5 release-version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 4091ac66f..1b5a6bada 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "plugwise-beta" -version = "0.57.5a0" +version = "0.57.5" description = "Plugwise beta custom-component" readme = "README.md" requires-python = ">=3.13" From cc41d1ec5fc1d5fccce77396dae3e819976ab322 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sun, 29 Jun 2025 08:02:06 +0200 Subject: [PATCH 12/13] Implement improvement suggestion --- tests/components/plugwise/conftest.py | 125 ++++++++++++++------------ 1 file changed, 70 insertions(+), 55 deletions(-) diff --git a/tests/components/plugwise/conftest.py b/tests/components/plugwise/conftest.py index 7d21ee985..841f7771c 100644 --- a/tests/components/plugwise/conftest.py +++ b/tests/components/plugwise/conftest.py @@ -23,6 +23,13 @@ from tests.common import MockConfigEntry, load_fixture +def build_smile(**attrs): + smile = Munch() + for k, v in attrs.items(): + setattr(smile, k, v) + return smile + + def _read_json(environment: str, call: str) -> dict[str, Any]: """Undecode the json data.""" fixture = load_fixture(f"plugwise/{environment}/{call}.json") @@ -106,12 +113,13 @@ def mock_smile_config_flow() -> Generator[MagicMock]: api = api_mock.return_value api.connect.return_value = Version("4.3.2") - api.smile = Munch() - api.smile.hostname = "smile12345" - api.smile.model = "Test Model" - api.smile.model_id = "Test Model ID" - api.smile.name = "Test Smile Name" - api.smile.version = "4.3.2" + api.smile = build_smile( + hostname = "smile12345", + model = "Test Model", + model_id = "Test Model ID", + name = "Test Smile Name", + version = "4.3.2", + ) yield api @@ -138,13 +146,14 @@ def mock_smile_adam() -> Generator[MagicMock]: api.gateway_id = "fe799307f1624099878210aa0b9f1475" api.heater_id = "90986d591dcd426cae3ec3e8111ff730" api.reboot = True - api.smile = Munch() - api.smile.hostname = "smile98765" - api.smile.model = "Gateway" - api.smile.model_id = "smile_open_therm" - api.smile.name = "Adam" - api.smile.type = "thermostat" - api.smile.version = "3.0.15" + api.smile = build_smile( + hostname = "smile98765", + model = "Gateway", + model_id = "smile_open_therm", + name = "Adam", + type = "thermostat", + version = "3.0.15", + ) yield api @@ -164,13 +173,14 @@ def mock_smile_adam_heat_cool(chosen_env: str, cooling_present: bool) -> Generat api.gateway_id = "da224107914542988a88561b4452b0f6" api.heater_id = "056ee145a816487eaa69243c3280f8bf" api.reboot = True - api.smile = Munch() - api.smile.version = "3.6.4" - api.smile.type = "thermostat" - api.smile.hostname = "smile98765" - api.smile.model = "Gateway" - api.smile.model_id = "smile_open_therm" - api.smile.name = "Adam" + api.smile = build_smile( + hostname = "smile98765", + model = "Gateway", + model_id = "smile_open_therm", + name = "Adam", + type = "thermostat", + version = "3.6.4", + ) yield api @@ -191,13 +201,14 @@ def mock_smile_adam_4() -> Generator[MagicMock]: api.gateway_id = "b5c2386c6f6342669e50fe49dd05b188" api.heater_id = "e4684553153b44afbef2200885f379dc" api.reboot = True - api.smile = Munch() - api.smile.hostname = "smile98765" - api.smile.model = "Gateway" - api.smile.model_id = "smile_open_therm" - api.smile.name = "Adam" - api.smile.type = "thermostat" - api.smile.version = "3.2.8" + api.smile = build_smile( + hostname = "smile98765", + model = "Gateway", + model_id = "smile_open_therm", + name = "Adam", + type = "thermostat", + version = "3.2.8", + ) yield api @@ -217,13 +228,14 @@ def mock_smile_anna(chosen_env: str, cooling_present: bool) -> Generator[MagicMo api.gateway_id = "015ae9ea3f964e668e490fa39da3870b" api.heater_id = "1cbf783bb11e4a7c8a6843dee3a86927" api.reboot = True - api.smile = Munch() - api.smile.version = "4.0.15" - api.smile.type = "thermostat" - api.smile.hostname = "smile98765" - api.smile.model = "Gateway" - api.smile.model_id = "smile_thermo" - api.smile.name = "Smile Anna" + api.smile = build_smile( + hostname = "smile98765", + model = "Gateway", + model_id = "smile_thermo", + name = "Smile Anna", + type = "thermostat", + version = "4.0.15", + ) yield api @@ -242,13 +254,14 @@ def mock_smile_p1(chosen_env: str, gateway_id: str) -> Generator[MagicMock]: api.gateway_id = gateway_id api.heater_id = None api.reboot = True - api.smile = Munch() - api.smile.hostname = "smile98765" - api.smile.model = "Gateway" - api.smile.model_id = "smile" - api.smile.name = "Smile P1" - api.smile.type = "power" - api.smile.version = "4.4.2" + api.smile = build_smile( + hostname = "smile98765", + model = "Gateway", + model_id = "smile", + name = "Smile P1", + type = "power", + version = "4.4.2", + ) yield api @@ -268,13 +281,14 @@ def mock_smile_legacy_anna() -> Generator[MagicMock]: api.gateway_id = "0000aaaa0000aaaa0000aaaa0000aa00" api.heater_id = "04e4cbfe7f4340f090f85ec3b9e6a950" api.reboot = False - api.smile = Munch() - api.smile.hostname = "smile98765" - api.smile.model = "Gateway" - api.smile.model_id = None - api.smile.name = "Smile Anna" - api.smile.type = "thermostat" - api.smile.version = "1.8.22" + api.smile = build_smile( + hostname = "smile98765", + model = "Gateway", + model_id = None, + name = "Smile Anna", + type = "thermostat", + version = "1.8.22", + ) yield api @@ -294,13 +308,14 @@ def mock_stretch() -> Generator[MagicMock]: api.gateway_id = "259882df3c05415b99c2d962534ce820" api.heater_id = None api.reboot = False - api.smile = Munch() - api.smile.hostname = "stretch98765" - api.smile.model = "Gateway" - api.smile.model_id = None - api.smile.name = "Stretch" - api.smile.type = "stretch" - api.smile.version = "3.1.11" + api.smile = build_smile( + hostname = "stretch98765", + model = "Gateway", + model_id = None, + name = "Stretch", + type = "stretch", + version = "3.1.11", + ) yield api From db5fad8e628f7f3ea8f9a75a2c917c8d83086252 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk Date: Sun, 29 Jun 2025 08:05:49 +0200 Subject: [PATCH 13/13] Add docstring to added function --- tests/components/plugwise/conftest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/components/plugwise/conftest.py b/tests/components/plugwise/conftest.py index 841f7771c..de96a5560 100644 --- a/tests/components/plugwise/conftest.py +++ b/tests/components/plugwise/conftest.py @@ -24,6 +24,7 @@ def build_smile(**attrs): + """Build smile Munch from provided attributes.""" smile = Munch() for k, v in attrs.items(): setattr(smile, k, v)