22
33from __future__ import annotations
44
5- from datetime import datetime , timedelta
5+ from asyncio import TimerHandle
6+ from datetime import timedelta
67
78from homeassistant .core import Event , HomeAssistant , callback
89from homeassistant .const import EVENT_STATE_CHANGED
10+ from homeassistant .util .dt import utcnow
911from homeassistant .helpers .event import async_track_entity_registry_updated_event
1012from homeassistant .config_entries import ConfigEntry
1113from homeassistant .helpers .entity_platform import AddConfigEntryEntitiesCallback
@@ -88,21 +90,23 @@ def __init__(
8890
8991 self ._attr_is_on = False
9092 self ._attr_extra_state_attributes = {}
91- self ._call_later_handle = None
93+ self ._call_later_handle : TimerHandle | None = None
9294
9395 async def async_added_to_hass (self ) -> None :
9496 """Handle added to Hass."""
9597 await super ().async_added_to_hass ()
9698
9799 # Add state listener for the calendar entity
98100 self .async_on_remove (
99- self ._hass .bus .async_listen (EVENT_STATE_CHANGED , self ._state_changed )
101+ self ._hass .bus .async_listen (EVENT_STATE_CHANGED , self ._state_changed ) # type: ignore[arg-type]
100102 )
101103
102104 # Track entity registry updates to detect when entity is disabled/enabled
103105 self .async_on_remove (
104106 async_track_entity_registry_updated_event (
105- self ._hass , self .entity_id , self ._entity_registry_updated
107+ self ._hass ,
108+ self .entity_id ,
109+ self ._entity_registry_updated , # type: ignore[arg-type]
106110 )
107111 )
108112
@@ -115,14 +119,6 @@ def _entity_registry_updated(self, event: Event) -> None:
115119 if not self .enabled :
116120 self ._cancel_call_later ()
117121
118- async def async_entity_registry_updated (self ) -> None :
119- """Handle entity registry update."""
120- await super ().async_entity_registry_updated ()
121-
122- # Cancel any pending timers if the entity is disabled
123- if not self .enabled :
124- self ._cancel_call_later ()
125-
126122 def _cancel_call_later (self ) -> None :
127123 """Cancel any pending call_later."""
128124 if self ._call_later_handle is not None :
@@ -187,7 +183,7 @@ async def _update_state(self) -> None:
187183
188184 # Schedule next update only if calendar is on and entity is enabled
189185 if calendar_state .state == "on" and self .enabled :
190- now = datetime . now ()
186+ now = utcnow ()
191187 seconds_until_next_minute = 60 - now .second
192188 self ._call_later_handle = self ._hass .loop .call_later (
193189 seconds_until_next_minute ,
@@ -210,11 +206,11 @@ def _matches_criteria(self, event_summary: str) -> bool:
210206 # Default to contains if unknown criteria
211207 return summary_lower in event_summary_lower
212208
213- async def _get_event_matching_summary (self ) -> Event | None :
209+ async def _get_event_matching_summary (self ) -> dict | None :
214210 """Check if the summary is in the calendar events."""
215211
216212 # Fetch all events for the calendar entity using the get_events service
217- now = datetime . now ()
213+ now = utcnow ()
218214 end_date_time = (now + timedelta (hours = 1 )).isoformat ()
219215
220216 events = await self ._hass .services .async_call (
@@ -228,11 +224,21 @@ async def _get_event_matching_summary(self) -> Event | None:
228224 return_response = True ,
229225 )
230226
231- calendar_events = events .get (self ._calendar_entity_id , {}).get ("events" , [])
227+ if not isinstance (events , dict ):
228+ return None
229+
230+ calendar_data = events .get (self ._calendar_entity_id , {})
231+ if not isinstance (calendar_data , dict ):
232+ return None
233+
234+ calendar_events = calendar_data .get ("events" , [])
235+ if not isinstance (calendar_events , list ):
236+ return None
232237 for event in calendar_events :
233238 if not isinstance (event , dict ):
234239 continue
235- if self ._matches_criteria (event .get ("summary" , "" )):
240+ summary = event .get ("summary" , "" )
241+ if isinstance (summary , str ) and self ._matches_criteria (summary ):
236242 return event
237243
238244 return None
0 commit comments