Fix entity_id should be based on object_id the first time an entity is added (#148484)

This commit is contained in:
Jan Bouwhuis 2025-07-11 11:19:54 +02:00 committed by Franck Nijhof
parent 00e2a177a5
commit e951fc401c
No known key found for this signature in database
GPG Key ID: AB33ADACE7101952
2 changed files with 69 additions and 12 deletions

View File

@ -389,16 +389,6 @@ def async_setup_entity_entry_helper(
_async_setup_entities() _async_setup_entities()
def init_entity_id_from_config(
hass: HomeAssistant, entity: Entity, config: ConfigType, entity_id_format: str
) -> None:
"""Set entity_id from object_id if defined in config."""
if CONF_OBJECT_ID in config:
entity.entity_id = async_generate_entity_id(
entity_id_format, config[CONF_OBJECT_ID], None, hass
)
class MqttAttributesMixin(Entity): class MqttAttributesMixin(Entity):
"""Mixin used for platforms that support JSON attributes.""" """Mixin used for platforms that support JSON attributes."""
@ -1312,6 +1302,7 @@ class MqttEntity(
_attr_should_poll = False _attr_should_poll = False
_default_name: str | None _default_name: str | None
_entity_id_format: str _entity_id_format: str
_update_registry_entity_id: str | None = None
def __init__( def __init__(
self, self,
@ -1346,13 +1337,33 @@ class MqttEntity(
def _init_entity_id(self) -> None: def _init_entity_id(self) -> None:
"""Set entity_id from object_id if defined in config.""" """Set entity_id from object_id if defined in config."""
init_entity_id_from_config( if CONF_OBJECT_ID not in self._config:
self.hass, self, self._config, self._entity_id_format return
self.entity_id = async_generate_entity_id(
self._entity_id_format, self._config[CONF_OBJECT_ID], None, self.hass
) )
if self.unique_id is None:
return
# Check for previous deleted entities
entity_registry = er.async_get(self.hass)
entity_platform = self._entity_id_format.split(".")[0]
if (
deleted_entry := entity_registry.deleted_entities.get(
(entity_platform, DOMAIN, self.unique_id)
)
) and deleted_entry.entity_id != self.entity_id:
# Plan to update the entity_id basis on `object_id` if a deleted entity was found
self._update_registry_entity_id = self.entity_id
@final @final
async def async_added_to_hass(self) -> None: async def async_added_to_hass(self) -> None:
"""Subscribe to MQTT events.""" """Subscribe to MQTT events."""
if self._update_registry_entity_id is not None:
entity_registry = er.async_get(self.hass)
entity_registry.async_update_entity(
self.entity_id, new_entity_id=self._update_registry_entity_id
)
await super().async_added_to_hass() await super().async_added_to_hass()
self._subscriptions = {} self._subscriptions = {}
self._prepare_subscribe_topics() self._prepare_subscribe_topics()

View File

@ -1496,6 +1496,52 @@ async def test_discovery_with_object_id(
assert (domain, "object bla") in hass.data["mqtt"].discovery_already_discovered assert (domain, "object bla") in hass.data["mqtt"].discovery_already_discovered
async def test_discovery_with_object_id_for_previous_deleted_entity(
hass: HomeAssistant,
mqtt_mock_entry: MqttMockHAClientGenerator,
) -> None:
"""Test discovering an MQTT entity with object_id and unique_id."""
topic = "homeassistant/sensor/object/bla/config"
config = (
'{ "name": "Hello World 11", "unique_id": "very_unique", '
'"obj_id": "hello_id", "state_topic": "test-topic" }'
)
new_config = (
'{ "name": "Hello World 11", "unique_id": "very_unique", '
'"obj_id": "updated_hello_id", "state_topic": "test-topic" }'
)
initial_entity_id = "sensor.hello_id"
new_entity_id = "sensor.updated_hello_id"
name = "Hello World 11"
domain = "sensor"
await mqtt_mock_entry()
async_fire_mqtt_message(hass, topic, config)
await hass.async_block_till_done()
state = hass.states.get(initial_entity_id)
assert state is not None
assert state.name == name
assert (domain, "object bla") in hass.data["mqtt"].discovery_already_discovered
# Delete the entity
async_fire_mqtt_message(hass, topic, "")
await hass.async_block_till_done()
assert (domain, "object bla") not in hass.data["mqtt"].discovery_already_discovered
# Rediscover with new object_id
async_fire_mqtt_message(hass, topic, new_config)
await hass.async_block_till_done()
state = hass.states.get(new_entity_id)
assert state is not None
assert state.name == name
assert (domain, "object bla") in hass.data["mqtt"].discovery_already_discovered
async def test_discovery_incl_nodeid( async def test_discovery_incl_nodeid(
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
) -> None: ) -> None: