diff --git a/homeassistant/components/mqtt/event.py b/homeassistant/components/mqtt/event.py index c9302bf65b1..351eb422edc 100644 --- a/homeassistant/components/mqtt/event.py +++ b/homeassistant/components/mqtt/event.py @@ -35,7 +35,6 @@ from .mixins import ( MQTT_ENTITY_COMMON_SCHEMA, MqttEntity, async_setup_entity_entry_helper, - write_state_on_attr_change, ) from .models import ( MqttValueTemplate, @@ -43,6 +42,7 @@ from .models import ( ReceiveMessage, ReceivePayloadType, ) +from .util import get_mqtt_data _LOGGER = logging.getLogger(__name__) @@ -120,9 +120,15 @@ class MqttEvent(MqttEntity, EventEntity): @callback @log_messages(self.hass, self.entity_id) - @write_state_on_attr_change(self, {"state"}) def message_received(msg: ReceiveMessage) -> None: """Handle new MQTT messages.""" + if msg.retain: + _LOGGER.debug( + "Ignoring event trigger from replayed retained payload '%s' on topic %s", + msg.payload, + msg.topic, + ) + return event_attributes: dict[str, Any] = {} event_type: str payload = self._template(msg.payload, PayloadSentinel.DEFAULT) @@ -183,6 +189,8 @@ class MqttEvent(MqttEntity, EventEntity): payload, ) return + mqtt_data = get_mqtt_data(self.hass) + mqtt_data.state_write_requests.write_state_request(self) topics["state_topic"] = { "topic": self._config[CONF_STATE_TOPIC], diff --git a/tests/components/mqtt/test_event.py b/tests/components/mqtt/test_event.py index e178eb40c0e..1a75d61c733 100644 --- a/tests/components/mqtt/test_event.py +++ b/tests/components/mqtt/test_event.py @@ -88,6 +88,68 @@ async def test_setting_event_value_via_mqtt_message( assert state.attributes.get("duration") == "short" +@pytest.mark.freeze_time("2023-08-01 00:00:00+00:00") +@pytest.mark.parametrize("hass_config", [DEFAULT_CONFIG]) +async def test_multiple_events_are_all_updating_the_state( + hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator +) -> None: + """Test all events are respected and trigger a state write.""" + await mqtt_mock_entry() + with patch( + "homeassistant.components.mqtt.mixins.MqttEntity.async_write_ha_state" + ) as mock_async_ha_write_state: + async_fire_mqtt_message( + hass, "test-topic", '{"event_type": "press", "duration": "short" }' + ) + assert len(mock_async_ha_write_state.mock_calls) == 1 + async_fire_mqtt_message( + hass, "test-topic", '{"event_type": "press", "duration": "short" }' + ) + assert len(mock_async_ha_write_state.mock_calls) == 2 + + +@pytest.mark.parametrize("hass_config", [DEFAULT_CONFIG]) +async def test_handling_retained_event_payloads( + hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator +) -> None: + """Test if event messages with a retained flag are ignored.""" + await mqtt_mock_entry() + with patch( + "homeassistant.components.mqtt.mixins.MqttEntity.async_write_ha_state" + ) as mock_async_ha_write_state: + async_fire_mqtt_message( + hass, + "test-topic", + '{"event_type": "press", "duration": "short" }', + retain=True, + ) + assert len(mock_async_ha_write_state.mock_calls) == 0 + + async_fire_mqtt_message( + hass, + "test-topic", + '{"event_type": "press", "duration": "short" }', + retain=False, + ) + assert len(mock_async_ha_write_state.mock_calls) == 1 + + async_fire_mqtt_message( + hass, + "test-topic", + '{"event_type": "press", "duration": "short" }', + retain=True, + ) + assert len(mock_async_ha_write_state.mock_calls) == 1 + + async_fire_mqtt_message( + hass, + "test-topic", + '{"event_type": "press", "duration": "short" }', + retain=False, + ) + assert len(mock_async_ha_write_state.mock_calls) == 2 + + @pytest.mark.freeze_time("2023-08-01 00:00:00+00:00") @pytest.mark.parametrize("hass_config", [DEFAULT_CONFIG]) @pytest.mark.parametrize(