mirror of
https://github.com/home-assistant/core.git
synced 2025-08-03 02:28:21 +00:00
Add WS command to help reset custom entity_id
This commit is contained in:
parent
77e9142722
commit
9f039002ff
@ -22,6 +22,7 @@ from homeassistant.helpers.json import json_dumps
|
|||||||
def async_setup(hass: HomeAssistant) -> bool:
|
def async_setup(hass: HomeAssistant) -> bool:
|
||||||
"""Enable the Entity Registry views."""
|
"""Enable the Entity Registry views."""
|
||||||
|
|
||||||
|
websocket_api.async_register_command(hass, websocket_get_automatic_entity_ids)
|
||||||
websocket_api.async_register_command(hass, websocket_get_entities)
|
websocket_api.async_register_command(hass, websocket_get_entities)
|
||||||
websocket_api.async_register_command(hass, websocket_get_entity)
|
websocket_api.async_register_command(hass, websocket_get_entity)
|
||||||
websocket_api.async_register_command(hass, websocket_list_entities_for_display)
|
websocket_api.async_register_command(hass, websocket_list_entities_for_display)
|
||||||
@ -316,3 +317,37 @@ def websocket_remove_entity(
|
|||||||
|
|
||||||
registry.async_remove(msg["entity_id"])
|
registry.async_remove(msg["entity_id"])
|
||||||
connection.send_message(websocket_api.result_message(msg["id"]))
|
connection.send_message(websocket_api.result_message(msg["id"]))
|
||||||
|
|
||||||
|
|
||||||
|
@websocket_api.websocket_command(
|
||||||
|
{
|
||||||
|
vol.Required("type"): "config/entity_registry/get_automatic_entity_ids",
|
||||||
|
vol.Required("entity_ids"): cv.entity_ids,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@callback
|
||||||
|
def websocket_get_automatic_entity_ids(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
connection: websocket_api.ActiveConnection,
|
||||||
|
msg: dict[str, Any],
|
||||||
|
) -> None:
|
||||||
|
"""Return the automatic entity IDs for the given entity IDs.
|
||||||
|
|
||||||
|
This is used to help user reset entity IDs which have been customized by the user.
|
||||||
|
"""
|
||||||
|
registry = er.async_get(hass)
|
||||||
|
|
||||||
|
entity_ids = msg["entity_ids"]
|
||||||
|
automatic_entity_ids: dict[str, str | None] = {}
|
||||||
|
for entity_id in entity_ids:
|
||||||
|
if not (entry := registry.entities.get(entity_id)):
|
||||||
|
automatic_entity_ids[entity_id] = None
|
||||||
|
continue
|
||||||
|
automatic_entity_ids[entity_id] = registry.async_generate_entity_id(
|
||||||
|
entry.domain,
|
||||||
|
entry.suggested_object_id or f"{entry.platform}_{entry.unique_id}",
|
||||||
|
)
|
||||||
|
|
||||||
|
connection.send_message(
|
||||||
|
websocket_api.result_message(msg["id"], automatic_entity_ids)
|
||||||
|
)
|
||||||
|
@ -79,7 +79,7 @@ EVENT_ENTITY_REGISTRY_UPDATED: EventType[EventEntityRegistryUpdatedData] = Event
|
|||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
STORAGE_VERSION_MAJOR = 1
|
STORAGE_VERSION_MAJOR = 1
|
||||||
STORAGE_VERSION_MINOR = 16
|
STORAGE_VERSION_MINOR = 17
|
||||||
STORAGE_KEY = "core.entity_registry"
|
STORAGE_KEY = "core.entity_registry"
|
||||||
|
|
||||||
CLEANUP_INTERVAL = 3600 * 24
|
CLEANUP_INTERVAL = 3600 * 24
|
||||||
@ -198,6 +198,7 @@ class RegistryEntry:
|
|||||||
original_device_class: str | None = attr.ib()
|
original_device_class: str | None = attr.ib()
|
||||||
original_icon: str | None = attr.ib()
|
original_icon: str | None = attr.ib()
|
||||||
original_name: str | None = attr.ib()
|
original_name: str | None = attr.ib()
|
||||||
|
suggested_object_id: str | None = attr.ib()
|
||||||
supported_features: int = attr.ib()
|
supported_features: int = attr.ib()
|
||||||
translation_key: str | None = attr.ib()
|
translation_key: str | None = attr.ib()
|
||||||
unit_of_measurement: str | None = attr.ib()
|
unit_of_measurement: str | None = attr.ib()
|
||||||
@ -359,6 +360,7 @@ class RegistryEntry:
|
|||||||
"original_icon": self.original_icon,
|
"original_icon": self.original_icon,
|
||||||
"original_name": self.original_name,
|
"original_name": self.original_name,
|
||||||
"platform": self.platform,
|
"platform": self.platform,
|
||||||
|
"suggested_object_id": self.suggested_object_id,
|
||||||
"supported_features": self.supported_features,
|
"supported_features": self.supported_features,
|
||||||
"translation_key": self.translation_key,
|
"translation_key": self.translation_key,
|
||||||
"unique_id": self.unique_id,
|
"unique_id": self.unique_id,
|
||||||
@ -548,6 +550,11 @@ class EntityRegistryStore(storage.Store[dict[str, list[dict[str, Any]]]]):
|
|||||||
for entity in data["deleted_entities"]:
|
for entity in data["deleted_entities"]:
|
||||||
entity["config_subentry_id"] = None
|
entity["config_subentry_id"] = None
|
||||||
|
|
||||||
|
if old_minor_version < 17:
|
||||||
|
# Version 1.17 adds suggested_object_id
|
||||||
|
for entity in data["entities"]:
|
||||||
|
entity["suggested_object_id"] = None
|
||||||
|
|
||||||
if old_major_version > 1:
|
if old_major_version > 1:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
return data
|
return data
|
||||||
@ -942,6 +949,7 @@ class EntityRegistry(BaseRegistry):
|
|||||||
original_icon=none_if_undefined(original_icon),
|
original_icon=none_if_undefined(original_icon),
|
||||||
original_name=none_if_undefined(original_name),
|
original_name=none_if_undefined(original_name),
|
||||||
platform=platform,
|
platform=platform,
|
||||||
|
suggested_object_id=suggested_object_id,
|
||||||
supported_features=none_if_undefined(supported_features) or 0,
|
supported_features=none_if_undefined(supported_features) or 0,
|
||||||
translation_key=none_if_undefined(translation_key),
|
translation_key=none_if_undefined(translation_key),
|
||||||
unique_id=unique_id,
|
unique_id=unique_id,
|
||||||
@ -1378,6 +1386,7 @@ class EntityRegistry(BaseRegistry):
|
|||||||
original_icon=entity["original_icon"],
|
original_icon=entity["original_icon"],
|
||||||
original_name=entity["original_name"],
|
original_name=entity["original_name"],
|
||||||
platform=entity["platform"],
|
platform=entity["platform"],
|
||||||
|
suggested_object_id=entity["suggested_object_id"],
|
||||||
supported_features=entity["supported_features"],
|
supported_features=entity["supported_features"],
|
||||||
translation_key=entity["translation_key"],
|
translation_key=entity["translation_key"],
|
||||||
unique_id=entity["unique_id"],
|
unique_id=entity["unique_id"],
|
||||||
|
@ -669,6 +669,7 @@ class RegistryEntryWithDefaults(er.RegistryEntry):
|
|||||||
original_device_class: str | None = attr.ib(default=None)
|
original_device_class: str | None = attr.ib(default=None)
|
||||||
original_icon: str | None = attr.ib(default=None)
|
original_icon: str | None = attr.ib(default=None)
|
||||||
original_name: str | None = attr.ib(default=None)
|
original_name: str | None = attr.ib(default=None)
|
||||||
|
suggested_object_id: str | None = attr.ib(default=None)
|
||||||
supported_features: int = attr.ib(default=0)
|
supported_features: int = attr.ib(default=0)
|
||||||
translation_key: str | None = attr.ib(default=None)
|
translation_key: str | None = attr.ib(default=None)
|
||||||
unit_of_measurement: str | None = attr.ib(default=None)
|
unit_of_measurement: str | None = attr.ib(default=None)
|
||||||
|
@ -1288,3 +1288,58 @@ async def test_remove_non_existing_entity(
|
|||||||
msg = await client.receive_json()
|
msg = await client.receive_json()
|
||||||
|
|
||||||
assert not msg["success"]
|
assert not msg["success"]
|
||||||
|
|
||||||
|
|
||||||
|
async def test_get_automatic_entity_ids(
|
||||||
|
hass: HomeAssistant, client: MockHAClientWebSocket
|
||||||
|
) -> None:
|
||||||
|
"""Test get_automatic_entity_ids."""
|
||||||
|
mock_registry(
|
||||||
|
hass,
|
||||||
|
{
|
||||||
|
"test_domain.test_1": RegistryEntryWithDefaults(
|
||||||
|
entity_id="test_domain.test_1",
|
||||||
|
unique_id="uniq1",
|
||||||
|
platform="test_platform",
|
||||||
|
),
|
||||||
|
"test_domain.test_2": RegistryEntryWithDefaults(
|
||||||
|
entity_id="test_domain.test_2",
|
||||||
|
unique_id="uniq2",
|
||||||
|
platform="test_platform",
|
||||||
|
suggested_object_id="blabla",
|
||||||
|
),
|
||||||
|
"test_domain.test_3": RegistryEntryWithDefaults(
|
||||||
|
entity_id="test_domain.test_3",
|
||||||
|
unique_id="uniq3",
|
||||||
|
platform="test_platform",
|
||||||
|
suggested_object_id="collision",
|
||||||
|
),
|
||||||
|
"test_domain.collision": RegistryEntryWithDefaults(
|
||||||
|
entity_id="test_domain.collision",
|
||||||
|
unique_id="uniq_collision",
|
||||||
|
platform="test_platform",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
await client.send_json_auto_id(
|
||||||
|
{
|
||||||
|
"type": "config/entity_registry/get_automatic_entity_ids",
|
||||||
|
"entity_ids": [
|
||||||
|
"test_domain.test_1",
|
||||||
|
"test_domain.test_2",
|
||||||
|
"test_domain.test_3",
|
||||||
|
"test_domain.unknown",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
msg = await client.receive_json()
|
||||||
|
|
||||||
|
assert msg["success"]
|
||||||
|
assert msg["result"] == {
|
||||||
|
"test_domain.test_1": "test_domain.test_platform_uniq1", # platform + unique_id
|
||||||
|
"test_domain.test_2": "test_domain.blabla", # suggested_object_id
|
||||||
|
"test_domain.test_3": "test_domain.collision_2", # suggested_object_id + _2
|
||||||
|
"test_domain.unknown": None, # no test_domain.unknown in registry
|
||||||
|
}
|
||||||
|
@ -1550,6 +1550,7 @@ async def test_entity_info_added_to_entity_registry(
|
|||||||
original_icon="nice:icon",
|
original_icon="nice:icon",
|
||||||
original_name="best name",
|
original_name="best name",
|
||||||
options=None,
|
options=None,
|
||||||
|
suggested_object_id="best name",
|
||||||
supported_features=5,
|
supported_features=5,
|
||||||
translation_key="my_translation_key",
|
translation_key="my_translation_key",
|
||||||
unit_of_measurement=PERCENTAGE,
|
unit_of_measurement=PERCENTAGE,
|
||||||
|
@ -144,6 +144,7 @@ def test_get_or_create_updates_data(
|
|||||||
original_device_class="mock-device-class",
|
original_device_class="mock-device-class",
|
||||||
original_icon="initial-original_icon",
|
original_icon="initial-original_icon",
|
||||||
original_name="initial-original_name",
|
original_name="initial-original_name",
|
||||||
|
suggested_object_id=None,
|
||||||
supported_features=5,
|
supported_features=5,
|
||||||
translation_key="initial-translation_key",
|
translation_key="initial-translation_key",
|
||||||
unit_of_measurement="initial-unit_of_measurement",
|
unit_of_measurement="initial-unit_of_measurement",
|
||||||
@ -202,6 +203,7 @@ def test_get_or_create_updates_data(
|
|||||||
original_device_class="new-mock-device-class",
|
original_device_class="new-mock-device-class",
|
||||||
original_icon="updated-original_icon",
|
original_icon="updated-original_icon",
|
||||||
original_name="updated-original_name",
|
original_name="updated-original_name",
|
||||||
|
suggested_object_id=None,
|
||||||
supported_features=10,
|
supported_features=10,
|
||||||
translation_key="updated-translation_key",
|
translation_key="updated-translation_key",
|
||||||
unit_of_measurement="updated-unit_of_measurement",
|
unit_of_measurement="updated-unit_of_measurement",
|
||||||
@ -254,6 +256,7 @@ def test_get_or_create_updates_data(
|
|||||||
original_device_class=None,
|
original_device_class=None,
|
||||||
original_icon=None,
|
original_icon=None,
|
||||||
original_name=None,
|
original_name=None,
|
||||||
|
suggested_object_id=None,
|
||||||
supported_features=0, # supported_features is stored as an int
|
supported_features=0, # supported_features is stored as an int
|
||||||
translation_key=None,
|
translation_key=None,
|
||||||
unit_of_measurement=None,
|
unit_of_measurement=None,
|
||||||
@ -537,6 +540,7 @@ async def test_load_bad_data(
|
|||||||
"original_name": None,
|
"original_name": None,
|
||||||
"platform": "super_platform",
|
"platform": "super_platform",
|
||||||
"previous_unique_id": None,
|
"previous_unique_id": None,
|
||||||
|
"suggested_object_id": None,
|
||||||
"supported_features": 0,
|
"supported_features": 0,
|
||||||
"translation_key": None,
|
"translation_key": None,
|
||||||
"unique_id": 123, # Should trigger warning
|
"unique_id": 123, # Should trigger warning
|
||||||
@ -568,6 +572,7 @@ async def test_load_bad_data(
|
|||||||
"original_name": None,
|
"original_name": None,
|
||||||
"platform": "super_platform",
|
"platform": "super_platform",
|
||||||
"previous_unique_id": None,
|
"previous_unique_id": None,
|
||||||
|
"suggested_object_id": None,
|
||||||
"supported_features": 0,
|
"supported_features": 0,
|
||||||
"translation_key": None,
|
"translation_key": None,
|
||||||
"unique_id": ["not", "valid"], # Should not load
|
"unique_id": ["not", "valid"], # Should not load
|
||||||
@ -922,6 +927,7 @@ async def test_migration_1_1(hass: HomeAssistant, hass_storage: dict[str, Any])
|
|||||||
"original_name": None,
|
"original_name": None,
|
||||||
"platform": "super_platform",
|
"platform": "super_platform",
|
||||||
"previous_unique_id": None,
|
"previous_unique_id": None,
|
||||||
|
"suggested_object_id": None,
|
||||||
"supported_features": 0,
|
"supported_features": 0,
|
||||||
"translation_key": None,
|
"translation_key": None,
|
||||||
"unique_id": "very_unique",
|
"unique_id": "very_unique",
|
||||||
@ -1101,6 +1107,7 @@ async def test_migration_1_11(
|
|||||||
"original_name": None,
|
"original_name": None,
|
||||||
"platform": "super_platform",
|
"platform": "super_platform",
|
||||||
"previous_unique_id": None,
|
"previous_unique_id": None,
|
||||||
|
"suggested_object_id": None,
|
||||||
"supported_features": 0,
|
"supported_features": 0,
|
||||||
"translation_key": None,
|
"translation_key": None,
|
||||||
"unique_id": "very_unique",
|
"unique_id": "very_unique",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user