Bump plugwise to v1.7.7 and adapt (#147809)

This commit is contained in:
Bouwe Westerdijk 2025-06-30 15:40:10 +02:00 committed by GitHub
parent ea70229426
commit b52a248def
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 177 additions and 126 deletions

View File

@ -27,10 +27,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
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

View File

@ -39,7 +39,7 @@ async def async_setup_entry(
if not coordinator.new_devices:
return
if coordinator.api.smile_name == "Adam":
if coordinator.api.smile.name == "Adam":
async_add_entities(
PlugwiseClimateEntity(coordinator, device_id)
for device_id in coordinator.new_devices
@ -85,7 +85,7 @@ class PlugwiseClimateEntity(PlugwiseEntity, ClimateEntity):
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

View File

@ -204,11 +204,11 @@ class PlugwiseConfigFlow(ConfigFlow, domain=DOMAIN):
api, errors = await verify_connection(self.hass, user_input)
if api:
await self.async_set_unique_id(
api.smile_hostname or api.gateway_id,
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)
return self.async_show_form(
step_id=SOURCE_USER,
@ -236,7 +236,7 @@ class PlugwiseConfigFlow(ConfigFlow, domain=DOMAIN):
api, errors = await verify_connection(self.hass, full_input)
if api:
await self.async_set_unique_id(
api.smile_hostname or api.gateway_id,
api.smile.hostname or api.gateway_id,
raise_on_progress=False,
)
self._abort_if_unique_id_mismatch(reason="not_the_same_smile")

View File

@ -48,7 +48,7 @@ class PlugwiseEntity(CoordinatorEntity[PlugwiseDataUpdateCoordinator]):
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"),
)

View File

@ -8,6 +8,6 @@
"iot_class": "local_polling",
"loggers": ["plugwise"],
"quality_scale": "platinum",
"requirements": ["plugwise==1.7.6"],
"requirements": ["plugwise==1.7.7"],
"zeroconf": ["_plugwise._tcp.local."]
}

2
requirements_all.txt generated
View File

@ -1689,7 +1689,7 @@ plexauth==0.0.6
plexwebsocket==0.0.14
# homeassistant.components.plugwise
plugwise==1.7.6
plugwise==1.7.7
# homeassistant.components.plum_lightpad
plumlightpad==0.0.11

View File

@ -1427,7 +1427,7 @@ plexauth==0.0.6
plexwebsocket==0.0.14
# homeassistant.components.plugwise
plugwise==1.7.6
plugwise==1.7.7
# homeassistant.components.plum_lightpad
plumlightpad==0.0.11

View File

@ -7,6 +7,7 @@ import json
from typing import Any
from unittest.mock import AsyncMock, MagicMock, patch
from munch import Munch
from packaging.version import Version
import pytest
@ -23,6 +24,14 @@ from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry, load_fixture
def build_smile(**attrs):
"""Build smile Munch from provided attributes."""
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,17 +115,19 @@ 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_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 = build_smile(
hostname="smile12345",
model="Test Model",
model_id="Test Model ID",
name="Test Smile Name",
version="4.3.2",
)
yield smile
yield api
@pytest.fixture
@ -127,28 +138,30 @@ 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_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 = build_smile(
hostname="smile98765",
model="Gateway",
model_id="smile_open_therm",
name="Adam",
type="thermostat",
version="3.0.15",
)
yield smile
yield api
@pytest.fixture
@ -159,23 +172,25 @@ def mock_smile_adam_heat_cool(
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("3.6.4")
smile.cooling_present = cooling_present
smile.gateway_id = "da224107914542988a88561b4452b0f6"
smile.heater_id = "056ee145a816487eaa69243c3280f8bf"
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.6.4"
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 = build_smile(
hostname="smile98765",
model="Gateway",
model_id="smile_open_therm",
name="Adam",
type="thermostat",
version="3.6.4",
)
yield smile
yield api
@pytest.fixture
@ -185,23 +200,25 @@ def mock_smile_adam_jip() -> 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("3.2.8")
smile.cooling_present = False
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"
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 = build_smile(
hostname="smile98765",
model="Gateway",
model_id="smile_open_therm",
name="Adam",
type="thermostat",
version="3.2.8",
)
yield smile
yield api
@pytest.fixture
@ -210,23 +227,25 @@ 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
) as api_mock:
api = api_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_hostname = "smile98765"
smile.smile_model = "Gateway"
smile.smile_model_id = "smile_thermo"
smile.smile_name = "Smile Anna"
smile.smile_type = "thermostat"
smile.smile_version = "4.0.15"
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 = build_smile(
hostname="smile98765",
model="Gateway",
model_id="smile_thermo",
name="Smile Anna",
type="thermostat",
version="4.0.15",
)
yield smile
yield api
@pytest.fixture
@ -235,22 +254,24 @@ 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_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 = build_smile(
hostname="smile98765",
model="Gateway",
model_id="smile",
name="Smile P1",
type="power",
version="4.4.2",
)
yield smile
yield api
@pytest.fixture
@ -260,22 +281,24 @@ 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_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 = build_smile(
hostname="smile98765",
model="Gateway",
model_id=None,
name="Smile Anna",
type="thermostat",
version="1.8.22",
)
yield smile
yield api
@pytest.fixture
@ -285,22 +308,24 @@ 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
) as api_mock:
api = api_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_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"
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 = build_smile(
hostname="stretch98765",
model="Gateway",
model_id=None,
name="Stretch",
type="stretch",
version="3.1.11",
)
yield smile
yield api
@pytest.fixture

View File

@ -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": {

View File

@ -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({

View File

@ -478,7 +478,7 @@ async def test_reconfigure_flow_smile_mismatch(
mock_config_entry: MockConfigEntry,
) -> None:
"""Test reconfigure flow aborts on other Smile ID."""
mock_smile_adam.smile_hostname = TEST_SMILE_HOST
mock_smile_adam.smile.hostname = TEST_SMILE_HOST
result = await _start_reconfigure_flow(hass, mock_config_entry, TEST_HOST)