Skip to content

Commit

Permalink
Remove last_reset attribute and set state class to `total_increasin…
Browse files Browse the repository at this point in the history
…g` for zwave_js energy sensors (home-assistant#54818)
  • Loading branch information
emontnemery authored Aug 18, 2021
1 parent aef8ec9 commit 5536e24
Show file tree
Hide file tree
Showing 4 changed files with 18 additions and 129 deletions.
53 changes: 5 additions & 48 deletions homeassistant/components/zwave_js/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
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
Expand All @@ -36,8 +36,6 @@
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
Expand Down Expand Up @@ -218,7 +216,7 @@ def native_unit_of_measurement(self) -> str | None:
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__(
Expand All @@ -231,51 +229,10 @@ def __init__(
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
Expand Down
5 changes: 0 additions & 5 deletions tests/components/zwave_js/common.py
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -35,6 +33,3 @@
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)
18 changes: 0 additions & 18 deletions tests/components/zwave_js/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,6 @@
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
Expand Down Expand Up @@ -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
71 changes: 13 additions & 58 deletions tests/components/zwave_js/test_sensor.py
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -29,14 +30,11 @@
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,
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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

0 comments on commit 5536e24

Please sign in to comment.