From 4efebcb86c92a1ebaae74a1bd209d723b23c7d2b Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Tue, 8 Feb 2022 19:08:01 +0100 Subject: [PATCH] Use upstream device information for Plugwise (#66074) --- .../components/plugwise/binary_sensor.py | 36 ++++------ homeassistant/components/plugwise/climate.py | 15 ++--- homeassistant/components/plugwise/entity.py | 65 +++++++------------ homeassistant/components/plugwise/sensor.py | 29 ++++----- homeassistant/components/plugwise/switch.py | 15 ++--- .../components/plugwise/test_binary_sensor.py | 20 +++--- tests/components/plugwise/test_sensor.py | 8 +-- 7 files changed, 70 insertions(+), 118 deletions(-) diff --git a/homeassistant/components/plugwise/binary_sensor.py b/homeassistant/components/plugwise/binary_sensor.py index 44d5e79ce16..1f5cfacb37e 100644 --- a/homeassistant/components/plugwise/binary_sensor.py +++ b/homeassistant/components/plugwise/binary_sensor.py @@ -1,6 +1,4 @@ """Plugwise Binary Sensor component for Home Assistant.""" -from plugwise.smile import Smile - from homeassistant.components.binary_sensor import ( BinarySensorEntity, BinarySensorEntityDescription, @@ -45,37 +43,32 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up the Smile binary_sensors from a config entry.""" - api: Smile = hass.data[DOMAIN][config_entry.entry_id]["api"] coordinator: PlugwiseDataUpdateCoordinator = hass.data[DOMAIN][ config_entry.entry_id ][COORDINATOR] entities: list[PlugwiseBinarySensorEntity] = [] - for device_id, device_properties in coordinator.data.devices.items(): - if device_properties["class"] == "heater_central": + for device_id, device in coordinator.data.devices.items(): + if device["class"] == "heater_central": for description in BINARY_SENSORS: if ( - "binary_sensors" not in device_properties - or description.key not in device_properties["binary_sensors"] + "binary_sensors" not in device + or description.key not in device["binary_sensors"] ): continue entities.append( PlugwiseBinarySensorEntity( - api, coordinator, - device_properties["name"], device_id, description, ) ) - if device_properties["class"] == "gateway": + if device["class"] == "gateway": entities.append( PlugwiseNotifyBinarySensorEntity( - api, coordinator, - device_properties["name"], device_id, BinarySensorEntityDescription( key="plugwise_notification", @@ -92,25 +85,18 @@ class PlugwiseBinarySensorEntity(PlugwiseEntity, BinarySensorEntity): def __init__( self, - api: Smile, coordinator: PlugwiseDataUpdateCoordinator, - name: str, - dev_id: str, + device_id: str, description: BinarySensorEntityDescription, ) -> None: """Initialise the binary_sensor.""" - super().__init__(api, coordinator, name, dev_id) + super().__init__(coordinator, device_id) self.entity_description = description self._attr_is_on = False - self._attr_unique_id = f"{dev_id}-{description.key}" - - if dev_id == coordinator.data.gateway["heater_id"]: - self._entity_name = "Auxiliary" - - self._name = f"{self._entity_name} {description.name}" - - if dev_id == coordinator.data.gateway["gateway_id"]: - self._entity_name = f"Smile {self._entity_name}" + self._attr_unique_id = f"{device_id}-{description.key}" + self._attr_name = ( + f"{coordinator.data.devices[device_id].get('name', '')} {description.name}" + ).lstrip() @callback def _async_process_data(self) -> None: diff --git a/homeassistant/components/plugwise/climate.py b/homeassistant/components/plugwise/climate.py index 49c73049a9a..1cfb4ab7c67 100644 --- a/homeassistant/components/plugwise/climate.py +++ b/homeassistant/components/plugwise/climate.py @@ -52,17 +52,14 @@ async def async_setup_entry( "zone_thermostat", "thermostatic_radiator_valve", ] - for device_id, device_properties in coordinator.data.devices.items(): - if device_properties["class"] not in thermostat_classes: + for device_id, device in coordinator.data.devices.items(): + if device["class"] not in thermostat_classes: continue thermostat = PlugwiseClimateEntity( api, coordinator, - device_properties["name"], device_id, - device_properties["location"], - device_properties["class"], ) entities.append(thermostat) @@ -87,18 +84,16 @@ class PlugwiseClimateEntity(PlugwiseEntity, ClimateEntity): self, api: Smile, coordinator: PlugwiseDataUpdateCoordinator, - name: str, device_id: str, - loc_id: str, - model: str, ) -> None: """Set up the Plugwise API.""" - super().__init__(api, coordinator, name, device_id) + super().__init__(coordinator, device_id) self._attr_extra_state_attributes = {} self._attr_unique_id = f"{device_id}-climate" + self._attr_name = coordinator.data.devices[device_id].get("name") self._api = api - self._loc_id = loc_id + self._loc_id = coordinator.data.devices[device_id]["location"] self._presets = None diff --git a/homeassistant/components/plugwise/entity.py b/homeassistant/components/plugwise/entity.py index c57f9c9281f..2f73d38e5e3 100644 --- a/homeassistant/components/plugwise/entity.py +++ b/homeassistant/components/plugwise/entity.py @@ -1,14 +1,7 @@ """Generic Plugwise Entity Class.""" from __future__ import annotations -from plugwise.smile import Smile - -from homeassistant.const import ( - ATTR_CONFIGURATION_URL, - ATTR_MODEL, - ATTR_VIA_DEVICE, - CONF_HOST, -) +from homeassistant.const import ATTR_NAME, ATTR_VIA_DEVICE, CONF_HOST from homeassistant.core import callback from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.update_coordinator import CoordinatorEntity @@ -22,50 +15,38 @@ class PlugwiseEntity(CoordinatorEntity[PlugwiseData]): def __init__( self, - api: Smile, coordinator: PlugwiseDataUpdateCoordinator, - name: str, - dev_id: str, + device_id: str, ) -> None: """Initialise the gateway.""" super().__init__(coordinator) + self._dev_id = device_id - self._api = api - self._name = name - self._dev_id = dev_id - self._entity_name = self._name + configuration_url: str | None = None + if entry := self.coordinator.config_entry: + configuration_url = f"http://{entry.data[CONF_HOST]}" - @property - def name(self) -> str | None: - """Return the name of the entity, if any.""" - return self._name - - @property - def device_info(self) -> DeviceInfo: - """Return the device information.""" - data = self.coordinator.data.devices[self._dev_id] - device_information = DeviceInfo( - identifiers={(DOMAIN, self._dev_id)}, - name=self._entity_name, - manufacturer="Plugwise", + data = coordinator.data.devices[device_id] + self._attr_device_info = DeviceInfo( + configuration_url=configuration_url, + identifiers={(DOMAIN, device_id)}, + manufacturer=data.get("vendor"), + model=data.get("model"), + name=f"Smile {coordinator.data.gateway['smile_name']}", + sw_version=data.get("fw"), ) - if entry := self.coordinator.config_entry: - device_information[ - ATTR_CONFIGURATION_URL - ] = f"http://{entry.data[CONF_HOST]}" - - if model := data.get("model"): - device_information[ATTR_MODEL] = model - - if self._dev_id != self.coordinator.data.gateway["gateway_id"]: - device_information[ATTR_VIA_DEVICE] = ( - DOMAIN, - str(self.coordinator.data.gateway["gateway_id"]), + if device_id != coordinator.data.gateway["gateway_id"]: + self._attr_device_info.update( + { + ATTR_NAME: data.get("name"), + ATTR_VIA_DEVICE: ( + DOMAIN, + str(self.coordinator.data.gateway["gateway_id"]), + ), + } ) - return device_information - async def async_added_to_hass(self) -> None: """Subscribe to updates.""" self._async_process_data() diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index d2fd47d4b7d..47b4f898c25 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -290,11 +290,11 @@ async def async_setup_entry( coordinator = hass.data[DOMAIN][config_entry.entry_id][COORDINATOR] entities: list[PlugwiseSensorEnity] = [] - for device_id, device_properties in coordinator.data.devices.items(): + for device_id, device in coordinator.data.devices.items(): for description in SENSORS: if ( - "sensors" not in device_properties - or device_properties["sensors"].get(description.key) is None + "sensors" not in device + or device["sensors"].get(description.key) is None ): continue @@ -302,7 +302,6 @@ async def async_setup_entry( PlugwiseSensorEnity( api, coordinator, - device_properties["name"], device_id, description, ) @@ -311,14 +310,13 @@ async def async_setup_entry( if coordinator.data.gateway["single_master_thermostat"] is False: # These sensors should actually be binary sensors. for description in INDICATE_ACTIVE_LOCAL_DEVICE_SENSORS: - if description.key not in device_properties: + if description.key not in device: continue entities.append( PlugwiseAuxSensorEntity( api, coordinator, - device_properties["name"], device_id, description, ) @@ -335,28 +333,23 @@ class PlugwiseSensorEnity(PlugwiseEntity, SensorEntity): self, api: Smile, coordinator: PlugwiseDataUpdateCoordinator, - name: str, device_id: str, description: SensorEntityDescription, ) -> None: """Initialise the sensor.""" - super().__init__(api, coordinator, name, device_id) + super().__init__(coordinator, device_id) self.entity_description = description + self._api = api self._attr_unique_id = f"{device_id}-{description.key}" - - if device_id == coordinator.data.gateway["heater_id"]: - self._entity_name = "Auxiliary" - - self._name = f"{self._entity_name} {description.name}" - - if device_id == coordinator.data.gateway["gateway_id"]: - self._entity_name = f"Smile {self._entity_name}" + self._attr_name = ( + f"{coordinator.data.devices[device_id].get('name', '')} {description.name}" + ).lstrip() @callback def _async_process_data(self) -> None: """Update the entity.""" if not (data := self.coordinator.data.devices.get(self._dev_id)): - LOGGER.error("Received no data for device %s", self._entity_name) + LOGGER.error("Received no data for device %s", self._dev_id) self.async_write_ha_state() return @@ -374,7 +367,7 @@ class PlugwiseAuxSensorEntity(PlugwiseSensorEnity): def _async_process_data(self) -> None: """Update the entity.""" if not (data := self.coordinator.data.devices.get(self._dev_id)): - LOGGER.error("Received no data for device %s", self._entity_name) + LOGGER.error("Received no data for device %s", self._dev_id) self.async_write_ha_state() return diff --git a/homeassistant/components/plugwise/switch.py b/homeassistant/components/plugwise/switch.py index 4e5a00e3e6a..6079862fe42 100644 --- a/homeassistant/components/plugwise/switch.py +++ b/homeassistant/components/plugwise/switch.py @@ -26,18 +26,14 @@ async def async_setup_entry( coordinator = hass.data[DOMAIN][config_entry.entry_id][COORDINATOR] entities: list[PlugwiseSwitchEntity] = [] - for device_id, device_properties in coordinator.data.devices.items(): - if ( - "switches" not in device_properties - or "relay" not in device_properties["switches"] - ): + for device_id, device in coordinator.data.devices.items(): + if "switches" not in device or "relay" not in device["switches"]: continue entities.append( PlugwiseSwitchEntity( api, coordinator, - device_properties["name"], device_id, ) ) @@ -54,14 +50,15 @@ class PlugwiseSwitchEntity(PlugwiseEntity, SwitchEntity): self, api: Smile, coordinator: PlugwiseDataUpdateCoordinator, - name: str, device_id: str, ) -> None: """Set up the Plugwise API.""" - super().__init__(api, coordinator, name, device_id) + super().__init__(coordinator, device_id) + self._api = api self._attr_unique_id = f"{device_id}-plug" self._members = coordinator.data.devices[device_id].get("members") self._attr_is_on = False + self._attr_name = coordinator.data.devices[device_id].get("name") async def async_turn_on(self, **kwargs: Any) -> None: """Turn the device on.""" @@ -93,7 +90,7 @@ class PlugwiseSwitchEntity(PlugwiseEntity, SwitchEntity): def _async_process_data(self) -> None: """Update the data from the Plugs.""" if not (data := self.coordinator.data.devices.get(self._dev_id)): - LOGGER.error("Received no data for device %s", self._name) + LOGGER.error("Received no data for device %s", self._dev_id) self.async_write_ha_state() return diff --git a/tests/components/plugwise/test_binary_sensor.py b/tests/components/plugwise/test_binary_sensor.py index 69080b364f0..b2356036eb9 100644 --- a/tests/components/plugwise/test_binary_sensor.py +++ b/tests/components/plugwise/test_binary_sensor.py @@ -11,11 +11,11 @@ async def test_anna_climate_binary_sensor_entities(hass, mock_smile_anna): entry = await async_init_integration(hass, mock_smile_anna) assert entry.state is ConfigEntryState.LOADED - state = hass.states.get("binary_sensor.auxiliary_secondary_boiler_state") - assert str(state.state) == STATE_OFF + state = hass.states.get("binary_sensor.opentherm_secondary_boiler_state") + assert state.state == STATE_OFF - state = hass.states.get("binary_sensor.auxiliary_dhw_state") - assert str(state.state) == STATE_OFF + state = hass.states.get("binary_sensor.opentherm_dhw_state") + assert state.state == STATE_OFF async def test_anna_climate_binary_sensor_change(hass, mock_smile_anna): @@ -23,18 +23,18 @@ async def test_anna_climate_binary_sensor_change(hass, mock_smile_anna): entry = await async_init_integration(hass, mock_smile_anna) assert entry.state is ConfigEntryState.LOADED - hass.states.async_set("binary_sensor.auxiliary_dhw_state", STATE_ON, {}) + hass.states.async_set("binary_sensor.opentherm_dhw_state", STATE_ON, {}) await hass.async_block_till_done() - state = hass.states.get("binary_sensor.auxiliary_dhw_state") - assert str(state.state) == STATE_ON + state = hass.states.get("binary_sensor.opentherm_dhw_state") + assert state.state == STATE_ON await hass.helpers.entity_component.async_update_entity( - "binary_sensor.auxiliary_dhw_state" + "binary_sensor.opentherm_dhw_state" ) - state = hass.states.get("binary_sensor.auxiliary_dhw_state") - assert str(state.state) == STATE_OFF + state = hass.states.get("binary_sensor.opentherm_dhw_state") + assert state.state == STATE_OFF async def test_adam_climate_binary_sensor_change(hass, mock_smile_adam): diff --git a/tests/components/plugwise/test_sensor.py b/tests/components/plugwise/test_sensor.py index 3498a7a8cf1..47cbea1a8bc 100644 --- a/tests/components/plugwise/test_sensor.py +++ b/tests/components/plugwise/test_sensor.py @@ -17,7 +17,7 @@ async def test_adam_climate_sensor_entities(hass, mock_smile_adam): state = hass.states.get("sensor.cv_pomp_electricity_consumed") assert float(state.state) == 35.6 - state = hass.states.get("sensor.auxiliary_water_temperature") + state = hass.states.get("sensor.onoff_water_temperature") assert float(state.state) == 70.0 state = hass.states.get("sensor.cv_pomp_electricity_consumed_interval") @@ -36,10 +36,10 @@ async def test_anna_as_smt_climate_sensor_entities(hass, mock_smile_anna): entry = await async_init_integration(hass, mock_smile_anna) assert entry.state is ConfigEntryState.LOADED - state = hass.states.get("sensor.auxiliary_outdoor_temperature") + state = hass.states.get("sensor.opentherm_outdoor_temperature") assert float(state.state) == 3.0 - state = hass.states.get("sensor.auxiliary_water_temperature") + state = hass.states.get("sensor.opentherm_water_temperature") assert float(state.state) == 29.1 state = hass.states.get("sensor.anna_illuminance") @@ -52,7 +52,7 @@ async def test_anna_climate_sensor_entities(hass, mock_smile_anna): entry = await async_init_integration(hass, mock_smile_anna) assert entry.state is ConfigEntryState.LOADED - state = hass.states.get("sensor.auxiliary_outdoor_temperature") + state = hass.states.get("sensor.opentherm_outdoor_temperature") assert float(state.state) == 3.0