From 5536e24dec7d1cfd221eeb881425d85c1dd3bdbd Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Wed, 18 Aug 2021 15:11:10 +0200 Subject: [PATCH] Remove `last_reset` attribute and set state class to `total_increasing` for zwave_js energy sensors (#54818) --- homeassistant/components/zwave_js/sensor.py | 53 ++------------- tests/components/zwave_js/common.py | 5 -- tests/components/zwave_js/conftest.py | 18 ------ tests/components/zwave_js/test_sensor.py | 71 ++++----------------- 4 files changed, 18 insertions(+), 129 deletions(-) diff --git a/homeassistant/components/zwave_js/sensor.py b/homeassistant/components/zwave_js/sensor.py index deacf3d874a..220184f5669 100644 --- a/homeassistant/components/zwave_js/sensor.py +++ b/homeassistant/components/zwave_js/sensor.py @@ -11,13 +11,13 @@ from zwave_js_server.model.node import Node as ZwaveNode from zwave_js_server.model.value import ConfigurationValue from homeassistant.components.sensor import ( - ATTR_LAST_RESET, DEVICE_CLASS_BATTERY, DEVICE_CLASS_ENERGY, DEVICE_CLASS_ILLUMINANCE, DEVICE_CLASS_POWER, DOMAIN as SENSOR_DOMAIN, STATE_CLASS_MEASUREMENT, + STATE_CLASS_TOTAL_INCREASING, SensorEntity, ) from homeassistant.config_entries import ConfigEntry @@ -36,8 +36,6 @@ from homeassistant.helpers.dispatcher import ( async_dispatcher_send, ) from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers.restore_state import RestoreEntity -from homeassistant.util import dt from .const import ATTR_METER_TYPE, ATTR_VALUE, DATA_CLIENT, DOMAIN, SERVICE_RESET_METER from .discovery import ZwaveDiscoveryInfo @@ -218,7 +216,7 @@ class ZWaveNumericSensor(ZwaveSensorBase): return str(self.info.primary_value.metadata.unit) -class ZWaveMeterSensor(ZWaveNumericSensor, RestoreEntity): +class ZWaveMeterSensor(ZWaveNumericSensor): """Representation of a Z-Wave Meter CC sensor.""" def __init__( @@ -231,51 +229,10 @@ class ZWaveMeterSensor(ZWaveNumericSensor, RestoreEntity): super().__init__(config_entry, client, info) # Entity class attributes - self._attr_state_class = STATE_CLASS_MEASUREMENT if self.device_class == DEVICE_CLASS_ENERGY: - self._attr_last_reset = dt.utc_from_timestamp(0) - - @callback - def async_update_last_reset( - self, node: ZwaveNode, endpoint: int, meter_type: int | None - ) -> None: - """Update last reset.""" - # If the signal is not for this node or is for a different endpoint, - # or a meter type was specified and doesn't match this entity's meter type: - if ( - self.info.node != node - or self.info.primary_value.endpoint != endpoint - or meter_type is not None - and self.info.primary_value.metadata.cc_specific.get("meterType") - != meter_type - ): - return - - self._attr_last_reset = dt.utcnow() - self.async_write_ha_state() - - async def async_added_to_hass(self) -> None: - """Call when entity is added.""" - await super().async_added_to_hass() - - # If the meter is not an accumulating meter type, do not reset. - if self.device_class != DEVICE_CLASS_ENERGY: - return - - # Restore the last reset time from stored state - restored_state = await self.async_get_last_state() - if restored_state and ATTR_LAST_RESET in restored_state.attributes: - self._attr_last_reset = dt.parse_datetime( - restored_state.attributes[ATTR_LAST_RESET] - ) - - self.async_on_remove( - async_dispatcher_connect( - self.hass, - f"{DOMAIN}_{SERVICE_RESET_METER}", - self.async_update_last_reset, - ) - ) + self._attr_state_class = STATE_CLASS_TOTAL_INCREASING + else: + self._attr_state_class = STATE_CLASS_MEASUREMENT async def async_reset_meter( self, meter_type: int | None = None, value: int | None = None diff --git a/tests/components/zwave_js/common.py b/tests/components/zwave_js/common.py index 0c6b19698a9..2590149c462 100644 --- a/tests/components/zwave_js/common.py +++ b/tests/components/zwave_js/common.py @@ -1,6 +1,4 @@ """Provide common test tools for Z-Wave JS.""" -from datetime import datetime, timezone - AIR_TEMPERATURE_SENSOR = "sensor.multisensor_6_air_temperature" HUMIDITY_SENSOR = "sensor.multisensor_6_humidity" POWER_SENSOR = "sensor.smart_plug_with_two_usb_ports_value_electric_consumed" @@ -35,6 +33,3 @@ ID_LOCK_CONFIG_PARAMETER_SENSOR = ( ZEN_31_ENTITY = "light.kitchen_under_cabinet_lights" METER_ENERGY_SENSOR = "sensor.smart_switch_6_electric_consumed_kwh" METER_VOLTAGE_SENSOR = "sensor.smart_switch_6_electric_consumed_v" - -DATETIME_ZERO = datetime(1970, 1, 1, 0, 0, 0, tzinfo=timezone.utc) -DATETIME_LAST_RESET = datetime(2020, 1, 1, 0, 0, 0, tzinfo=timezone.utc) diff --git a/tests/components/zwave_js/conftest.py b/tests/components/zwave_js/conftest.py index 8165dac33a7..900a7937539 100644 --- a/tests/components/zwave_js/conftest.py +++ b/tests/components/zwave_js/conftest.py @@ -11,11 +11,6 @@ from zwave_js_server.model.driver import Driver from zwave_js_server.model.node import Node from zwave_js_server.version import VersionInfo -from homeassistant.components.sensor import ATTR_LAST_RESET -from homeassistant.core import State - -from .common import DATETIME_LAST_RESET - from tests.common import MockConfigEntry, load_fixture # Add-on fixtures @@ -858,16 +853,3 @@ def lock_popp_electric_strike_lock_control_fixture( def firmware_file_fixture(): """Return mock firmware file stream.""" return io.BytesIO(bytes(10)) - - -@pytest.fixture(name="restore_last_reset") -def restore_last_reset_fixture(): - """Return mock restore last reset.""" - state = State( - "sensor.test", "test", {ATTR_LAST_RESET: DATETIME_LAST_RESET.isoformat()} - ) - with patch( - "homeassistant.components.zwave_js.sensor.ZWaveMeterSensor.async_get_last_state", - return_value=state, - ): - yield state diff --git a/tests/components/zwave_js/test_sensor.py b/tests/components/zwave_js/test_sensor.py index 268d8ee1380..6d64f6f92dd 100644 --- a/tests/components/zwave_js/test_sensor.py +++ b/tests/components/zwave_js/test_sensor.py @@ -1,9 +1,10 @@ """Test the Z-Wave JS sensor platform.""" -from unittest.mock import patch - from zwave_js_server.event import Event -from homeassistant.components.sensor import ATTR_LAST_RESET, STATE_CLASS_MEASUREMENT +from homeassistant.components.sensor import ( + STATE_CLASS_MEASUREMENT, + STATE_CLASS_TOTAL_INCREASING, +) from homeassistant.components.zwave_js.const import ( ATTR_METER_TYPE, ATTR_VALUE, @@ -29,14 +30,11 @@ from homeassistant.helpers import entity_registry as er from .common import ( AIR_TEMPERATURE_SENSOR, CURRENT_SENSOR, - DATETIME_LAST_RESET, - DATETIME_ZERO, ENERGY_SENSOR, HUMIDITY_SENSOR, ID_LOCK_CONFIG_PARAMETER_SENSOR, INDICATOR_SENSOR, METER_ENERGY_SENSOR, - METER_VOLTAGE_SENSOR, NOTIFICATION_MOTION_SENSOR, POWER_SENSOR, VOLTAGE_SENSOR, @@ -76,7 +74,7 @@ async def test_energy_sensors(hass, hank_binary_switch, integration): assert state.state == "0.16" assert state.attributes["unit_of_measurement"] == ENERGY_KILO_WATT_HOUR assert state.attributes["device_class"] == DEVICE_CLASS_ENERGY - assert state.attributes["state_class"] == STATE_CLASS_MEASUREMENT + assert state.attributes["state_class"] == STATE_CLASS_TOTAL_INCREASING state = hass.states.get(VOLTAGE_SENSOR) @@ -192,31 +190,14 @@ async def test_reset_meter( client.async_send_command.return_value = {} client.async_send_command_no_wait.return_value = {} - # Validate that non accumulating meter does not have a last reset attribute - - assert ATTR_LAST_RESET not in hass.states.get(METER_VOLTAGE_SENSOR).attributes - - # Validate that the sensor last reset is starting from nothing - assert ( - hass.states.get(METER_ENERGY_SENSOR).attributes[ATTR_LAST_RESET] - == DATETIME_ZERO.isoformat() - ) - - # Test successful meter reset call, patching utcnow so we can make sure the last - # reset gets updated - with patch("homeassistant.util.dt.utcnow", return_value=DATETIME_LAST_RESET): - await hass.services.async_call( - DOMAIN, - SERVICE_RESET_METER, - { - ATTR_ENTITY_ID: METER_ENERGY_SENSOR, - }, - blocking=True, - ) - - assert ( - hass.states.get(METER_ENERGY_SENSOR).attributes[ATTR_LAST_RESET] - == DATETIME_LAST_RESET.isoformat() + # Test successful meter reset call + await hass.services.async_call( + DOMAIN, + SERVICE_RESET_METER, + { + ATTR_ENTITY_ID: METER_ENERGY_SENSOR, + }, + blocking=True, ) assert len(client.async_send_command_no_wait.call_args_list) == 1 @@ -226,10 +207,6 @@ async def test_reset_meter( assert args["endpoint"] == 0 assert args["args"] == [] - # Validate that non accumulating meter does not have a last reset attribute - - assert ATTR_LAST_RESET not in hass.states.get(METER_VOLTAGE_SENSOR).attributes - client.async_send_command_no_wait.reset_mock() # Test successful meter reset call with options @@ -251,26 +228,4 @@ async def test_reset_meter( assert args["endpoint"] == 0 assert args["args"] == [{"type": 1, "targetValue": 2}] - # Validate that non accumulating meter does not have a last reset attribute - - assert ATTR_LAST_RESET not in hass.states.get(METER_VOLTAGE_SENSOR).attributes - client.async_send_command_no_wait.reset_mock() - - -async def test_restore_last_reset( - hass, - client, - aeon_smart_switch_6, - restore_last_reset, - integration, -): - """Test restoring last_reset on setup.""" - assert ( - hass.states.get(METER_ENERGY_SENSOR).attributes[ATTR_LAST_RESET] - == DATETIME_LAST_RESET.isoformat() - ) - - # Validate that non accumulating meter does not have a last reset attribute - - assert ATTR_LAST_RESET not in hass.states.get(METER_VOLTAGE_SENSOR).attributes