From e1926caeb91345441ba133ef7768eb887d2e060d Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Wed, 18 Aug 2021 10:03:27 +0200 Subject: [PATCH] Remove STATE_CLASS_TOTAL and last_reset from sensor (#54755) * Remove STATE_CLASS_TOTAL * Update mill sensor * Update tests * Kill last_reset * Return ATTR_LAST_RESET to utility_meter * Update energy cost sensor * Restore last_reset for backwards compatibility * Re-add and update deprecation warning * Update tests * Fix utility_meter * Update EnergyCostSensor * Tweak * Fix rebase mistake * Fix test --- homeassistant/components/energy/sensor.py | 37 +++-- homeassistant/components/mill/sensor.py | 26 +--- homeassistant/components/recorder/models.py | 2 - .../components/recorder/statistics.py | 2 - homeassistant/components/sensor/__init__.py | 18 +-- homeassistant/components/sensor/recorder.py | 41 ++---- .../components/utility_meter/sensor.py | 13 +- tests/components/energy/test_sensor.py | 41 +++--- tests/components/history/test_init.py | 1 - tests/components/recorder/test_statistics.py | 3 - tests/components/sensor/test_init.py | 9 +- tests/components/sensor/test_recorder.py | 126 ++---------------- 12 files changed, 68 insertions(+), 251 deletions(-) diff --git a/homeassistant/components/energy/sensor.py b/homeassistant/components/energy/sensor.py index fd36611acaf..497c762add9 100644 --- a/homeassistant/components/energy/sensor.py +++ b/homeassistant/components/energy/sensor.py @@ -6,9 +6,8 @@ import logging from typing import Any, Final, Literal, TypeVar, cast from homeassistant.components.sensor import ( - ATTR_LAST_RESET, DEVICE_CLASS_MONETARY, - STATE_CLASS_MEASUREMENT, + STATE_CLASS_TOTAL_INCREASING, SensorEntity, ) from homeassistant.const import ( @@ -17,11 +16,10 @@ from homeassistant.const import ( ENERGY_WATT_HOUR, VOLUME_CUBIC_METERS, ) -from homeassistant.core import HomeAssistant, State, callback, split_entity_id +from homeassistant.core import HomeAssistant, callback, split_entity_id from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.event import async_track_state_change_event -from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType -import homeassistant.util.dt as dt_util +from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType, StateType from .const import DOMAIN from .data import EnergyManager, async_get_manager @@ -203,16 +201,15 @@ class EnergyCostSensor(SensorEntity): f"{config[adapter.entity_energy_key]}_{adapter.entity_id_suffix}" ) self._attr_device_class = DEVICE_CLASS_MONETARY - self._attr_state_class = STATE_CLASS_MEASUREMENT + self._attr_state_class = STATE_CLASS_TOTAL_INCREASING self._config = config - self._last_energy_sensor_state: State | None = None + self._last_energy_sensor_state: StateType | None = None self._cur_value = 0.0 - def _reset(self, energy_state: State) -> None: + def _reset(self, energy_state: StateType) -> None: """Reset the cost sensor.""" self._attr_native_value = 0.0 self._cur_value = 0.0 - self._attr_last_reset = dt_util.utcnow() self._last_energy_sensor_state = energy_state self.async_write_ha_state() @@ -223,7 +220,7 @@ class EnergyCostSensor(SensorEntity): cast(str, self._config[self._adapter.entity_energy_key]) ) - if energy_state is None or ATTR_LAST_RESET not in energy_state.attributes: + if energy_state is None: return try: @@ -259,7 +256,7 @@ class EnergyCostSensor(SensorEntity): if self._last_energy_sensor_state is None: # Initialize as it's the first time all required entities are in place. - self._reset(energy_state) + self._reset(energy_state.state) return energy_unit = energy_state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) @@ -280,19 +277,15 @@ class EnergyCostSensor(SensorEntity): ) return - if ( - energy_state.attributes[ATTR_LAST_RESET] - != self._last_energy_sensor_state.attributes[ATTR_LAST_RESET] - ): + if energy < float(self._last_energy_sensor_state): # Energy meter was reset, reset cost sensor too - self._reset(energy_state) - else: - # Update with newly incurred cost - old_energy_value = float(self._last_energy_sensor_state.state) - self._cur_value += (energy - old_energy_value) * energy_price - self._attr_native_value = round(self._cur_value, 2) + self._reset(0) + # Update with newly incurred cost + old_energy_value = float(self._last_energy_sensor_state) + self._cur_value += (energy - old_energy_value) * energy_price + self._attr_native_value = round(self._cur_value, 2) - self._last_energy_sensor_state = energy_state + self._last_energy_sensor_state = energy_state.state async def async_added_to_hass(self) -> None: """Register callbacks.""" diff --git a/homeassistant/components/mill/sensor.py b/homeassistant/components/mill/sensor.py index 5241f95abdb..ce7704ad1be 100644 --- a/homeassistant/components/mill/sensor.py +++ b/homeassistant/components/mill/sensor.py @@ -2,11 +2,10 @@ from homeassistant.components.sensor import ( DEVICE_CLASS_ENERGY, - STATE_CLASS_TOTAL, + STATE_CLASS_TOTAL_INCREASING, SensorEntity, ) from homeassistant.const import ENERGY_KILO_WATT_HOUR -from homeassistant.util import dt as dt_util from .const import CONSUMPTION_TODAY, CONSUMPTION_YEAR, DOMAIN, MANUFACTURER @@ -29,7 +28,7 @@ class MillHeaterEnergySensor(SensorEntity): _attr_device_class = DEVICE_CLASS_ENERGY _attr_native_unit_of_measurement = ENERGY_KILO_WATT_HOUR - _attr_state_class = STATE_CLASS_TOTAL + _attr_state_class = STATE_CLASS_TOTAL_INCREASING def __init__(self, heater, mill_data_connection, sensor_type): """Initialize the sensor.""" @@ -45,16 +44,6 @@ class MillHeaterEnergySensor(SensorEntity): "manufacturer": MANUFACTURER, "model": f"generation {1 if heater.is_gen1 else 2}", } - if self._sensor_type == CONSUMPTION_TODAY: - self._attr_last_reset = dt_util.as_utc( - dt_util.now().replace(hour=0, minute=0, second=0, microsecond=0) - ) - elif self._sensor_type == CONSUMPTION_YEAR: - self._attr_last_reset = dt_util.as_utc( - dt_util.now().replace( - month=1, day=1, hour=0, minute=0, second=0, microsecond=0 - ) - ) async def async_update(self): """Retrieve latest state.""" @@ -71,15 +60,4 @@ class MillHeaterEnergySensor(SensorEntity): self._attr_native_value = _state return - if self.state is not None and _state < self.state: - if self._sensor_type == CONSUMPTION_TODAY: - self._attr_last_reset = dt_util.as_utc( - dt_util.now().replace(hour=0, minute=0, second=0, microsecond=0) - ) - elif self._sensor_type == CONSUMPTION_YEAR: - self._attr_last_reset = dt_util.as_utc( - dt_util.now().replace( - month=1, day=1, hour=0, minute=0, second=0, microsecond=0 - ) - ) self._attr_native_value = _state diff --git a/homeassistant/components/recorder/models.py b/homeassistant/components/recorder/models.py index ff64deb60cd..fe75ba1cb50 100644 --- a/homeassistant/components/recorder/models.py +++ b/homeassistant/components/recorder/models.py @@ -218,7 +218,6 @@ class StatisticData(TypedDict, total=False): mean: float min: float max: float - last_reset: datetime | None state: float sum: float @@ -242,7 +241,6 @@ class Statistics(Base): # type: ignore mean = Column(Float()) min = Column(Float()) max = Column(Float()) - last_reset = Column(DATETIME_TYPE) state = Column(Float()) sum = Column(Float()) diff --git a/homeassistant/components/recorder/statistics.py b/homeassistant/components/recorder/statistics.py index b91e4d160df..6017f050419 100644 --- a/homeassistant/components/recorder/statistics.py +++ b/homeassistant/components/recorder/statistics.py @@ -43,7 +43,6 @@ QUERY_STATISTICS = [ Statistics.mean, Statistics.min, Statistics.max, - Statistics.last_reset, Statistics.state, Statistics.sum, ] @@ -375,7 +374,6 @@ def _sorted_statistics_to_dict( "mean": convert(db_state.mean, units), "min": convert(db_state.min, units), "max": convert(db_state.max, units), - "last_reset": _process_timestamp_to_utc_isoformat(db_state.last_reset), "state": convert(db_state.state, units), "sum": convert(db_state.sum, units), } diff --git a/homeassistant/components/sensor/__init__.py b/homeassistant/components/sensor/__init__.py index 950af5a1375..94fb08c66b1 100644 --- a/homeassistant/components/sensor/__init__.py +++ b/homeassistant/components/sensor/__init__.py @@ -51,7 +51,7 @@ from homeassistant.helpers.typing import ConfigType, StateType _LOGGER: Final = logging.getLogger(__name__) -ATTR_LAST_RESET: Final = "last_reset" +ATTR_LAST_RESET: Final = "last_reset" # Deprecated, to be removed in 2021.11 ATTR_STATE_CLASS: Final = "state_class" DOMAIN: Final = "sensor" @@ -91,14 +91,11 @@ DEVICE_CLASSES_SCHEMA: Final = vol.All(vol.Lower, vol.In(DEVICE_CLASSES)) # The state represents a measurement in present time STATE_CLASS_MEASUREMENT: Final = "measurement" -# The state represents a total amount, e.g. a value of a stock portfolio -STATE_CLASS_TOTAL: Final = "total" # The state represents a monotonically increasing total, e.g. an amount of consumed gas STATE_CLASS_TOTAL_INCREASING: Final = "total_increasing" STATE_CLASSES: Final[list[str]] = [ STATE_CLASS_MEASUREMENT, - STATE_CLASS_TOTAL, STATE_CLASS_TOTAL_INCREASING, ] @@ -132,7 +129,7 @@ class SensorEntityDescription(EntityDescription): """A class that describes sensor entities.""" state_class: str | None = None - last_reset: datetime | None = None + last_reset: datetime | None = None # Deprecated, to be removed in 2021.11 native_unit_of_measurement: str | None = None @@ -140,7 +137,7 @@ class SensorEntity(Entity): """Base class for sensor entities.""" entity_description: SensorEntityDescription - _attr_last_reset: datetime | None + _attr_last_reset: datetime | None # Deprecated, to be removed in 2021.11 _attr_native_unit_of_measurement: str | None _attr_native_value: StateType = None _attr_state_class: str | None @@ -157,7 +154,7 @@ class SensorEntity(Entity): return None @property - def last_reset(self) -> datetime | None: + def last_reset(self) -> datetime | None: # Deprecated, to be removed in 2021.11 """Return the time when the sensor was last reset, if any.""" if hasattr(self, "_attr_last_reset"): return self._attr_last_reset @@ -187,10 +184,9 @@ class SensorEntity(Entity): report_issue = self._suggest_report_issue() _LOGGER.warning( "Entity %s (%s) with state_class %s has set last_reset. Setting " - "last_reset for entities with state_class other than 'total' is " - "deprecated and will be removed from Home Assistant Core 2021.10. " - "Please update your configuration if state_class is manually " - "configured, otherwise %s", + "last_reset is deprecated and will be unsupported from Home " + "Assistant Core 2021.11. Please update your configuration if " + "state_class is manually configured, otherwise %s", self.entity_id, type(self), self.state_class, diff --git a/homeassistant/components/sensor/recorder.py b/homeassistant/components/sensor/recorder.py index 48f80bab5c2..2cbca09c09d 100644 --- a/homeassistant/components/sensor/recorder.py +++ b/homeassistant/components/sensor/recorder.py @@ -17,7 +17,6 @@ from homeassistant.components.sensor import ( DEVICE_CLASS_PRESSURE, DEVICE_CLASS_TEMPERATURE, STATE_CLASS_MEASUREMENT, - STATE_CLASS_TOTAL, STATE_CLASS_TOTAL_INCREASING, STATE_CLASSES, ) @@ -43,7 +42,6 @@ from homeassistant.const import ( VOLUME_CUBIC_METERS, ) from homeassistant.core import HomeAssistant, State -import homeassistant.util.dt as dt_util import homeassistant.util.pressure as pressure_util import homeassistant.util.temperature as temperature_util import homeassistant.util.volume as volume_util @@ -53,11 +51,6 @@ from . import ATTR_LAST_RESET, DOMAIN _LOGGER = logging.getLogger(__name__) DEVICE_CLASS_OR_UNIT_STATISTICS = { - STATE_CLASS_TOTAL: { - DEVICE_CLASS_ENERGY: {"sum"}, - DEVICE_CLASS_GAS: {"sum"}, - DEVICE_CLASS_MONETARY: {"sum"}, - }, STATE_CLASS_MEASUREMENT: { DEVICE_CLASS_BATTERY: {"mean", "min", "max"}, DEVICE_CLASS_HUMIDITY: {"mean", "min", "max"}, @@ -65,7 +58,7 @@ DEVICE_CLASS_OR_UNIT_STATISTICS = { DEVICE_CLASS_PRESSURE: {"mean", "min", "max"}, DEVICE_CLASS_TEMPERATURE: {"mean", "min", "max"}, PERCENTAGE: {"mean", "min", "max"}, - # Deprecated, support will be removed in Home Assistant 2021.10 + # Deprecated, support will be removed in Home Assistant 2021.11 DEVICE_CLASS_ENERGY: {"sum"}, DEVICE_CLASS_GAS: {"sum"}, DEVICE_CLASS_MONETARY: {"sum"}, @@ -73,6 +66,7 @@ DEVICE_CLASS_OR_UNIT_STATISTICS = { STATE_CLASS_TOTAL_INCREASING: { DEVICE_CLASS_ENERGY: {"sum"}, DEVICE_CLASS_GAS: {"sum"}, + DEVICE_CLASS_MONETARY: {"sum"}, }, } @@ -279,13 +273,11 @@ def compile_statistics( stat["mean"] = _time_weighted_average(fstates, start, end) if "sum" in wanted_statistics: - last_reset = old_last_reset = None new_state = old_state = None _sum = 0 last_stats = statistics.get_last_statistics(hass, 1, entity_id) if entity_id in last_stats: # We have compiled history for this sensor before, use that as a starting point - last_reset = old_last_reset = last_stats[entity_id][0]["last_reset"] new_state = old_state = last_stats[entity_id][0]["state"] _sum = last_stats[entity_id][0]["sum"] @@ -299,13 +291,7 @@ def compile_statistics( continue reset = False - if ( - state_class != STATE_CLASS_TOTAL_INCREASING - and (last_reset := state.attributes.get("last_reset")) - != old_last_reset - ): - reset = True - elif old_state is None and last_reset is None: + if old_state is None: reset = True elif state_class == STATE_CLASS_TOTAL_INCREASING and ( old_state is None or (new_state is not None and fstate < new_state) @@ -318,21 +304,14 @@ def compile_statistics( _sum += new_state - old_state # ..and update the starting point new_state = fstate - old_last_reset = last_reset - # Force a new cycle for STATE_CLASS_TOTAL_INCREASING to start at 0 - if state_class == STATE_CLASS_TOTAL_INCREASING and old_state: - old_state = 0 + # Force a new cycle to start at 0 + if old_state is not None: + old_state = 0.0 else: old_state = new_state else: new_state = fstate - # Deprecated, will be removed in Home Assistant 2021.10 - if last_reset is None and state_class == STATE_CLASS_MEASUREMENT: - # No valid updates - result.pop(entity_id) - continue - if new_state is None or old_state is None: # No valid updates result.pop(entity_id) @@ -340,8 +319,6 @@ def compile_statistics( # Update the sum with the last state _sum += new_state - old_state - if last_reset is not None: - stat["last_reset"] = dt_util.parse_datetime(last_reset) stat["sum"] = _sum stat["state"] = new_state @@ -365,7 +342,11 @@ def list_statistic_ids(hass: HomeAssistant, statistic_type: str | None = None) - state = hass.states.get(entity_id) assert state - if "sum" in provided_statistics and ATTR_LAST_RESET not in state.attributes: + if ( + "sum" in provided_statistics + and ATTR_LAST_RESET not in state.attributes + and state.attributes.get(ATTR_STATE_CLASS) == STATE_CLASS_MEASUREMENT + ): continue native_unit = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) diff --git a/homeassistant/components/utility_meter/sensor.py b/homeassistant/components/utility_meter/sensor.py index 1ff201aaceb..84533efdcf5 100644 --- a/homeassistant/components/utility_meter/sensor.py +++ b/homeassistant/components/utility_meter/sensor.py @@ -5,11 +5,7 @@ import logging import voluptuous as vol -from homeassistant.components.sensor import ( - ATTR_LAST_RESET, - STATE_CLASS_MEASUREMENT, - SensorEntity, -) +from homeassistant.components.sensor import STATE_CLASS_MEASUREMENT, SensorEntity from homeassistant.const import ( ATTR_UNIT_OF_MEASUREMENT, CONF_NAME, @@ -58,6 +54,7 @@ ATTR_SOURCE_ID = "source" ATTR_STATUS = "status" ATTR_PERIOD = "meter_period" ATTR_LAST_PERIOD = "last_period" +ATTR_LAST_RESET = "last_reset" ATTR_TARIFF = "tariff" DEVICE_CLASS_MAP = { @@ -352,6 +349,7 @@ class UtilityMeterSensor(RestoreEntity, SensorEntity): ATTR_SOURCE_ID: self._sensor_source_id, ATTR_STATUS: PAUSED if self._collecting is None else COLLECTING, ATTR_LAST_PERIOD: self._last_period, + ATTR_LAST_RESET: self._last_reset.isoformat(), } if self._period is not None: state_attr[ATTR_PERIOD] = self._period @@ -363,8 +361,3 @@ class UtilityMeterSensor(RestoreEntity, SensorEntity): def icon(self): """Return the icon to use in the frontend, if any.""" return ICON - - @property - def last_reset(self): - """Return the time when the sensor was last reset.""" - return self._last_reset diff --git a/tests/components/energy/test_sensor.py b/tests/components/energy/test_sensor.py index 1e89c05fbd6..ea183ec52f4 100644 --- a/tests/components/energy/test_sensor.py +++ b/tests/components/energy/test_sensor.py @@ -7,9 +7,8 @@ import pytest from homeassistant.components.energy import data from homeassistant.components.sensor import ( - ATTR_LAST_RESET, ATTR_STATE_CLASS, - STATE_CLASS_MEASUREMENT, + STATE_CLASS_TOTAL_INCREASING, ) from homeassistant.components.sensor.recorder import compile_statistics from homeassistant.const import ( @@ -131,14 +130,13 @@ async def test_cost_sensor_price_entity( } now = dt_util.utcnow() - last_reset = dt_util.utc_from_timestamp(0).isoformat() # Optionally initialize dependent entities if initial_energy is not None: hass.states.async_set( usage_sensor_entity_id, initial_energy, - {"last_reset": last_reset, ATTR_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR}, + {ATTR_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR}, ) hass.states.async_set("sensor.energy_price", "1") @@ -148,9 +146,7 @@ async def test_cost_sensor_price_entity( state = hass.states.get(cost_sensor_entity_id) assert state.state == initial_cost assert state.attributes[ATTR_DEVICE_CLASS] == DEVICE_CLASS_MONETARY - if initial_cost != "unknown": - assert state.attributes[ATTR_LAST_RESET] == now.isoformat() - assert state.attributes[ATTR_STATE_CLASS] == STATE_CLASS_MEASUREMENT + assert state.attributes[ATTR_STATE_CLASS] == STATE_CLASS_TOTAL_INCREASING assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == "EUR" # Optional late setup of dependent entities @@ -160,7 +156,6 @@ async def test_cost_sensor_price_entity( usage_sensor_entity_id, "0", { - "last_reset": last_reset, ATTR_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR, }, ) @@ -169,8 +164,7 @@ async def test_cost_sensor_price_entity( state = hass.states.get(cost_sensor_entity_id) assert state.state == "0.0" assert state.attributes[ATTR_DEVICE_CLASS] == DEVICE_CLASS_MONETARY - assert state.attributes[ATTR_LAST_RESET] == now.isoformat() - assert state.attributes[ATTR_STATE_CLASS] == STATE_CLASS_MEASUREMENT + assert state.attributes[ATTR_STATE_CLASS] == STATE_CLASS_TOTAL_INCREASING assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == "EUR" # # Unique ID temp disabled @@ -182,7 +176,7 @@ async def test_cost_sensor_price_entity( hass.states.async_set( usage_sensor_entity_id, "10", - {"last_reset": last_reset, ATTR_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR}, + {ATTR_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR}, ) await hass.async_block_till_done() state = hass.states.get(cost_sensor_entity_id) @@ -206,7 +200,7 @@ async def test_cost_sensor_price_entity( hass.states.async_set( usage_sensor_entity_id, "14.5", - {"last_reset": last_reset, ATTR_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR}, + {ATTR_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR}, ) await hass.async_block_till_done() state = hass.states.get(cost_sensor_entity_id) @@ -218,32 +212,31 @@ async def test_cost_sensor_price_entity( assert cost_sensor_entity_id in statistics assert statistics[cost_sensor_entity_id]["stat"]["sum"] == 19.0 - # Energy sensor is reset, with start point at 4kWh - last_reset = (now + timedelta(seconds=1)).isoformat() + # Energy sensor is reset, with initial state at 4kWh, 0 kWh is used as zero-point hass.states.async_set( usage_sensor_entity_id, "4", - {"last_reset": last_reset, ATTR_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR}, + {ATTR_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR}, ) await hass.async_block_till_done() state = hass.states.get(cost_sensor_entity_id) - assert state.state == "0.0" # 0 EUR + (4-4) kWh * 2 EUR/kWh = 0 EUR + assert state.state == "8.0" # 0 EUR + (4-0) kWh * 2 EUR/kWh = 8 EUR # Energy use bumped to 10 kWh hass.states.async_set( usage_sensor_entity_id, "10", - {"last_reset": last_reset, ATTR_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR}, + {ATTR_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR}, ) await hass.async_block_till_done() state = hass.states.get(cost_sensor_entity_id) - assert state.state == "12.0" # 0 EUR + (10-4) kWh * 2 EUR/kWh = 12 EUR + assert state.state == "20.0" # 8 EUR + (10-4) kWh * 2 EUR/kWh = 20 EUR # Check generated statistics await async_wait_recording_done_without_instance(hass) statistics = await hass.loop.run_in_executor(None, _compile_statistics, hass) assert cost_sensor_entity_id in statistics - assert statistics[cost_sensor_entity_id]["stat"]["sum"] == 31.0 + assert statistics[cost_sensor_entity_id]["stat"]["sum"] == 39.0 async def test_cost_sensor_handle_wh(hass, hass_storage) -> None: @@ -272,12 +265,11 @@ async def test_cost_sensor_handle_wh(hass, hass_storage) -> None: } now = dt_util.utcnow() - last_reset = dt_util.utc_from_timestamp(0).isoformat() hass.states.async_set( "sensor.energy_consumption", 10000, - {"last_reset": last_reset, "unit_of_measurement": ENERGY_WATT_HOUR}, + {"unit_of_measurement": ENERGY_WATT_HOUR}, ) with patch("homeassistant.util.dt.utcnow", return_value=now): @@ -290,7 +282,7 @@ async def test_cost_sensor_handle_wh(hass, hass_storage) -> None: hass.states.async_set( "sensor.energy_consumption", 20000, - {"last_reset": last_reset, "unit_of_measurement": ENERGY_WATT_HOUR}, + {"unit_of_measurement": ENERGY_WATT_HOUR}, ) await hass.async_block_till_done() @@ -318,12 +310,11 @@ async def test_cost_sensor_handle_gas(hass, hass_storage) -> None: } now = dt_util.utcnow() - last_reset = dt_util.utc_from_timestamp(0).isoformat() hass.states.async_set( "sensor.gas_consumption", 100, - {"last_reset": last_reset, "unit_of_measurement": VOLUME_CUBIC_METERS}, + {"unit_of_measurement": VOLUME_CUBIC_METERS}, ) with patch("homeassistant.util.dt.utcnow", return_value=now): @@ -336,7 +327,7 @@ async def test_cost_sensor_handle_gas(hass, hass_storage) -> None: hass.states.async_set( "sensor.gas_consumption", 200, - {"last_reset": last_reset, "unit_of_measurement": VOLUME_CUBIC_METERS}, + {"unit_of_measurement": VOLUME_CUBIC_METERS}, ) await hass.async_block_till_done() diff --git a/tests/components/history/test_init.py b/tests/components/history/test_init.py index 7909d8f0239..8de44843626 100644 --- a/tests/components/history/test_init.py +++ b/tests/components/history/test_init.py @@ -911,7 +911,6 @@ async def test_statistics_during_period( "mean": approx(value), "min": approx(value), "max": approx(value), - "last_reset": None, "state": None, "sum": None, } diff --git a/tests/components/recorder/test_statistics.py b/tests/components/recorder/test_statistics.py index 0468cc26a23..83995b0c0ac 100644 --- a/tests/components/recorder/test_statistics.py +++ b/tests/components/recorder/test_statistics.py @@ -44,7 +44,6 @@ def test_compile_hourly_statistics(hass_recorder): "mean": approx(14.915254237288135), "min": approx(10.0), "max": approx(20.0), - "last_reset": None, "state": None, "sum": None, } @@ -54,7 +53,6 @@ def test_compile_hourly_statistics(hass_recorder): "mean": approx(20.0), "min": approx(20.0), "max": approx(20.0), - "last_reset": None, "state": None, "sum": None, } @@ -127,7 +125,6 @@ def test_rename_entity(hass_recorder): "mean": approx(14.915254237288135), "min": approx(10.0), "max": approx(20.0), - "last_reset": None, "state": None, "sum": None, } diff --git a/tests/components/sensor/test_init.py b/tests/components/sensor/test_init.py index 793bcaf4f99..5ff2cad9edc 100644 --- a/tests/components/sensor/test_init.py +++ b/tests/components/sensor/test_init.py @@ -44,9 +44,8 @@ async def test_deprecated_last_reset(hass, caplog, enable_custom_integrations): assert ( "Entity sensor.test () " - "with state_class measurement has set last_reset. Setting last_reset for " - "entities with state_class other than 'total' is deprecated and will be " - "removed from Home Assistant Core 2021.10. Please update your configuration if " - "state_class is manually configured, otherwise report it to the custom " - "component author." + "with state_class measurement has set last_reset. Setting last_reset is " + "deprecated and will be unsupported from Home Assistant Core 2021.11. Please " + "update your configuration if state_class is manually configured, otherwise " + "report it to the custom component author." ) in caplog.text diff --git a/tests/components/sensor/test_recorder.py b/tests/components/sensor/test_recorder.py index d4dee872823..3a2572f8141 100644 --- a/tests/components/sensor/test_recorder.py +++ b/tests/components/sensor/test_recorder.py @@ -95,7 +95,6 @@ def test_compile_hourly_statistics( "mean": approx(mean), "min": approx(min), "max": approx(max), - "last_reset": None, "state": None, "sum": None, } @@ -145,7 +144,6 @@ def test_compile_hourly_statistics_unsupported(hass_recorder, caplog, attributes "mean": approx(16.440677966101696), "min": approx(10.0), "max": approx(30.0), - "last_reset": None, "state": None, "sum": None, } @@ -154,7 +152,6 @@ def test_compile_hourly_statistics_unsupported(hass_recorder, caplog, attributes assert "Error while processing event StatisticsTask" not in caplog.text -@pytest.mark.parametrize("state_class", ["measurement", "total"]) @pytest.mark.parametrize( "device_class,unit,native_unit,factor", [ @@ -167,7 +164,7 @@ def test_compile_hourly_statistics_unsupported(hass_recorder, caplog, attributes ], ) def test_compile_hourly_sum_statistics_amount( - hass_recorder, caplog, state_class, device_class, unit, native_unit, factor + hass_recorder, caplog, device_class, unit, native_unit, factor ): """Test compiling hourly statistics.""" zero = dt_util.utcnow() @@ -176,7 +173,7 @@ def test_compile_hourly_sum_statistics_amount( setup_component(hass, "sensor", {}) attributes = { "device_class": device_class, - "state_class": state_class, + "state_class": "measurement", "unit_of_measurement": unit, "last_reset": None, } @@ -209,7 +206,6 @@ def test_compile_hourly_sum_statistics_amount( "max": None, "mean": None, "min": None, - "last_reset": process_timestamp_to_utc_isoformat(zero), "state": approx(factor * seq[2]), "sum": approx(factor * 10.0), }, @@ -219,89 +215,6 @@ def test_compile_hourly_sum_statistics_amount( "max": None, "mean": None, "min": None, - "last_reset": process_timestamp_to_utc_isoformat(four), - "state": approx(factor * seq[5]), - "sum": approx(factor * 10.0), - }, - { - "statistic_id": "sensor.test1", - "start": process_timestamp_to_utc_isoformat(zero + timedelta(hours=2)), - "max": None, - "mean": None, - "min": None, - "last_reset": process_timestamp_to_utc_isoformat(four), - "state": approx(factor * seq[8]), - "sum": approx(factor * 40.0), - }, - ] - } - assert "Error while processing event StatisticsTask" not in caplog.text - - -@pytest.mark.parametrize( - "device_class,unit,native_unit,factor", - [ - ("energy", "kWh", "kWh", 1), - ("energy", "Wh", "kWh", 1 / 1000), - ("monetary", "EUR", "EUR", 1), - ("monetary", "SEK", "SEK", 1), - ("gas", "m³", "m³", 1), - ("gas", "ft³", "m³", 0.0283168466), - ], -) -def test_compile_hourly_sum_statistics_total_no_reset( - hass_recorder, caplog, device_class, unit, native_unit, factor -): - """Test compiling hourly statistics.""" - zero = dt_util.utcnow() - hass = hass_recorder() - recorder = hass.data[DATA_INSTANCE] - setup_component(hass, "sensor", {}) - attributes = { - "device_class": device_class, - "state_class": "total", - "unit_of_measurement": unit, - } - seq = [10, 15, 20, 10, 30, 40, 50, 60, 70] - - four, eight, states = record_meter_states( - hass, zero, "sensor.test1", attributes, seq - ) - hist = history.get_significant_states( - hass, zero - timedelta.resolution, eight + timedelta.resolution - ) - assert dict(states)["sensor.test1"] == dict(hist)["sensor.test1"] - - recorder.do_adhoc_statistics(period="hourly", start=zero) - wait_recording_done(hass) - recorder.do_adhoc_statistics(period="hourly", start=zero + timedelta(hours=1)) - wait_recording_done(hass) - recorder.do_adhoc_statistics(period="hourly", start=zero + timedelta(hours=2)) - wait_recording_done(hass) - statistic_ids = list_statistic_ids(hass) - assert statistic_ids == [ - {"statistic_id": "sensor.test1", "unit_of_measurement": native_unit} - ] - stats = statistics_during_period(hass, zero) - assert stats == { - "sensor.test1": [ - { - "statistic_id": "sensor.test1", - "start": process_timestamp_to_utc_isoformat(zero), - "max": None, - "mean": None, - "min": None, - "last_reset": None, - "state": approx(factor * seq[2]), - "sum": approx(factor * 10.0), - }, - { - "statistic_id": "sensor.test1", - "start": process_timestamp_to_utc_isoformat(zero + timedelta(hours=1)), - "max": None, - "mean": None, - "min": None, - "last_reset": None, "state": approx(factor * seq[5]), "sum": approx(factor * 30.0), }, @@ -311,7 +224,6 @@ def test_compile_hourly_sum_statistics_total_no_reset( "max": None, "mean": None, "min": None, - "last_reset": None, "state": approx(factor * seq[8]), "sum": approx(factor * 60.0), }, @@ -371,7 +283,6 @@ def test_compile_hourly_sum_statistics_total_increasing( "max": None, "mean": None, "min": None, - "last_reset": None, "state": approx(factor * seq[2]), "sum": approx(factor * 10.0), }, @@ -381,7 +292,6 @@ def test_compile_hourly_sum_statistics_total_increasing( "max": None, "mean": None, "min": None, - "last_reset": None, "state": approx(factor * seq[5]), "sum": approx(factor * 50.0), }, @@ -391,7 +301,6 @@ def test_compile_hourly_sum_statistics_total_increasing( "max": None, "mean": None, "min": None, - "last_reset": None, "state": approx(factor * seq[8]), "sum": approx(factor * 80.0), }, @@ -458,7 +367,6 @@ def test_compile_hourly_energy_statistics_unsupported(hass_recorder, caplog): "max": None, "mean": None, "min": None, - "last_reset": process_timestamp_to_utc_isoformat(zero), "state": approx(20.0), "sum": approx(10.0), }, @@ -468,9 +376,8 @@ def test_compile_hourly_energy_statistics_unsupported(hass_recorder, caplog): "max": None, "mean": None, "min": None, - "last_reset": process_timestamp_to_utc_isoformat(four), "state": approx(40.0), - "sum": approx(10.0), + "sum": approx(30.0), }, { "statistic_id": "sensor.test1", @@ -478,9 +385,8 @@ def test_compile_hourly_energy_statistics_unsupported(hass_recorder, caplog): "max": None, "mean": None, "min": None, - "last_reset": process_timestamp_to_utc_isoformat(four), "state": approx(70.0), - "sum": approx(40.0), + "sum": approx(60.0), }, ] } @@ -541,7 +447,6 @@ def test_compile_hourly_energy_statistics_multiple(hass_recorder, caplog): "max": None, "mean": None, "min": None, - "last_reset": process_timestamp_to_utc_isoformat(zero), "state": approx(20.0), "sum": approx(10.0), }, @@ -551,9 +456,8 @@ def test_compile_hourly_energy_statistics_multiple(hass_recorder, caplog): "max": None, "mean": None, "min": None, - "last_reset": process_timestamp_to_utc_isoformat(four), "state": approx(40.0), - "sum": approx(10.0), + "sum": approx(30.0), }, { "statistic_id": "sensor.test1", @@ -561,9 +465,8 @@ def test_compile_hourly_energy_statistics_multiple(hass_recorder, caplog): "max": None, "mean": None, "min": None, - "last_reset": process_timestamp_to_utc_isoformat(four), "state": approx(70.0), - "sum": approx(40.0), + "sum": approx(60.0), }, ], "sensor.test2": [ @@ -573,7 +476,6 @@ def test_compile_hourly_energy_statistics_multiple(hass_recorder, caplog): "max": None, "mean": None, "min": None, - "last_reset": process_timestamp_to_utc_isoformat(zero), "state": approx(130.0), "sum": approx(20.0), }, @@ -583,9 +485,8 @@ def test_compile_hourly_energy_statistics_multiple(hass_recorder, caplog): "max": None, "mean": None, "min": None, - "last_reset": process_timestamp_to_utc_isoformat(four), "state": approx(45.0), - "sum": approx(-95.0), + "sum": approx(-65.0), }, { "statistic_id": "sensor.test2", @@ -593,9 +494,8 @@ def test_compile_hourly_energy_statistics_multiple(hass_recorder, caplog): "max": None, "mean": None, "min": None, - "last_reset": process_timestamp_to_utc_isoformat(four), "state": approx(75.0), - "sum": approx(-65.0), + "sum": approx(-35.0), }, ], "sensor.test3": [ @@ -605,7 +505,6 @@ def test_compile_hourly_energy_statistics_multiple(hass_recorder, caplog): "max": None, "mean": None, "min": None, - "last_reset": process_timestamp_to_utc_isoformat(zero), "state": approx(5.0 / 1000), "sum": approx(5.0 / 1000), }, @@ -615,9 +514,8 @@ def test_compile_hourly_energy_statistics_multiple(hass_recorder, caplog): "max": None, "mean": None, "min": None, - "last_reset": process_timestamp_to_utc_isoformat(four), "state": approx(50.0 / 1000), - "sum": approx(30.0 / 1000), + "sum": approx(50.0 / 1000), }, { "statistic_id": "sensor.test3", @@ -625,9 +523,8 @@ def test_compile_hourly_energy_statistics_multiple(hass_recorder, caplog): "max": None, "mean": None, "min": None, - "last_reset": process_timestamp_to_utc_isoformat(four), "state": approx(90.0 / 1000), - "sum": approx(70.0 / 1000), + "sum": approx(90.0 / 1000), }, ], } @@ -678,7 +575,6 @@ def test_compile_hourly_statistics_unchanged( "mean": approx(value), "min": approx(value), "max": approx(value), - "last_reset": None, "state": None, "sum": None, } @@ -710,7 +606,6 @@ def test_compile_hourly_statistics_partially_unavailable(hass_recorder, caplog): "mean": approx(21.1864406779661), "min": approx(10.0), "max": approx(25.0), - "last_reset": None, "state": None, "sum": None, } @@ -767,7 +662,6 @@ def test_compile_hourly_statistics_unavailable( "mean": approx(value), "min": approx(value), "max": approx(value), - "last_reset": None, "state": None, "sum": None, }