Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions homeassistant/components/mqtt/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -572,9 +572,7 @@ async def discovery_callback(payload):
else:
# Non-empty, unchanged payload: Ignore to avoid changing states
_LOGGER.info("Ignoring unchanged update for: %s", self.entity_id)
async_dispatcher_send(
self.hass, MQTT_DISCOVERY_DONE.format(discovery_hash), None
)
self.async_send_discovery_done()

if discovery_hash:
debug_info.add_entity_discovery_data(
Expand All @@ -587,9 +585,18 @@ async def discovery_callback(payload):
MQTT_DISCOVERY_UPDATED.format(discovery_hash),
discovery_callback,
)
async_dispatcher_send(
self.hass, MQTT_DISCOVERY_DONE.format(discovery_hash), None
)

@callback
def async_send_discovery_done(self) -> None:
"""Acknowledge a discovery message has been handled."""
discovery_hash = (
self._discovery_data[ATTR_DISCOVERY_HASH] if self._discovery_data else None
)
if not discovery_hash:
return
async_dispatcher_send(
self.hass, MQTT_DISCOVERY_DONE.format(discovery_hash), None
)

async def async_removed_from_registry(self) -> None:
"""Clear retained discovery topic in broker."""
Expand Down Expand Up @@ -728,6 +735,7 @@ async def async_added_to_hass(self):
await super().async_added_to_hass()
self._prepare_subscribe_topics()
await self._subscribe_topics()
self.async_send_discovery_done()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

async_added_to_hass is overrided called from sensor and binary_sensor. These overrides should process the restore before calling super().async_added_to_hass

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be async_added_to_hass is also called when a config_entry is added.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems no issue since self.async_send_discovery_done() is not doing anything when the entity is restored, only when it is discovered.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The MQTT entities are only added when they are discovered.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correct


async def discovery_update(self, discovery_payload):
"""Handle updated discovery message."""
Expand Down
52 changes: 52 additions & 0 deletions tests/components/mqtt/test_discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,58 @@ def callback(event):
assert events[3].data["old_state"] is None


async def test_rapid_reconfigure(hass, mqtt_mock, caplog):
"""Test immediate reconfigure of added component."""

events = []

@ha.callback
def callback(event):
"""Verify event got called."""
events.append(event)

hass.bus.async_listen(EVENT_STATE_CHANGED, callback)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have this helper:

def async_capture_events(hass, event_name):


# Discovery immediately followed by reconfig
async_fire_mqtt_message(hass, "homeassistant/binary_sensor/bla/config", "")
async_fire_mqtt_message(
hass,
"homeassistant/binary_sensor/bla/config",
'{ "name": "Beer", "state_topic": "test-topic1" }',
)
async_fire_mqtt_message(
hass,
"homeassistant/binary_sensor/bla/config",
'{ "name": "Milk", "state_topic": "test-topic2" }',
)
async_fire_mqtt_message(
hass,
"homeassistant/binary_sensor/bla/config",
'{ "name": "Wine", "state_topic": "test-topic3" }',
)
await hass.async_block_till_done()

assert len(hass.states.async_entity_ids("binary_sensor")) == 1
state = hass.states.get("binary_sensor.beer")
assert state is not None

assert len(events) == 3
# Add the entity
assert events[0].data["entity_id"] == "binary_sensor.beer"
assert events[0].data["old_state"] is None
assert events[0].data["new_state"].attributes["friendly_name"] == "Beer"
# Update the entity
assert events[1].data["entity_id"] == "binary_sensor.beer"
assert events[1].data["new_state"] is not None
assert events[1].data["old_state"] is not None
assert events[1].data["new_state"].attributes["friendly_name"] == "Milk"
# Update the entity
assert events[2].data["entity_id"] == "binary_sensor.beer"
assert events[2].data["new_state"] is not None
assert events[2].data["old_state"] is not None
assert events[2].data["new_state"].attributes["friendly_name"] == "Wine"


async def test_duplicate_removal(hass, mqtt_mock, caplog):
"""Test for a non duplicate component."""
async_fire_mqtt_message(
Expand Down
2 changes: 2 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,8 @@ async def mqtt_mock(hass, mqtt_client_mock, mqtt_config):
)
mqtt_component_mock.conf = hass.data["mqtt"].conf # For diagnostics
mqtt_component_mock._mqttc = mqtt_client_mock
# connected set to True to get a more realistics behavior when subscribing
hass.data["mqtt"].connected = True

hass.data["mqtt"] = mqtt_component_mock
component = hass.data["mqtt"]
Expand Down