Skip to content

Commit 2a737f1

Browse files
committed
Refresh rate sensors on time changes
1 parent 6adf4d6 commit 2a737f1

3 files changed

Lines changed: 63 additions & 2 deletions

File tree

custom_components/dte_rates/sensor.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@
55
from homeassistant.components.sensor import SensorDeviceClass, SensorEntity, SensorStateClass
66
from homeassistant.components import persistent_notification
77
from homeassistant.config_entries import ConfigEntry
8-
from homeassistant.core import HomeAssistant
8+
from homeassistant.core import HomeAssistant, callback
99
from homeassistant.helpers.device_registry import DeviceEntryType
1010
from homeassistant.helpers.entity_platform import AddEntitiesCallback
11+
from homeassistant.helpers.event import async_track_time_interval
1112
from homeassistant.helpers.update_coordinator import CoordinatorEntity
1213
from homeassistant.util import dt as dt_util
14+
from datetime import timedelta
1315

1416
from .const import (
1517
ATTR_CARD_EFFECTIVE_DATE,
@@ -66,6 +68,18 @@ def __init__(self, coordinator, entry: ConfigEntry) -> None:
6668
self._entry = entry
6769
self._notification_id = f"dte_rates_missing_rate_{entry.entry_id}"
6870

71+
async def async_added_to_hass(self) -> None:
72+
remove_listener = async_track_time_interval(
73+
self.hass,
74+
self._handle_time_interval,
75+
timedelta(minutes=1),
76+
)
77+
self.async_on_remove(remove_listener)
78+
79+
@callback
80+
def _handle_time_interval(self, _now) -> None:
81+
self.async_write_ha_state()
82+
6983
def _selected_rate(self) -> RatePlan | None:
7084
selected = self._entry.data[CONF_SELECTED_RATE]
7185
return self.coordinator.data.rates.get(selected)

tests/conftest.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,15 @@ class CoordinatorEntity:
6464
def __init__(self, coordinator):
6565
self.coordinator = coordinator
6666

67+
async def async_added_to_hass(self):
68+
return None
69+
70+
def async_on_remove(self, _remove_callback):
71+
return None
72+
73+
def async_write_ha_state(self):
74+
return None
75+
6776
class SensorEntity:
6877
@property
6978
def native_unit_of_measurement(self):
@@ -77,6 +86,9 @@ class SensorDeviceClass:
7786
class HomeAssistant:
7887
pass
7988

89+
def callback(func):
90+
return func
91+
8092
class DeviceEntryType:
8193
SERVICE = "service"
8294

@@ -99,7 +111,7 @@ def __init__(self, url_path, path, cache_headers=True):
99111
FlowResult=FlowResult,
100112
),
101113
"homeassistant.data_entry_flow": _make_module("homeassistant.data_entry_flow", FlowResult=FlowResult),
102-
"homeassistant.core": _make_module("homeassistant.core", HomeAssistant=HomeAssistant),
114+
"homeassistant.core": _make_module("homeassistant.core", HomeAssistant=HomeAssistant, callback=callback),
103115
"homeassistant.helpers": _make_module("homeassistant.helpers"),
104116
"homeassistant.helpers.update_coordinator": _make_module(
105117
"homeassistant.helpers.update_coordinator",
@@ -108,6 +120,10 @@ def __init__(self, url_path, path, cache_headers=True):
108120
CoordinatorEntity=CoordinatorEntity,
109121
),
110122
"homeassistant.helpers.entity_platform": _make_module("homeassistant.helpers.entity_platform", AddEntitiesCallback=MagicMock()),
123+
"homeassistant.helpers.event": _make_module(
124+
"homeassistant.helpers.event",
125+
async_track_time_interval=MagicMock(return_value=lambda: None),
126+
),
111127
"homeassistant.helpers.aiohttp_client": _make_module("homeassistant.helpers.aiohttp_client", async_get_clientsession=MagicMock()),
112128
"homeassistant.helpers.device_registry": _make_module("homeassistant.helpers.device_registry", DeviceEntryType=DeviceEntryType),
113129
"homeassistant.components": _make_module("homeassistant.components"),

tests/test_sensor.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from decimal import Decimal
55
from types import SimpleNamespace
66
from unittest.mock import MagicMock
7+
import pytest
78

89
from homeassistant.components import persistent_notification
910
from custom_components.dte_rates.const import CONF_NET_METERING, CONF_SELECTED_RATE
@@ -206,3 +207,33 @@ def test_available_rate_dismisses_existing_notification(monkeypatch):
206207

207208
create_mock.assert_not_called()
208209
dismiss_mock.assert_called_once()
210+
211+
212+
@pytest.mark.asyncio
213+
async def test_sensor_registers_time_interval_refresh(monkeypatch):
214+
monkeypatch.setattr("custom_components.dte_rates.sensor.dt_util.now", lambda: datetime(2026, 3, 1, 12, 0))
215+
track_mock = MagicMock(return_value=lambda: None)
216+
monkeypatch.setattr("custom_components.dte_rates.sensor.async_track_time_interval", track_mock)
217+
218+
coordinator = _coordinator_with_rate()
219+
entry = SimpleNamespace(entry_id="entry_11", data={CONF_SELECTED_RATE: "D1.11", CONF_NET_METERING: False})
220+
sensor = DteImportRateSensor(coordinator, entry)
221+
sensor.hass = SimpleNamespace()
222+
sensor.async_on_remove = MagicMock()
223+
224+
await sensor.async_added_to_hass()
225+
226+
track_mock.assert_called_once()
227+
sensor.async_on_remove.assert_called_once()
228+
229+
230+
def test_time_interval_callback_writes_state(monkeypatch):
231+
monkeypatch.setattr("custom_components.dte_rates.sensor.dt_util.now", lambda: datetime(2026, 3, 1, 12, 0))
232+
coordinator = _coordinator_with_rate()
233+
entry = SimpleNamespace(entry_id="entry_12", data={CONF_SELECTED_RATE: "D1.11", CONF_NET_METERING: False})
234+
sensor = DteImportRateSensor(coordinator, entry)
235+
sensor.async_write_ha_state = MagicMock()
236+
237+
sensor._handle_time_interval(None)
238+
239+
sensor.async_write_ha_state.assert_called_once()

0 commit comments

Comments
 (0)