From 9e4e43cf77a210edd046a1476ece99854763e1e8 Mon Sep 17 00:00:00 2001 From: Raman Gupta <7243222+raman325@users.noreply.github.com> Date: Sat, 8 Jan 2022 07:23:29 -0500 Subject: [PATCH] Handle zwave_js metadata/value updates when the unit changes (#63579) * Handle zwave_js metadata updates when the unit changes * Use value updated event instead of metadata updated event so we don't get an invalid state value * update comments and formatting * simplify * Update tests/components/zwave_js/test_sensor.py Co-authored-by: Martin Hjelmare * Update tests/components/zwave_js/test_sensor.py Co-authored-by: Martin Hjelmare * Update tests/components/zwave_js/test_sensor.py Co-authored-by: Martin Hjelmare * fix tests * add additional assertions * Add unit checks and simplify logic * Add unit assertion Co-authored-by: Martin Hjelmare --- homeassistant/components/zwave_js/sensor.py | 14 ++++- tests/components/zwave_js/test_sensor.py | 62 +++++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/zwave_js/sensor.py b/homeassistant/components/zwave_js/sensor.py index 81ab803d982..76cb6fd22e9 100644 --- a/homeassistant/components/zwave_js/sensor.py +++ b/homeassistant/components/zwave_js/sensor.py @@ -56,7 +56,10 @@ from .const import ( SERVICE_RESET_METER, ) from .discovery import ZwaveDiscoveryInfo -from .discovery_data_template import NumericSensorDataTemplateData +from .discovery_data_template import ( + NumericSensorDataTemplate, + NumericSensorDataTemplateData, +) from .entity import ZWaveBaseEntity from .helpers import get_device_id @@ -296,6 +299,15 @@ class ZWaveStringSensor(ZwaveSensorBase): class ZWaveNumericSensor(ZwaveSensorBase): """Representation of a Z-Wave Numeric sensor.""" + @callback + def on_value_update(self) -> None: + """Handle scale changes for this value on value updated event.""" + self._attr_native_unit_of_measurement = ( + NumericSensorDataTemplate() + .resolve_data(self.info.primary_value) + .unit_of_measurement + ) + @property def native_value(self) -> float: """Return state of the sensor.""" diff --git a/tests/components/zwave_js/test_sensor.py b/tests/components/zwave_js/test_sensor.py index 03c0aa07599..2d120411513 100644 --- a/tests/components/zwave_js/test_sensor.py +++ b/tests/components/zwave_js/test_sensor.py @@ -358,3 +358,65 @@ async def test_special_meters(hass, aeon_smart_switch_6_state, client, integrati assert state assert ATTR_DEVICE_CLASS not in state.attributes assert state.attributes[ATTR_STATE_CLASS] is SensorStateClass.MEASUREMENT + + +async def test_unit_change(hass, zp3111, client, integration): + """Test unit change via metadata updated event is handled by numeric sensors.""" + entity_id = "sensor.4_in_1_sensor_air_temperature" + state = hass.states.get(entity_id) + assert state + assert state.state == "21.98" + assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == TEMP_CELSIUS + event = Event( + "metadata updated", + { + "source": "node", + "event": "metadata updated", + "nodeId": zp3111.node_id, + "args": { + "commandClassName": "Multilevel Sensor", + "commandClass": 49, + "endpoint": 0, + "property": "Air temperature", + "metadata": { + "type": "number", + "readable": True, + "writeable": False, + "label": "Air temperature", + "ccSpecific": {"sensorType": 1, "scale": 1}, + "unit": "°F", + }, + "propertyName": "Air temperature", + "nodeId": zp3111.node_id, + }, + }, + ) + zp3111.receive_event(event) + await hass.async_block_till_done() + state = hass.states.get(entity_id) + assert state + assert state.state == "21.98" + assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == TEMP_CELSIUS + event = Event( + "value updated", + { + "source": "node", + "event": "value updated", + "nodeId": zp3111.node_id, + "args": { + "commandClassName": "Multilevel Sensor", + "commandClass": 49, + "endpoint": 0, + "property": "Air temperature", + "newValue": 212, + "prevValue": 21.98, + "propertyName": "Air temperature", + }, + }, + ) + zp3111.receive_event(event) + await hass.async_block_till_done() + state = hass.states.get(entity_id) + assert state + assert state.state == "100.0" + assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == TEMP_CELSIUS