Correct state restoring for MQTT temperature sensors (#66741)

* Correct state restoring for MQTT temperature sensors

* Adjust test

* Adjust test
This commit is contained in:
Erik Montnemery 2022-02-18 11:35:44 +01:00 committed by GitHub
parent bfb1abd3a2
commit 2abcd7cd94
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 11 deletions

View File

@ -13,8 +13,8 @@ from homeassistant.components.sensor import (
DEVICE_CLASSES_SCHEMA,
ENTITY_ID_FORMAT,
STATE_CLASSES_SCHEMA,
RestoreSensor,
SensorDeviceClass,
SensorEntity,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
@ -30,7 +30,6 @@ from homeassistant.core import HomeAssistant, callback
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.event import async_track_point_in_utc_time
from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.util import dt as dt_util
@ -144,7 +143,7 @@ async def _async_setup_entity(
async_add_entities([MqttSensor(hass, config, config_entry, discovery_data)])
class MqttSensor(MqttEntity, SensorEntity, RestoreEntity):
class MqttSensor(MqttEntity, RestoreSensor):
"""Representation of a sensor that can be updated using MQTT."""
_entity_id_format = ENTITY_ID_FORMAT
@ -172,6 +171,8 @@ class MqttSensor(MqttEntity, SensorEntity, RestoreEntity):
and expire_after > 0
and (last_state := await self.async_get_last_state()) is not None
and last_state.state not in [STATE_UNKNOWN, STATE_UNAVAILABLE]
and (last_sensor_data := await self.async_get_last_sensor_data())
is not None
# We might have set up a trigger already after subscribing from
# super().async_added_to_hass(), then we should not restore state
and not self._expiration_trigger
@ -182,7 +183,7 @@ class MqttSensor(MqttEntity, SensorEntity, RestoreEntity):
_LOGGER.debug("Skip state recovery after reload for %s", self.entity_id)
return
self._expired = False
self._state = last_state.state
self._state = last_sensor_data.native_value
self._expiration_trigger = async_track_point_in_utc_time(
self.hass, self._value_is_expired, expiration_at

View File

@ -2,13 +2,19 @@
import copy
from datetime import datetime, timedelta
import json
from unittest.mock import patch
from unittest.mock import MagicMock, patch
import pytest
from homeassistant.components.mqtt.sensor import MQTT_SENSOR_ATTRIBUTES_BLOCKED
import homeassistant.components.sensor as sensor
from homeassistant.const import EVENT_STATE_CHANGED, STATE_UNAVAILABLE, STATE_UNKNOWN
from homeassistant.const import (
EVENT_STATE_CHANGED,
STATE_UNAVAILABLE,
STATE_UNKNOWN,
TEMP_CELSIUS,
TEMP_FAHRENHEIT,
)
import homeassistant.core as ha
from homeassistant.helpers import device_registry as dr
from homeassistant.setup import async_setup_component
@ -989,10 +995,15 @@ async def test_cleanup_triggers_and_restoring_state(
config1["name"] = "test1"
config1["expire_after"] = 30
config1["state_topic"] = "test-topic1"
config1["device_class"] = "temperature"
config1["unit_of_measurement"] = TEMP_FAHRENHEIT
config2 = copy.deepcopy(DEFAULT_CONFIG[domain])
config2["name"] = "test2"
config2["expire_after"] = 5
config2["state_topic"] = "test-topic2"
config2["device_class"] = "temperature"
config2["unit_of_measurement"] = TEMP_CELSIUS
freezer.move_to("2022-02-02 12:01:00+01:00")
@ -1004,7 +1015,7 @@ async def test_cleanup_triggers_and_restoring_state(
await hass.async_block_till_done()
async_fire_mqtt_message(hass, "test-topic1", "100")
state = hass.states.get("sensor.test1")
assert state.state == "100"
assert state.state == "38" # 100 °F -> 38 °C
async_fire_mqtt_message(hass, "test-topic2", "200")
state = hass.states.get("sensor.test2")
@ -1026,14 +1037,14 @@ async def test_cleanup_triggers_and_restoring_state(
assert "State recovered after reload for sensor.test2" not in caplog.text
state = hass.states.get("sensor.test1")
assert state.state == "100"
assert state.state == "38" # 100 °F -> 38 °C
state = hass.states.get("sensor.test2")
assert state.state == STATE_UNAVAILABLE
async_fire_mqtt_message(hass, "test-topic1", "101")
async_fire_mqtt_message(hass, "test-topic1", "80")
state = hass.states.get("sensor.test1")
assert state.state == "101"
assert state.state == "27" # 80 °F -> 27 °C
async_fire_mqtt_message(hass, "test-topic2", "201")
state = hass.states.get("sensor.test2")
@ -1057,10 +1068,16 @@ async def test_skip_restoring_state_with_over_due_expire_trigger(
{},
last_changed=datetime.fromisoformat("2022-02-02 12:01:35+01:00"),
)
fake_extra_data = MagicMock()
with patch(
"homeassistant.helpers.restore_state.RestoreEntity.async_get_last_state",
return_value=fake_state,
), assert_setup_component(1, domain):
), patch(
"homeassistant.helpers.restore_state.RestoreEntity.async_get_last_extra_data",
return_value=fake_extra_data,
), assert_setup_component(
1, domain
):
assert await async_setup_component(hass, domain, {domain: config3})
await hass.async_block_till_done()
assert "Skip state recovery after reload for sensor.test3" in caplog.text
@ -1087,4 +1104,5 @@ async def test_encoding_subscribable_topics(
value,
attribute,
attribute_value,
skip_raw_test=True,
)