Use upstream device information for Plugwise (#66074)
This commit is contained in:
parent
199c8fef40
commit
4efebcb86c
7 changed files with 70 additions and 118 deletions
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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] = (
|
||||
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()
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue