mirror of
https://github.com/home-assistant/core.git
synced 2026-08-30 02:35:19 -05:00
Fix utility meter next_reset shifting forward on entity rename (#170957)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
9a1fd913bf
commit
ff7964bcfc
@@ -406,11 +406,12 @@ class UtilityMeterSensor(RestoreSensor):
|
||||
self._current_tz = None
|
||||
self._config_scheduler()
|
||||
|
||||
def _config_scheduler(self):
|
||||
def _config_scheduler(self, start_time: datetime | None = None) -> None:
|
||||
self.scheduler = (
|
||||
CronSim(
|
||||
self._cron_pattern,
|
||||
dt_util.now(
|
||||
start_time
|
||||
or dt_util.now(
|
||||
dt_util.get_default_time_zone()
|
||||
), # we need timezone for DST purposes (see issue #102984)
|
||||
)
|
||||
@@ -608,8 +609,6 @@ class UtilityMeterSensor(RestoreSensor):
|
||||
# and we need to reconfigure the scheduler
|
||||
self._current_tz = self.hass.config.time_zone
|
||||
|
||||
await self._program_reset()
|
||||
|
||||
self.async_on_remove(
|
||||
async_dispatcher_connect(
|
||||
self.hass, SIGNAL_RESET_METER, self.async_reset_meter
|
||||
@@ -628,6 +627,13 @@ class UtilityMeterSensor(RestoreSensor):
|
||||
if last_sensor_data.status == COLLECTING:
|
||||
# Null lambda to allow cancelling the collection on tariff change
|
||||
self._collecting = lambda: None
|
||||
# Reconfigure the scheduler from the restored last_reset so that
|
||||
# next_reset is not shifted forward on entity restore/rename.
|
||||
self._config_scheduler(
|
||||
dt_util.as_local(self._last_reset) if self._last_reset else None
|
||||
)
|
||||
|
||||
await self._program_reset()
|
||||
|
||||
@callback
|
||||
def async_source_tracking(event):
|
||||
|
||||
@@ -1799,6 +1799,63 @@ async def test_tz_changes(hass: HomeAssistant) -> None:
|
||||
assert state.attributes.get("next_reset") != "2024-10-28T00:00:00+01:00"
|
||||
|
||||
|
||||
async def test_next_reset_not_shifted_on_restore(hass: HomeAssistant) -> None:
|
||||
"""Test that a missed reset fires on restore after entity rename.
|
||||
|
||||
When an entity is restored (e.g. after rename) and a reset was missed,
|
||||
the scheduler should catch up from last_reset rather than starting from
|
||||
now(), which would skip the missed reset entirely.
|
||||
"""
|
||||
last_reset = "2024-10-27T00:00:00+00:00"
|
||||
|
||||
mock_restore_cache_with_extra_data(
|
||||
hass,
|
||||
[
|
||||
(
|
||||
State(
|
||||
"sensor.energy_bill",
|
||||
"3",
|
||||
attributes={
|
||||
ATTR_STATUS: COLLECTING,
|
||||
ATTR_LAST_RESET: last_reset,
|
||||
ATTR_UNIT_OF_MEASUREMENT: UnitOfEnergy.KILO_WATT_HOUR,
|
||||
},
|
||||
),
|
||||
{
|
||||
"native_value": {
|
||||
"__type": "<class 'decimal.Decimal'>",
|
||||
"decimal_str": "3",
|
||||
},
|
||||
"native_unit_of_measurement": "kWh",
|
||||
"last_reset": last_reset,
|
||||
"last_period": "0",
|
||||
"last_valid_state": "3",
|
||||
"status": "collecting",
|
||||
"input_device_class": "energy",
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
# Restore at noon on Oct 28 - the Oct 28 midnight reset was missed
|
||||
now = dt_util.parse_datetime("2024-10-28T12:00:00+00:00")
|
||||
with freeze_time(now):
|
||||
assert await async_setup_component(hass, DOMAIN, gen_config("daily"))
|
||||
await hass.async_block_till_done()
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("sensor.energy_bill")
|
||||
assert state is not None
|
||||
# The missed reset should have fired as a catch-up, updating last_reset
|
||||
# and recording the previous period value. Without the fix, last_reset
|
||||
# stays at the original value because the scheduler starts from now()
|
||||
# and skips the missed period entirely.
|
||||
assert state.attributes.get("last_reset") != last_reset
|
||||
assert state.attributes.get("last_period") == "3"
|
||||
assert state.state == "0"
|
||||
|
||||
|
||||
async def test_self_reset_daily(hass: HomeAssistant) -> None:
|
||||
"""Test daily reset of meter."""
|
||||
await _test_self_reset(
|
||||
|
||||
Reference in New Issue
Block a user