diff --git a/homeassistant/components/holiday/calendar.py b/homeassistant/components/holiday/calendar.py index 57503b340d9..83988502d18 100644 --- a/homeassistant/components/holiday/calendar.py +++ b/homeassistant/components/holiday/calendar.py @@ -2,16 +2,17 @@ from __future__ import annotations -from datetime import datetime +from datetime import datetime, timedelta from holidays import HolidayBase, country_holidays from homeassistant.components.calendar import CalendarEntity, CalendarEvent from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_COUNTRY -from homeassistant.core import HomeAssistant +from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.event import async_track_point_in_utc_time from homeassistant.util import dt as dt_util from .const import CONF_PROVINCE, DOMAIN @@ -77,6 +78,9 @@ class HolidayCalendarEntity(CalendarEntity): _attr_has_entity_name = True _attr_name = None + _attr_event: CalendarEvent | None = None + _attr_should_poll = False + unsub: CALLBACK_TYPE | None = None def __init__( self, @@ -100,14 +104,36 @@ class HolidayCalendarEntity(CalendarEntity): ) self._obj_holidays = obj_holidays - @property - def event(self) -> CalendarEvent | None: + def get_next_interval(self, now: datetime) -> datetime: + """Compute next time an update should occur.""" + tomorrow = dt_util.as_local(now) + timedelta(days=1) + return dt_util.start_of_local_day(tomorrow) + + def _update_state_and_setup_listener(self) -> None: + """Update state and setup listener for next interval.""" + now = dt_util.utcnow() + self._attr_event = self.update_event(now) + self.unsub = async_track_point_in_utc_time( + self.hass, self.point_in_time_listener, self.get_next_interval(now) + ) + + @callback + def point_in_time_listener(self, time_date: datetime) -> None: + """Get the latest data and update state.""" + self._update_state_and_setup_listener() + self.async_write_ha_state() + + async def async_added_to_hass(self) -> None: + """Set up first update.""" + self._update_state_and_setup_listener() + + def update_event(self, now: datetime) -> CalendarEvent | None: """Return the next upcoming event.""" next_holiday = None for holiday_date, holiday_name in sorted( self._obj_holidays.items(), key=lambda x: x[0] ): - if holiday_date >= dt_util.now().date(): + if holiday_date >= now.date(): next_holiday = (holiday_date, holiday_name) break @@ -121,6 +147,11 @@ class HolidayCalendarEntity(CalendarEntity): location=self._location, ) + @property + def event(self) -> CalendarEvent | None: + """Return the next upcoming event.""" + return self._attr_event + async def async_get_events( self, hass: HomeAssistant, start_date: datetime, end_date: datetime ) -> list[CalendarEvent]: