Add entity descriptions to Plugwise switch platform (#66174)

This commit is contained in:
Franck Nijhof 2022-02-09 17:56:07 +01:00 committed by GitHub
parent 1f4ee3c265
commit aa95150360
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 94 additions and 17 deletions

View File

@ -62,6 +62,5 @@ FLAME_ICON = "mdi:fire"
FLOW_OFF_ICON = "mdi:water-pump-off" FLOW_OFF_ICON = "mdi:water-pump-off"
FLOW_ON_ICON = "mdi:water-pump" FLOW_ON_ICON = "mdi:water-pump"
IDLE_ICON = "mdi:circle-off-outline" IDLE_ICON = "mdi:circle-off-outline"
SWITCH_ICON = "mdi:electric-switch"
NO_NOTIFICATION_ICON = "mdi:mailbox-outline" NO_NOTIFICATION_ICON = "mdi:mailbox-outline"
NOTIFICATION_ICON = "mdi:mailbox-up-outline" NOTIFICATION_ICON = "mdi:mailbox-up-outline"

View File

@ -2,16 +2,19 @@
from __future__ import annotations from __future__ import annotations
import asyncio import asyncio
from typing import Any
from plugwise.exceptions import InvalidAuthentication, PlugwiseException from plugwise.exceptions import InvalidAuthentication, PlugwiseException
from plugwise.smile import Smile from plugwise.smile import Smile
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_USERNAME from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_USERNAME
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import device_registry as dr from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.entity_registry import RegistryEntry, async_migrate_entries
from .const import ( from .const import (
DEFAULT_PORT, DEFAULT_PORT,
@ -26,6 +29,8 @@ from .coordinator import PlugwiseDataUpdateCoordinator
async def async_setup_entry_gw(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_setup_entry_gw(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Plugwise Smiles from a config entry.""" """Set up Plugwise Smiles from a config entry."""
await async_migrate_entries(hass, entry.entry_id, async_migrate_entity_entry)
websession = async_get_clientsession(hass, verify_ssl=False) websession = async_get_clientsession(hass, verify_ssl=False)
api = Smile( api = Smile(
host=entry.data[CONF_HOST], host=entry.data[CONF_HOST],
@ -88,3 +93,16 @@ async def async_unload_entry_gw(hass: HomeAssistant, entry: ConfigEntry):
): ):
hass.data[DOMAIN].pop(entry.entry_id) hass.data[DOMAIN].pop(entry.entry_id)
return unload_ok return unload_ok
@callback
def async_migrate_entity_entry(entry: RegistryEntry) -> dict[str, Any] | None:
"""Migrate Plugwise entity entries.
- Migrates unique ID from old relay switches to the new unique ID
"""
if entry.domain == SWITCH_DOMAIN and entry.unique_id.endswith("-plug"):
return {"new_unique_id": entry.unique_id.replace("-plug", "-relay")}
# No migration needed
return None

View File

@ -5,15 +5,23 @@ from typing import Any
from plugwise.exceptions import PlugwiseException from plugwise.exceptions import PlugwiseException
from homeassistant.components.switch import SwitchEntity from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN, LOGGER, SWITCH_ICON from .const import DOMAIN, LOGGER
from .coordinator import PlugwiseDataUpdateCoordinator from .coordinator import PlugwiseDataUpdateCoordinator
from .entity import PlugwiseEntity from .entity import PlugwiseEntity
SWITCHES: tuple[SwitchEntityDescription, ...] = (
SwitchEntityDescription(
key="relay",
name="Relay",
icon="mdi:electric-switch",
),
)
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
@ -22,35 +30,38 @@ async def async_setup_entry(
) -> None: ) -> None:
"""Set up the Smile switches from a config entry.""" """Set up the Smile switches from a config entry."""
coordinator = hass.data[DOMAIN][config_entry.entry_id] coordinator = hass.data[DOMAIN][config_entry.entry_id]
async_add_entities( entities: list[PlugwiseSwitchEntity] = []
PlugwiseSwitchEntity(coordinator, device_id) for device_id, device in coordinator.data.devices.items():
for device_id, device in coordinator.data.devices.items() for description in SWITCHES:
if "switches" in device and "relay" in device["switches"] if "switches" not in device or description.key not in device["switches"]:
) continue
entities.append(PlugwiseSwitchEntity(coordinator, device_id, description))
async_add_entities(entities)
class PlugwiseSwitchEntity(PlugwiseEntity, SwitchEntity): class PlugwiseSwitchEntity(PlugwiseEntity, SwitchEntity):
"""Representation of a Plugwise plug.""" """Representation of a Plugwise plug."""
_attr_icon = SWITCH_ICON
def __init__( def __init__(
self, self,
coordinator: PlugwiseDataUpdateCoordinator, coordinator: PlugwiseDataUpdateCoordinator,
device_id: str, device_id: str,
description: SwitchEntityDescription,
) -> None: ) -> None:
"""Set up the Plugwise API.""" """Set up the Plugwise API."""
super().__init__(coordinator, device_id) super().__init__(coordinator, device_id)
self._attr_unique_id = f"{device_id}-plug" self.entity_description = description
self._members = coordinator.data.devices[device_id].get("members") self._attr_unique_id = f"{device_id}-{description.key}"
self._attr_is_on = False
self._attr_name = coordinator.data.devices[device_id].get("name") self._attr_name = coordinator.data.devices[device_id].get("name")
async def async_turn_on(self, **kwargs: Any) -> None: async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the device on.""" """Turn the device on."""
try: try:
state_on = await self.coordinator.api.set_switch_state( state_on = await self.coordinator.api.set_switch_state(
self._dev_id, self._members, "relay", "on" self._dev_id,
self.coordinator.data.devices[self._dev_id].get("members"),
self.entity_description.key,
"on",
) )
except PlugwiseException: except PlugwiseException:
LOGGER.error("Error while communicating to device") LOGGER.error("Error while communicating to device")
@ -63,7 +74,10 @@ class PlugwiseSwitchEntity(PlugwiseEntity, SwitchEntity):
"""Turn the device off.""" """Turn the device off."""
try: try:
state_off = await self.coordinator.api.set_switch_state( state_off = await self.coordinator.api.set_switch_state(
self._dev_id, self._members, "relay", "off" self._dev_id,
self.coordinator.data.devices[self._dev_id].get("members"),
self.entity_description.key,
"off",
) )
except PlugwiseException: except PlugwiseException:
LOGGER.error("Error while communicating to device") LOGGER.error("Error while communicating to device")
@ -80,5 +94,5 @@ class PlugwiseSwitchEntity(PlugwiseEntity, SwitchEntity):
super()._handle_coordinator_update() super()._handle_coordinator_update()
return return
self._attr_is_on = data["switches"].get("relay") self._attr_is_on = data["switches"].get(self.entity_description.key)
super()._handle_coordinator_update() super()._handle_coordinator_update()

View File

@ -2,8 +2,12 @@
from plugwise.exceptions import PlugwiseException from plugwise.exceptions import PlugwiseException
from homeassistant.components.plugwise.const import DOMAIN
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
from homeassistant.config_entries import ConfigEntryState from homeassistant.config_entries import ConfigEntryState
from homeassistant.helpers import entity_registry as er
from tests.common import MockConfigEntry
from tests.components.plugwise.common import async_init_integration from tests.components.plugwise.common import async_init_integration
@ -121,3 +125,45 @@ async def test_stretch_switch_changes(hass, mock_stretch):
) )
state = hass.states.get("switch.droger_52559") state = hass.states.get("switch.droger_52559")
assert str(state.state) == "on" assert str(state.state) == "on"
async def test_unique_id_migration_plug_relay(hass, mock_smile_adam):
"""Test unique ID migration of -plugs to -relay."""
entry = MockConfigEntry(
domain=DOMAIN, data={"host": "1.1.1.1", "password": "test-password"}
)
entry.add_to_hass(hass)
registry = er.async_get(hass)
# Entry to migrate
registry.async_get_or_create(
SWITCH_DOMAIN,
DOMAIN,
"21f2b542c49845e6bb416884c55778d6-plug",
config_entry=entry,
suggested_object_id="playstation_smart_plug",
disabled_by=None,
)
# Entry not needing migration
registry.async_get_or_create(
SWITCH_DOMAIN,
DOMAIN,
"675416a629f343c495449970e2ca37b5-relay",
config_entry=entry,
suggested_object_id="router",
disabled_by=None,
)
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
assert hass.states.get("switch.playstation_smart_plug") is not None
assert hass.states.get("switch.router") is not None
entity_entry = registry.async_get("switch.playstation_smart_plug")
assert entity_entry
assert entity_entry.unique_id == "21f2b542c49845e6bb416884c55778d6-relay"
entity_entry = registry.async_get("switch.router")
assert entity_entry
assert entity_entry.unique_id == "675416a629f343c495449970e2ca37b5-relay"