Fix KNX unique_id (#49677)

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
Matthias Alphart 2021-04-28 15:50:01 +02:00 committed by GitHub
parent e96cbccc92
commit 78befcd3fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 96 additions and 6 deletions

View File

@ -37,6 +37,7 @@ class KNXBinarySensor(KnxEntity, BinarySensorEntity):
"""Initialize of KNX binary sensor."""
self._device: XknxBinarySensor
super().__init__(device)
self._unique_id = f"{self._device.remote_value.group_address_state}"
@property
def device_class(self) -> str | None:

View File

@ -6,6 +6,7 @@ from typing import Any, Callable
from xknx.devices import Climate as XknxClimate
from xknx.dpt.dpt_hvac_mode import HVACControllerMode, HVACOperationMode
from xknx.telegram.address import parse_device_group_address
from homeassistant.components.climate import ClimateEntity
from homeassistant.components.climate.const import (
@ -16,12 +17,14 @@ from homeassistant.components.climate.const import (
SUPPORT_TARGET_TEMPERATURE,
)
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS
from homeassistant.core import HomeAssistant
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from .const import CONTROLLER_MODES, DOMAIN, PRESET_MODES
from .knx_entity import KnxEntity
from .schema import ClimateSchema
CONTROLLER_MODES_INV = {value: key for key, value in CONTROLLER_MODES.items()}
PRESET_MODES_INV = {value: key for key, value in PRESET_MODES.items()}
@ -34,6 +37,7 @@ async def async_setup_platform(
discovery_info: DiscoveryInfoType | None = None,
) -> None:
"""Set up climate(s) for KNX platform."""
_async_migrate_unique_id(hass, discovery_info)
entities = []
for device in hass.data[DOMAIN].xknx.devices:
if isinstance(device, XknxClimate):
@ -41,6 +45,33 @@ async def async_setup_platform(
async_add_entities(entities)
@callback
def _async_migrate_unique_id(
hass: HomeAssistant, discovery_info: DiscoveryInfoType | None
) -> None:
"""Change unique_ids used in 2021.4 to include target_temperature GA."""
entity_registry = er.async_get(hass)
if not discovery_info or not discovery_info["platform_config"]:
return
platform_config = discovery_info["platform_config"]
for entity_config in platform_config:
# normalize group address strings - ga_temperature_state was the old uid
ga_temperature_state = parse_device_group_address(
entity_config[ClimateSchema.CONF_TEMPERATURE_ADDRESS][0]
)
old_uid = str(ga_temperature_state)
entity_id = entity_registry.async_get_entity_id("climate", DOMAIN, old_uid)
if entity_id is None:
continue
ga_target_temperature_state = parse_device_group_address(
entity_config[ClimateSchema.CONF_TARGET_TEMPERATURE_STATE_ADDRESS][0]
)
new_uid = f"{ga_temperature_state}_{ga_target_temperature_state}"
entity_registry.async_update_entity(entity_id, new_unique_id=new_uid)
class KNXClimate(KnxEntity, ClimateEntity):
"""Representation of a KNX climate device."""
@ -48,7 +79,10 @@ class KNXClimate(KnxEntity, ClimateEntity):
"""Initialize of a KNX climate device."""
self._device: XknxClimate
super().__init__(device)
self._unique_id = (
f"{device.temperature.group_address_state}_"
f"{device.target_temperature.group_address_state}"
)
self._unit_of_measurement = TEMP_CELSIUS
@property

View File

@ -6,6 +6,7 @@ from datetime import datetime
from typing import Any, Callable
from xknx.devices import Cover as XknxCover, Device as XknxDevice
from xknx.telegram.address import parse_device_group_address
from homeassistant.components.cover import (
ATTR_POSITION,
@ -23,12 +24,14 @@ from homeassistant.components.cover import (
CoverEntity,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.event import async_track_utc_time_change
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from .const import DOMAIN
from .knx_entity import KnxEntity
from .schema import CoverSchema
async def async_setup_platform(
@ -38,6 +41,7 @@ async def async_setup_platform(
discovery_info: DiscoveryInfoType | None = None,
) -> None:
"""Set up cover(s) for KNX platform."""
_async_migrate_unique_id(hass, discovery_info)
entities = []
for device in hass.data[DOMAIN].xknx.devices:
if isinstance(device, XknxCover):
@ -45,6 +49,37 @@ async def async_setup_platform(
async_add_entities(entities)
@callback
def _async_migrate_unique_id(
hass: HomeAssistant, discovery_info: DiscoveryInfoType | None
) -> None:
"""Change unique_ids used in 2021.4 to include position_target GA."""
entity_registry = er.async_get(hass)
if not discovery_info or not discovery_info["platform_config"]:
return
platform_config = discovery_info["platform_config"]
for entity_config in platform_config:
# normalize group address strings - ga_updown was the old uid but is optional
updown_addresses = entity_config.get(CoverSchema.CONF_MOVE_LONG_ADDRESS)
if updown_addresses is None:
continue
ga_updown = parse_device_group_address(updown_addresses[0])
old_uid = str(ga_updown)
entity_id = entity_registry.async_get_entity_id("cover", DOMAIN, old_uid)
if entity_id is None:
continue
position_target_addresses = entity_config.get(CoverSchema.CONF_POSITION_ADDRESS)
ga_position_target = (
parse_device_group_address(position_target_addresses[0])
if position_target_addresses is not None
else None
)
new_uid = f"{ga_updown}_{ga_position_target}"
entity_registry.async_update_entity(entity_id, new_unique_id=new_uid)
class KNXCover(KnxEntity, CoverEntity):
"""Representation of a KNX cover."""
@ -52,7 +87,9 @@ class KNXCover(KnxEntity, CoverEntity):
"""Initialize the cover."""
self._device: XknxCover
super().__init__(device)
self._unique_id = (
f"{device.updown.group_address}_{device.position_target.group_address}"
)
self._unsubscribe_auto_updater: Callable[[], None] | None = None
@callback

View File

@ -44,7 +44,7 @@ class KNXFan(KnxEntity, FanEntity):
"""Initialize of KNX fan."""
self._device: XknxFan
super().__init__(device)
self._unique_id = f"{self._device.speed.group_address}"
self._step_range: tuple[int, int] | None = None
if device.max_step:
# FanSpeedMode.STEP:

View File

@ -17,6 +17,7 @@ class KnxEntity(Entity):
def __init__(self, device: XknxDevice) -> None:
"""Set up device."""
self._device = device
self._unique_id: str | None = None
@property
def name(self) -> str:
@ -37,7 +38,7 @@ class KnxEntity(Entity):
@property
def unique_id(self) -> str | None:
"""Return the unique id of the device."""
return self._device.unique_id
return self._unique_id
async def async_update(self) -> None:
"""Request a state update from KNX bus."""

View File

@ -52,7 +52,7 @@ class KNXLight(KnxEntity, LightEntity):
"""Initialize of KNX light."""
self._device: XknxLight
super().__init__(device)
self._unique_id = self._device_unique_id()
self._min_kelvin = device.min_kelvin or LightSchema.DEFAULT_MIN_KELVIN
self._max_kelvin = device.max_kelvin or LightSchema.DEFAULT_MAX_KELVIN
self._min_mireds = color_util.color_temperature_kelvin_to_mired(
@ -62,6 +62,17 @@ class KNXLight(KnxEntity, LightEntity):
self._min_kelvin
)
def _device_unique_id(self) -> str:
"""Return unique id for this device."""
if self._device.switch.group_address is not None:
return f"{self._device.switch.group_address}"
return (
f"{self._device.red.switch.group_address}_"
f"{self._device.green.switch.group_address}_"
f"{self._device.blue.switch.group_address}_"
f"{self._device.white.switch.group_address}"
)
@property
def brightness(self) -> int | None:
"""Return the brightness of this light between 0..255."""

View File

@ -36,6 +36,9 @@ class KNXScene(KnxEntity, Scene):
"""Init KNX scene."""
self._device: XknxScene
super().__init__(device)
self._unique_id = (
f"{self._device.scene_value.group_address}_{self._device.scene_number}"
)
async def async_activate(self, **kwargs: Any) -> None:
"""Activate the scene."""

View File

@ -37,6 +37,7 @@ class KNXSensor(KnxEntity, SensorEntity):
"""Initialize of a KNX sensor."""
self._device: XknxSensor
super().__init__(device)
self._unique_id = f"{self._device.sensor_value.group_address_state}"
@property
def state(self) -> StateType:

View File

@ -53,6 +53,7 @@ class KNXSwitch(KnxEntity, SwitchEntity):
invert=config[SwitchSchema.CONF_INVERT],
)
)
self._unique_id = f"{self._device.switch.group_address}"
@property
def is_on(self) -> bool:

View File

@ -37,6 +37,7 @@ class KNXWeather(KnxEntity, WeatherEntity):
"""Initialize of a KNX sensor."""
self._device: XknxWeather
super().__init__(device)
self._unique_id = f"{self._device._temperature.group_address_state}"
@property
def temperature(self) -> float | None: