Home Assistant Unofficial Reference 2024.12.1
calendar.py
Go to the documentation of this file.
1 """Holiday Calendar."""
2 
3 from __future__ import annotations
4 
5 from datetime import datetime, timedelta
6 
7 from holidays import HolidayBase, country_holidays
8 
9 from homeassistant.components.calendar import CalendarEntity, CalendarEvent
10 from homeassistant.config_entries import ConfigEntry
11 from homeassistant.const import CONF_COUNTRY
12 from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
13 from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
14 from homeassistant.helpers.entity_platform import AddEntitiesCallback
15 from homeassistant.helpers.event import async_track_point_in_utc_time
16 from homeassistant.util import dt as dt_util
17 
18 from .const import CONF_PROVINCE, DOMAIN
19 
20 
22  country: str, province: str | None, language: str
23 ) -> tuple[HolidayBase, str]:
24  """Get the object for the requested country and year."""
25  obj_holidays = country_holidays(
26  country,
27  subdiv=province,
28  years={dt_util.now().year, dt_util.now().year + 1},
29  language=language,
30  )
31  if language == "en":
32  for lang in obj_holidays.supported_languages:
33  if lang.startswith("en"):
34  obj_holidays = country_holidays(
35  country,
36  subdiv=province,
37  years={dt_util.now().year, dt_util.now().year + 1},
38  language=lang,
39  )
40  language = lang
41  break
42  if (
43  obj_holidays.supported_languages
44  and language not in obj_holidays.supported_languages
45  and (default_language := obj_holidays.default_language)
46  ):
47  obj_holidays = country_holidays(
48  country,
49  subdiv=province,
50  years={dt_util.now().year, dt_util.now().year + 1},
51  language=default_language,
52  )
53  language = default_language
54 
55  return (obj_holidays, language)
56 
57 
59  hass: HomeAssistant,
60  config_entry: ConfigEntry,
61  async_add_entities: AddEntitiesCallback,
62 ) -> None:
63  """Set up the Holiday Calendar config entry."""
64  country: str = config_entry.data[CONF_COUNTRY]
65  province: str | None = config_entry.data.get(CONF_PROVINCE)
66  language = hass.config.language
67 
68  obj_holidays, language = await hass.async_add_executor_job(
69  _get_obj_holidays_and_language, country, province, language
70  )
71 
73  [
75  config_entry.title,
76  country,
77  province,
78  language,
79  obj_holidays,
80  config_entry.entry_id,
81  )
82  ],
83  True,
84  )
85 
86 
88  """Representation of a Holiday Calendar element."""
89 
90  _attr_has_entity_name = True
91  _attr_name = None
92  _attr_event: CalendarEvent | None = None
93  _attr_should_poll = False
94  unsub: CALLBACK_TYPE | None = None
95 
96  def __init__(
97  self,
98  name: str,
99  country: str,
100  province: str | None,
101  language: str,
102  obj_holidays: HolidayBase,
103  unique_id: str,
104  ) -> None:
105  """Initialize HolidayCalendarEntity."""
106  self._country_country = country
107  self._province_province = province
108  self._location_location = name
109  self._language_language = language
110  self._attr_unique_id_attr_unique_id = unique_id
111  self._attr_device_info_attr_device_info = DeviceInfo(
112  identifiers={(DOMAIN, unique_id)},
113  entry_type=DeviceEntryType.SERVICE,
114  name=name,
115  )
116  self._obj_holidays_obj_holidays = obj_holidays
117 
118  def get_next_interval(self, now: datetime) -> datetime:
119  """Compute next time an update should occur."""
120  tomorrow = dt_util.as_local(now) + timedelta(days=1)
121  return dt_util.start_of_local_day(tomorrow)
122 
124  """Update state and setup listener for next interval."""
125  now = dt_util.now()
126  self._attr_event_attr_event = self.update_eventupdate_event(now)
128  self.hasshass, self.point_in_time_listenerpoint_in_time_listener, self.get_next_intervalget_next_interval(now)
129  )
130 
131  @callback
132  def point_in_time_listener(self, time_date: datetime) -> None:
133  """Get the latest data and update state."""
134  self._update_state_and_setup_listener_update_state_and_setup_listener()
135  self.async_write_ha_stateasync_write_ha_stateasync_write_ha_state()
136 
137  async def async_added_to_hass(self) -> None:
138  """Set up first update."""
139  self._update_state_and_setup_listener_update_state_and_setup_listener()
140 
141  def update_event(self, now: datetime) -> CalendarEvent | None:
142  """Return the next upcoming event."""
143  next_holiday = None
144  for holiday_date, holiday_name in sorted(
145  self._obj_holidays_obj_holidays.items(), key=lambda x: x[0]
146  ):
147  if holiday_date >= now.date():
148  next_holiday = (holiday_date, holiday_name)
149  break
150 
151  if next_holiday is None:
152  return None
153 
154  return CalendarEvent(
155  summary=next_holiday[1],
156  start=next_holiday[0],
157  end=next_holiday[0],
158  location=self._location_location,
159  )
160 
161  @property
162  def event(self) -> CalendarEvent | None:
163  """Return the next upcoming event."""
164  return self._attr_event_attr_event
165 
166  async def async_get_events(
167  self, hass: HomeAssistant, start_date: datetime, end_date: datetime
168  ) -> list[CalendarEvent]:
169  """Get all events in a specific time frame."""
170  obj_holidays = country_holidays(
171  self._country_country,
172  subdiv=self._province_province,
173  years=list({start_date.year, end_date.year}),
174  language=self._language_language,
175  )
176 
177  event_list: list[CalendarEvent] = []
178 
179  for holiday_date, holiday_name in obj_holidays.items():
180  if start_date.date() <= holiday_date <= end_date.date():
181  event = CalendarEvent(
182  summary=holiday_name,
183  start=holiday_date,
184  end=holiday_date,
185  location=self._location_location,
186  )
187  event_list.append(event)
188 
189  return event_list
CalendarEvent|None update_event(self, datetime now)
Definition: calendar.py:141
None __init__(self, str name, str country, str|None province, str language, HolidayBase obj_holidays, str unique_id)
Definition: calendar.py:104
list[CalendarEvent] async_get_events(self, HomeAssistant hass, datetime start_date, datetime end_date)
Definition: calendar.py:168
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Definition: calendar.py:62
tuple[HolidayBase, str] _get_obj_holidays_and_language(str country, str|None province, str language)
Definition: calendar.py:23
CALLBACK_TYPE async_track_point_in_utc_time(HomeAssistant hass, HassJob[[datetime], Coroutine[Any, Any, None]|None]|Callable[[datetime], Coroutine[Any, Any, None]|None] action, datetime point_in_time)
Definition: event.py:1542