diff --git a/homeassistant/components/goodwe/sensor.py b/homeassistant/components/goodwe/sensor.py index 6dcdc6e8cb1..bf01f449724 100644 --- a/homeassistant/components/goodwe/sensor.py +++ b/homeassistant/components/goodwe/sensor.py @@ -3,6 +3,7 @@ from __future__ import annotations from collections.abc import Callable from dataclasses import dataclass +from datetime import timedelta from typing import Any, cast from goodwe import Inverter, Sensor, SensorKind @@ -23,19 +24,28 @@ from homeassistant.const import ( POWER_WATT, TEMP_CELSIUS, ) -from homeassistant.core import HomeAssistant +from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity import DeviceInfo, EntityCategory from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.event import async_track_point_in_time from homeassistant.helpers.update_coordinator import ( CoordinatorEntity, DataUpdateCoordinator, ) +import homeassistant.util.dt as dt_util from .const import DOMAIN, KEY_COORDINATOR, KEY_DEVICE_INFO, KEY_INVERTER # Sensor name of battery SoC BATTERY_SOC = "battery_soc" +# Sensors that are reset to 0 at midnight. +# The inverter is only powered by the solar panels and not mains power, so it goes dead when the sun goes down. +# The "_day" sensors are reset to 0 when the inverter wakes up in the morning when the sun comes up and power to the inverter is restored. +# This makes sure daily values are reset at midnight instead of at sunrise. +# When the inverter has a battery connected, HomeAssistant will not reset the values but let the inverter reset them by looking at the unavailable state of the inverter. +DAILY_RESET = ["e_day", "e_load_day"] + _MAIN_SENSORS = ( "ppv", "house_consumption", @@ -167,6 +177,7 @@ class InverterSensor(CoordinatorEntity, SensorEntity): self._attr_device_class = SensorDeviceClass.BATTERY self._sensor = sensor self._previous_value = None + self._stop_reset = None @property def native_value(self): @@ -190,3 +201,32 @@ class InverterSensor(CoordinatorEntity, SensorEntity): return cast(GoodweSensorEntityDescription, self.entity_description).available( self ) + + @callback + def async_reset(self, now): + """Reset the value back to 0 at midnight.""" + if not self.coordinator.last_update_success: + self._previous_value = 0 + self.coordinator.data[self._sensor.id_] = 0 + self.async_write_ha_state() + next_midnight = dt_util.start_of_local_day(dt_util.utcnow() + timedelta(days=1)) + self._stop_reset = async_track_point_in_time( + self.hass, self.async_reset, next_midnight + ) + + async def async_added_to_hass(self): + """Schedule reset task at midnight.""" + if self._sensor.id_ in DAILY_RESET: + next_midnight = dt_util.start_of_local_day( + dt_util.utcnow() + timedelta(days=1) + ) + self._stop_reset = async_track_point_in_time( + self.hass, self.async_reset, next_midnight + ) + await super().async_added_to_hass() + + async def async_will_remove_from_hass(self): + """Remove reset task at midnight.""" + if self._sensor.id_ in DAILY_RESET and self._stop_reset is not None: + self._stop_reset() + await super().async_will_remove_from_hass()