From 375f48142c6949fb97e42cbd4a5683fc8c1ceb9c Mon Sep 17 00:00:00 2001 From: Jan Bouwhuis Date: Sun, 2 Jun 2024 21:25:05 +0200 Subject: [PATCH] Fix handling undecoded mqtt sensor payloads (#118633) --- homeassistant/components/mqtt/sensor.py | 24 ++++++++++------- tests/components/mqtt/test_sensor.py | 36 +++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/mqtt/sensor.py b/homeassistant/components/mqtt/sensor.py index 12de26b2358a5..043bc9a5c0e8c 100644 --- a/homeassistant/components/mqtt/sensor.py +++ b/homeassistant/components/mqtt/sensor.py @@ -237,28 +237,32 @@ def _update_state(self, msg: ReceiveMessage) -> None: payload = msg.payload if payload is PayloadSentinel.DEFAULT: return - new_value = str(payload) + if not isinstance(payload, str): + _LOGGER.warning( + "Invalid undecoded state message '%s' received from '%s'", + payload, + msg.topic, + ) + return if self._numeric_state_expected: - if new_value == "": + if payload == "": _LOGGER.debug("Ignore empty state from '%s'", msg.topic) - elif new_value == PAYLOAD_NONE: + elif payload == PAYLOAD_NONE: self._attr_native_value = None else: - self._attr_native_value = new_value + self._attr_native_value = payload return if self.device_class in { None, SensorDeviceClass.ENUM, - } and not check_state_too_long(_LOGGER, new_value, self.entity_id, msg): - self._attr_native_value = new_value + } and not check_state_too_long(_LOGGER, payload, self.entity_id, msg): + self._attr_native_value = payload return try: - if (payload_datetime := dt_util.parse_datetime(new_value)) is None: + if (payload_datetime := dt_util.parse_datetime(payload)) is None: raise ValueError except ValueError: - _LOGGER.warning( - "Invalid state message '%s' from '%s'", msg.payload, msg.topic - ) + _LOGGER.warning("Invalid state message '%s' from '%s'", payload, msg.topic) self._attr_native_value = None return if self.device_class == SensorDeviceClass.DATE: diff --git a/tests/components/mqtt/test_sensor.py b/tests/components/mqtt/test_sensor.py index b827027716198..bde85abf3fb74 100644 --- a/tests/components/mqtt/test_sensor.py +++ b/tests/components/mqtt/test_sensor.py @@ -110,6 +110,42 @@ async def test_setting_sensor_value_via_mqtt_message( assert state.attributes.get("unit_of_measurement") == "fav unit" +@pytest.mark.parametrize( + "hass_config", + [ + { + mqtt.DOMAIN: { + sensor.DOMAIN: { + "name": "test", + "state_topic": "test-topic", + "unit_of_measurement": "%", + "device_class": "battery", + "encoding": "", + } + } + } + ], +) +async def test_handling_undecoded_sensor_value( + hass: HomeAssistant, + mqtt_mock_entry: MqttMockHAClientGenerator, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test the setting of the value via MQTT.""" + await mqtt_mock_entry() + + state = hass.states.get("sensor.test") + assert state.state == STATE_UNKNOWN + + async_fire_mqtt_message(hass, "test-topic", b"88") + state = hass.states.get("sensor.test") + assert state.state == STATE_UNKNOWN + assert ( + "Invalid undecoded state message 'b'88'' received from 'test-topic'" + in caplog.text + ) + + @pytest.mark.parametrize( "hass_config", [