diff --git a/homeassistant/components/mqtt/client.py b/homeassistant/components/mqtt/client.py index 557d418c54..3a95fe4ef6 100644 --- a/homeassistant/components/mqtt/client.py +++ b/homeassistant/components/mqtt/client.py @@ -583,12 +583,16 @@ class MQTT: self._async_track_subscription(subscription) self._matching_subscriptions.cache_clear() - if self._init_payload.get(subscription, False) and topic in self._last_payload: + if topic in self._last_payload and not self._init_payload.get( + subscription, False + ): + # pylint: disable-next=import-outside-toplevel + import paho.mqtt.client as mqtt + # replay last payload of retained topics we already discovered and # skip subscribing at the broker self._last_subscribe = time.time() - msg = mqtt.MQTTMessage() - msg.topic = topic + msg = mqtt.MQTTMessage(topic=topic.encode("utf-8")) msg.retain = True msg.payload, msg.qos = self._last_payload[topic] self._mqtt_on_message(self._mqttc, None, msg) @@ -774,7 +778,7 @@ class MQTT: timestamp = dt_util.utcnow() # Cache last payload if len(msg.payload): - self._last_payload["topic"] = (msg.payload, msg.qos) + self._last_payload[msg.topic] = (msg.payload, msg.qos) elif msg.topic in self._last_payload: del self._last_payload[msg.topic] diff --git a/tests/components/mqtt/test_init.py b/tests/components/mqtt/test_init.py index 9a7dbc6eec..3627a43bb1 100644 --- a/tests/components/mqtt/test_init.py +++ b/tests/components/mqtt/test_init.py @@ -1264,6 +1264,7 @@ async def test_subscribe_same_topic( mqtt_client_mock.subscribe.assert_called() +@patch("homeassistant.components.mqtt.client.SUBSCRIBE_COOLDOWN", 0.0) async def test_replaying_payload_same_topic( hass: HomeAssistant, mqtt_client_mock: MqttMockPahoClient, @@ -1296,21 +1297,21 @@ async def test_replaying_payload_same_topic( ) # Simulate a (retained) message played back await hass.async_block_till_done() assert len(calls_a) == 1 - mqtt_client_mock.subscribe.assert_called() calls_a = [] - mqtt_client_mock.reset_mock() await mqtt.async_subscribe(hass, "test/state", _callback_b) async_fire_mqtt_message( hass, "test/state", "online", qos=0, retain=True ) # Simulate a (retained) message played back on new subscriptions await hass.async_block_till_done() + await hass.async_block_till_done() + await hass.async_block_till_done() # The retained message playback should only be processed by the new subscription # The existing subscription already got the latest update, # hence the existing subscription should not receive the replayed payload. assert len(calls_a) == 0 assert len(calls_b) == 1 - mqtt_client_mock.subscribe.assert_called() + mqtt_client_mock.subscribe.assert_called_once() calls_a = [] calls_b = [] @@ -1333,6 +1334,7 @@ async def test_replaying_payload_same_topic( with patch("homeassistant.components.mqtt.client.DISCOVERY_COOLDOWN", 0): mqtt_client_mock.on_connect(None, None, None, 0) await hass.async_block_till_done() + await hass.async_block_till_done() mqtt_client_mock.subscribe.assert_called() async_fire_mqtt_message( hass, "test/state", "online", qos=0, retain=True