-
Notifications
You must be signed in to change notification settings - Fork 34
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow device cluster entities overwrite from v2 quirks #328
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,7 @@ | |
from zigpy.types.named import EUI64 | ||
|
||
from zha.application import Platform | ||
from zha.application.const import ENTITY_PREVIOUS_UNIQUE_ID | ||
from zha.const import STATE_CHANGED | ||
from zha.debounce import Debouncer | ||
from zha.event import EventBase | ||
|
@@ -50,6 +51,7 @@ class BaseEntityInfo: | |
|
||
fallback_name: str | ||
unique_id: str | ||
previous_unique_id: str | None | ||
platform: str | ||
class_name: str | ||
translation_key: str | None | ||
|
@@ -118,11 +120,12 @@ class BaseEntity(LogMixin, EventBase): | |
_attr_state_class: str | None | ||
_attr_enabled: bool = True | ||
|
||
def __init__(self, unique_id: str) -> None: | ||
def __init__(self, unique_id: str, previous_unique_id: str | None = None) -> None: | ||
"""Initialize the platform entity.""" | ||
super().__init__() | ||
|
||
self._unique_id: str = unique_id | ||
self._previous_unique_id: str | None = previous_unique_id | ||
|
||
self.__previous_state: Any = None | ||
self._tracked_tasks: list[asyncio.Task] = [] | ||
|
@@ -189,6 +192,12 @@ def unique_id(self) -> str: | |
"""Return the unique id.""" | ||
return self._unique_id | ||
|
||
@final | ||
@property | ||
def previous_unique_id(self) -> str | None: | ||
"""Return the previous unique id, if any.""" | ||
return self._previous_unique_id | ||
|
||
@cached_property | ||
def identifiers(self) -> BaseIdentifiers: | ||
"""Return a dict with the information necessary to identify this entity.""" | ||
|
@@ -203,6 +212,7 @@ def info_object(self) -> BaseEntityInfo: | |
|
||
return BaseEntityInfo( | ||
unique_id=self.unique_id, | ||
previous_unique_id=self.previous_unique_id, | ||
platform=self.PLATFORM, | ||
class_name=self.__class__.__name__, | ||
fallback_name=self.fallback_name, | ||
|
@@ -299,6 +309,12 @@ def __init__( | |
if self._unique_id_suffix: | ||
unique_id += f"-{self._unique_id_suffix}" | ||
|
||
if ENTITY_PREVIOUS_UNIQUE_ID in kwargs: | ||
previous_unique_id = kwargs[ENTITY_PREVIOUS_UNIQUE_ID] | ||
if previous_unique_id is not None: | ||
previous_unique_id += f"-{self._unique_id_suffix}" | ||
kwargs[ENTITY_PREVIOUS_UNIQUE_ID] = previous_unique_id | ||
|
||
# XXX: The ordering here matters: `_init_from_quirks_metadata` affects how | ||
# the `unique_id` is computed! | ||
super().__init__(unique_id=unique_id, **kwargs) | ||
|
@@ -309,16 +325,15 @@ def __init__( | |
self.cluster_handlers[cluster_handler.name] = cluster_handler | ||
self._device: Device = device | ||
self._endpoint = endpoint | ||
# we double create these in discovery tests because we reissue the create calls to count and prove them out | ||
if (self.PLATFORM, self.unique_id) not in self._device.platform_entities: | ||
self._device.platform_entities[(self.PLATFORM, self.unique_id)] = self | ||
else: | ||
_LOGGER.debug( | ||
"Not registering entity %r, unique id %r already exists: %r", | ||
self, | ||
|
||
if (self.PLATFORM, self.unique_id) in self._device.platform_entities: | ||
_LOGGER.warning( | ||
"Duplicate entity detected - unique id %r already exists: %r. Replacing with %r", | ||
(self.PLATFORM, self.unique_id), | ||
self._device.platform_entities[(self.PLATFORM, self.unique_id)], | ||
self, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is this doing? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Intention was to offer a debugging message for those cases where it is not intended or expected to encounter duplicated entities. Can be removed or demoted to debug. |
||
) | ||
self._device.platform_entities[(self.PLATFORM, self.unique_id)] = self | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same question as above There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is allowing a newer entity instance to overwrite an existing one. In my specific case, an automatic zha created local temp calibration entity would be replaced by one provided by a quirk v2. At least, in my setup, the quirk v2 entity gets created last. |
||
|
||
@classmethod | ||
def create_platform_entity( | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this will break all existing v2 entities and it will require a migration of the HA entity registry.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that migration a post-install operation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In ZHA
async_setup_entry
I can get access to all HA ZHA entities. But it doesn't look like the HA associated entity data contains the info I need to migrate the ids - I would not know the cluster id of each entity in order to migrate to<unique id>-<cluster id>
.Here is how the registry entry looks like for a local temperature calibration entity:
Is there any other place where the migration could be done?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Found a way: inside BaseEntityInfo, the previous unique id can be stored and used by ZHA to migrate existing HA entities.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is the migration code: home-assistant/core#136788.