Fix ZHA temperature sensor restoration (#30661)
* Add test for restoring state for zha temp. * Don't restore unit of measurement for ZHA sensors. Properly restore ZHA temperature sensor state.
This commit is contained in:
parent
605b0ceb5f
commit
008dddb17c
2 changed files with 135 additions and 8 deletions
|
@ -12,9 +12,15 @@ from homeassistant.components.sensor import (
|
|||
DEVICE_CLASS_TEMPERATURE,
|
||||
DOMAIN,
|
||||
)
|
||||
from homeassistant.const import ATTR_UNIT_OF_MEASUREMENT, POWER_WATT, TEMP_CELSIUS
|
||||
from homeassistant.const import (
|
||||
ATTR_UNIT_OF_MEASUREMENT,
|
||||
POWER_WATT,
|
||||
STATE_UNKNOWN,
|
||||
TEMP_CELSIUS,
|
||||
)
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.util.temperature import fahrenheit_to_celsius
|
||||
|
||||
from .core.const import (
|
||||
CHANNEL_ELECTRICAL_MEASUREMENT,
|
||||
|
@ -160,7 +166,6 @@ class Sensor(ZhaEntity):
|
|||
def async_restore_last_state(self, last_state):
|
||||
"""Restore previous state."""
|
||||
self._state = last_state.state
|
||||
self._unit = last_state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
|
||||
|
||||
@callback
|
||||
async def async_state_attr_provider(self):
|
||||
|
@ -277,3 +282,14 @@ class Temperature(Sensor):
|
|||
_device_class = DEVICE_CLASS_TEMPERATURE
|
||||
_divisor = 100
|
||||
_unit = TEMP_CELSIUS
|
||||
|
||||
@callback
|
||||
def async_restore_last_state(self, last_state):
|
||||
"""Restore previous state."""
|
||||
if last_state.state == STATE_UNKNOWN:
|
||||
return
|
||||
if last_state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) != TEMP_CELSIUS:
|
||||
ftemp = float(last_state.state)
|
||||
self._state = round(fahrenheit_to_celsius(ftemp), 1)
|
||||
return
|
||||
self._state = last_state.state
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
"""Test zha sensor."""
|
||||
import pytest
|
||||
import zigpy.zcl.clusters.general as general
|
||||
import zigpy.zcl.clusters.homeautomation as homeautomation
|
||||
import zigpy.zcl.clusters.measurement as measurement
|
||||
|
@ -6,7 +7,20 @@ import zigpy.zcl.clusters.smartenergy as smartenergy
|
|||
import zigpy.zcl.foundation as zcl_f
|
||||
|
||||
from homeassistant.components.sensor import DOMAIN
|
||||
from homeassistant.const import STATE_UNAVAILABLE, STATE_UNKNOWN
|
||||
import homeassistant.config as config_util
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
ATTR_UNIT_OF_MEASUREMENT,
|
||||
CONF_UNIT_SYSTEM,
|
||||
CONF_UNIT_SYSTEM_IMPERIAL,
|
||||
CONF_UNIT_SYSTEM_METRIC,
|
||||
STATE_UNAVAILABLE,
|
||||
STATE_UNKNOWN,
|
||||
TEMP_CELSIUS,
|
||||
TEMP_FAHRENHEIT,
|
||||
)
|
||||
from homeassistant.helpers import restore_state
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from .common import (
|
||||
async_enable_traffic,
|
||||
|
@ -39,7 +53,7 @@ async def test_sensor(hass, config_entry, zha_gateway):
|
|||
# ensure the sensor entity was created for each id in cluster_ids
|
||||
for cluster_id in cluster_ids:
|
||||
zigpy_device_info = zigpy_device_infos[cluster_id]
|
||||
entity_id = zigpy_device_info["entity_id"]
|
||||
entity_id = zigpy_device_info[ATTR_ENTITY_ID]
|
||||
assert hass.states.get(entity_id).state == STATE_UNAVAILABLE
|
||||
|
||||
# allow traffic to flow through the gateway and devices
|
||||
|
@ -55,7 +69,7 @@ async def test_sensor(hass, config_entry, zha_gateway):
|
|||
# test that the sensors now have a state of unknown
|
||||
for cluster_id in cluster_ids:
|
||||
zigpy_device_info = zigpy_device_infos[cluster_id]
|
||||
entity_id = zigpy_device_info["entity_id"]
|
||||
entity_id = zigpy_device_info[ATTR_ENTITY_ID]
|
||||
assert hass.states.get(entity_id).state == STATE_UNKNOWN
|
||||
|
||||
# get the humidity device info and test the associated sensor logic
|
||||
|
@ -128,7 +142,7 @@ async def async_build_devices(hass, zha_gateway, config_entry, cluster_ids):
|
|||
device_info["cluster"] = zigpy_device.endpoints.get(1).in_clusters[cluster_id]
|
||||
zha_device = zha_gateway.get_device(zigpy_device.ieee)
|
||||
device_info["zha_device"] = zha_device
|
||||
device_info["entity_id"] = await find_entity_id(DOMAIN, zha_device, hass)
|
||||
device_info[ATTR_ENTITY_ID] = await find_entity_id(DOMAIN, zha_device, hass)
|
||||
await hass.async_block_till_done()
|
||||
return device_infos
|
||||
|
||||
|
@ -187,6 +201,103 @@ def assert_state(hass, device_info, state, unit_of_measurement):
|
|||
This is used to ensure that the logic in each sensor class handled the
|
||||
attribute report it received correctly.
|
||||
"""
|
||||
hass_state = hass.states.get(device_info["entity_id"])
|
||||
hass_state = hass.states.get(device_info[ATTR_ENTITY_ID])
|
||||
assert hass_state.state == state
|
||||
assert hass_state.attributes.get("unit_of_measurement") == unit_of_measurement
|
||||
assert hass_state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == unit_of_measurement
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def hass_ms(hass):
|
||||
"""Hass instance with measurement system."""
|
||||
|
||||
async def _hass_ms(meas_sys):
|
||||
await config_util.async_process_ha_core_config(
|
||||
hass, {CONF_UNIT_SYSTEM: meas_sys}
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
return hass
|
||||
|
||||
return _hass_ms
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def core_rs(hass_storage):
|
||||
"""Core.restore_state fixture."""
|
||||
|
||||
def _storage(entity_id, uom, state):
|
||||
now = dt_util.utcnow().isoformat()
|
||||
|
||||
hass_storage[restore_state.STORAGE_KEY] = {
|
||||
"version": restore_state.STORAGE_VERSION,
|
||||
"key": restore_state.STORAGE_KEY,
|
||||
"data": [
|
||||
{
|
||||
"state": {
|
||||
"entity_id": entity_id,
|
||||
"state": str(state),
|
||||
"attributes": {ATTR_UNIT_OF_MEASUREMENT: uom},
|
||||
"last_changed": now,
|
||||
"last_updated": now,
|
||||
"context": {
|
||||
"id": "3c2243ff5f30447eb12e7348cfd5b8ff",
|
||||
"user_id": None,
|
||||
},
|
||||
},
|
||||
"last_seen": now,
|
||||
}
|
||||
],
|
||||
}
|
||||
return
|
||||
|
||||
return _storage
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"uom, raw_temp, expected, restore",
|
||||
[
|
||||
(TEMP_CELSIUS, 2900, 29, False),
|
||||
(TEMP_CELSIUS, 2900, 29, True),
|
||||
(TEMP_FAHRENHEIT, 2900, 84, False),
|
||||
(TEMP_FAHRENHEIT, 2900, 84, True),
|
||||
],
|
||||
)
|
||||
async def test_temp_uom(
|
||||
uom, raw_temp, expected, restore, hass_ms, config_entry, zha_gateway, core_rs
|
||||
):
|
||||
"""Test zha temperature sensor unit of measurement."""
|
||||
|
||||
entity_id = "sensor.fake1026_fakemodel1026_004f3202_temperature"
|
||||
if restore:
|
||||
core_rs(entity_id, uom, state=(expected - 2))
|
||||
|
||||
hass = await hass_ms(
|
||||
CONF_UNIT_SYSTEM_METRIC if uom == TEMP_CELSIUS else CONF_UNIT_SYSTEM_IMPERIAL
|
||||
)
|
||||
|
||||
# list of cluster ids to create devices and sensor entities for
|
||||
temp_cluster = measurement.TemperatureMeasurement
|
||||
cluster_ids = [temp_cluster.cluster_id]
|
||||
|
||||
# devices that were created from cluster_ids list above
|
||||
zigpy_device_infos = await async_build_devices(
|
||||
hass, zha_gateway, config_entry, cluster_ids
|
||||
)
|
||||
|
||||
zigpy_device_info = zigpy_device_infos[temp_cluster.cluster_id]
|
||||
zha_device = zigpy_device_info["zha_device"]
|
||||
if not restore:
|
||||
assert hass.states.get(entity_id).state == STATE_UNAVAILABLE
|
||||
|
||||
# allow traffic to flow through the gateway and devices
|
||||
await async_enable_traffic(hass, zha_gateway, [zha_device])
|
||||
|
||||
# test that the sensors now have a state of unknown
|
||||
if not restore:
|
||||
assert hass.states.get(entity_id).state == STATE_UNKNOWN
|
||||
|
||||
await send_attribute_report(hass, zigpy_device_info["cluster"], 0, raw_temp)
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get(entity_id)
|
||||
assert state is not None
|
||||
assert round(float(state.state)) == expected
|
||||
assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == uom
|
||||
|
|
Loading…
Add table
Reference in a new issue