Partially revert google local sync for search cases (#81761)
fixes undefined
This commit is contained in:
parent
4d1fa42a3c
commit
dfab3b2651
1 changed files with 118 additions and 36 deletions
|
@ -3,11 +3,12 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
from collections.abc import Iterable
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
import logging
|
import logging
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from gcal_sync.api import SyncEventsRequest
|
from gcal_sync.api import GoogleCalendarService, ListEventsRequest, SyncEventsRequest
|
||||||
from gcal_sync.exceptions import ApiException
|
from gcal_sync.exceptions import ApiException
|
||||||
from gcal_sync.model import DateOrDatetime, Event
|
from gcal_sync.model import DateOrDatetime, Event
|
||||||
from gcal_sync.store import ScopedCalendarStore
|
from gcal_sync.store import ScopedCalendarStore
|
||||||
|
@ -196,21 +197,30 @@ async def async_setup_entry(
|
||||||
entity_registry.async_remove(
|
entity_registry.async_remove(
|
||||||
entity_entry.entity_id,
|
entity_entry.entity_id,
|
||||||
)
|
)
|
||||||
request_template = SyncEventsRequest(
|
coordinator: CalendarSyncUpdateCoordinator | CalendarQueryUpdateCoordinator
|
||||||
calendar_id=calendar_id,
|
if search := data.get(CONF_SEARCH):
|
||||||
search=data.get(CONF_SEARCH),
|
coordinator = CalendarQueryUpdateCoordinator(
|
||||||
start_time=dt_util.now() + SYNC_EVENT_MIN_TIME,
|
hass,
|
||||||
)
|
calendar_service,
|
||||||
sync = CalendarEventSyncManager(
|
data[CONF_NAME],
|
||||||
calendar_service,
|
calendar_id,
|
||||||
store=ScopedCalendarStore(store, unique_id or entity_name),
|
search,
|
||||||
request_template=request_template,
|
)
|
||||||
)
|
else:
|
||||||
coordinator = CalendarUpdateCoordinator(
|
request_template = SyncEventsRequest(
|
||||||
hass,
|
calendar_id=calendar_id,
|
||||||
sync,
|
start_time=dt_util.now() + SYNC_EVENT_MIN_TIME,
|
||||||
data[CONF_NAME],
|
)
|
||||||
)
|
sync = CalendarEventSyncManager(
|
||||||
|
calendar_service,
|
||||||
|
store=ScopedCalendarStore(store, unique_id or entity_name),
|
||||||
|
request_template=request_template,
|
||||||
|
)
|
||||||
|
coordinator = CalendarSyncUpdateCoordinator(
|
||||||
|
hass,
|
||||||
|
sync,
|
||||||
|
data[CONF_NAME],
|
||||||
|
)
|
||||||
entities.append(
|
entities.append(
|
||||||
GoogleCalendarEntity(
|
GoogleCalendarEntity(
|
||||||
coordinator,
|
coordinator,
|
||||||
|
@ -242,8 +252,8 @@ async def async_setup_entry(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class CalendarUpdateCoordinator(DataUpdateCoordinator[Timeline]):
|
class CalendarSyncUpdateCoordinator(DataUpdateCoordinator[Timeline]):
|
||||||
"""Coordinator for calendar RPC calls."""
|
"""Coordinator for calendar RPC calls that use an efficient sync."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
@ -251,7 +261,7 @@ class CalendarUpdateCoordinator(DataUpdateCoordinator[Timeline]):
|
||||||
sync: CalendarEventSyncManager,
|
sync: CalendarEventSyncManager,
|
||||||
name: str,
|
name: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Create the Calendar event device."""
|
"""Create the CalendarSyncUpdateCoordinator."""
|
||||||
super().__init__(
|
super().__init__(
|
||||||
hass,
|
hass,
|
||||||
_LOGGER,
|
_LOGGER,
|
||||||
|
@ -271,6 +281,87 @@ class CalendarUpdateCoordinator(DataUpdateCoordinator[Timeline]):
|
||||||
dt_util.DEFAULT_TIME_ZONE
|
dt_util.DEFAULT_TIME_ZONE
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def async_get_events(
|
||||||
|
self, start_date: datetime, end_date: datetime
|
||||||
|
) -> Iterable[Event]:
|
||||||
|
"""Get all events in a specific time frame."""
|
||||||
|
if not self.data:
|
||||||
|
raise HomeAssistantError(
|
||||||
|
"Unable to get events: Sync from server has not completed"
|
||||||
|
)
|
||||||
|
return self.data.overlapping(
|
||||||
|
dt_util.as_local(start_date),
|
||||||
|
dt_util.as_local(end_date),
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def upcoming(self) -> Iterable[Event] | None:
|
||||||
|
"""Return upcoming events if any."""
|
||||||
|
if self.data:
|
||||||
|
return self.data.active_after(dt_util.now())
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class CalendarQueryUpdateCoordinator(DataUpdateCoordinator[list[Event]]):
|
||||||
|
"""Coordinator for calendar RPC calls.
|
||||||
|
|
||||||
|
This sends a polling RPC, not using sync, as a workaround
|
||||||
|
for limitations in the calendar API for supporting search.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
hass: HomeAssistant,
|
||||||
|
calendar_service: GoogleCalendarService,
|
||||||
|
name: str,
|
||||||
|
calendar_id: str,
|
||||||
|
search: str | None,
|
||||||
|
) -> None:
|
||||||
|
"""Create the CalendarQueryUpdateCoordinator."""
|
||||||
|
super().__init__(
|
||||||
|
hass,
|
||||||
|
_LOGGER,
|
||||||
|
name=name,
|
||||||
|
update_interval=MIN_TIME_BETWEEN_UPDATES,
|
||||||
|
)
|
||||||
|
self.calendar_service = calendar_service
|
||||||
|
self.calendar_id = calendar_id
|
||||||
|
self._search = search
|
||||||
|
|
||||||
|
async def async_get_events(
|
||||||
|
self, start_date: datetime, end_date: datetime
|
||||||
|
) -> Iterable[Event]:
|
||||||
|
"""Get all events in a specific time frame."""
|
||||||
|
request = ListEventsRequest(
|
||||||
|
calendar_id=self.calendar_id,
|
||||||
|
start_time=start_date,
|
||||||
|
end_time=end_date,
|
||||||
|
search=self._search,
|
||||||
|
)
|
||||||
|
result_items = []
|
||||||
|
try:
|
||||||
|
result = await self.calendar_service.async_list_events(request)
|
||||||
|
async for result_page in result:
|
||||||
|
result_items.extend(result_page.items)
|
||||||
|
except ApiException as err:
|
||||||
|
self.async_set_update_error(err)
|
||||||
|
raise HomeAssistantError(str(err)) from err
|
||||||
|
return result_items
|
||||||
|
|
||||||
|
async def _async_update_data(self) -> list[Event]:
|
||||||
|
"""Fetch data from API endpoint."""
|
||||||
|
request = ListEventsRequest(calendar_id=self.calendar_id, search=self._search)
|
||||||
|
try:
|
||||||
|
result = await self.calendar_service.async_list_events(request)
|
||||||
|
except ApiException as err:
|
||||||
|
raise UpdateFailed(f"Error communicating with API: {err}") from err
|
||||||
|
return result.items
|
||||||
|
|
||||||
|
@property
|
||||||
|
def upcoming(self) -> Iterable[Event] | None:
|
||||||
|
"""Return the next upcoming event if any."""
|
||||||
|
return self.data
|
||||||
|
|
||||||
|
|
||||||
class GoogleCalendarEntity(CoordinatorEntity, CalendarEntity):
|
class GoogleCalendarEntity(CoordinatorEntity, CalendarEntity):
|
||||||
"""A calendar event entity."""
|
"""A calendar event entity."""
|
||||||
|
@ -279,7 +370,7 @@ class GoogleCalendarEntity(CoordinatorEntity, CalendarEntity):
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
coordinator: CalendarUpdateCoordinator,
|
coordinator: CalendarSyncUpdateCoordinator | CalendarQueryUpdateCoordinator,
|
||||||
calendar_id: str,
|
calendar_id: str,
|
||||||
data: dict[str, Any],
|
data: dict[str, Any],
|
||||||
entity_id: str,
|
entity_id: str,
|
||||||
|
@ -352,14 +443,7 @@ class GoogleCalendarEntity(CoordinatorEntity, CalendarEntity):
|
||||||
self, hass: HomeAssistant, start_date: datetime, end_date: datetime
|
self, hass: HomeAssistant, start_date: datetime, end_date: datetime
|
||||||
) -> list[CalendarEvent]:
|
) -> list[CalendarEvent]:
|
||||||
"""Get all events in a specific time frame."""
|
"""Get all events in a specific time frame."""
|
||||||
if not (timeline := self.coordinator.data):
|
result_items = await self.coordinator.async_get_events(start_date, end_date)
|
||||||
raise HomeAssistantError(
|
|
||||||
"Unable to get events: Sync from server has not completed"
|
|
||||||
)
|
|
||||||
result_items = timeline.overlapping(
|
|
||||||
dt_util.as_local(start_date),
|
|
||||||
dt_util.as_local(end_date),
|
|
||||||
)
|
|
||||||
return [
|
return [
|
||||||
_get_calendar_event(event)
|
_get_calendar_event(event)
|
||||||
for event in filter(self._event_filter, result_items)
|
for event in filter(self._event_filter, result_items)
|
||||||
|
@ -367,14 +451,12 @@ class GoogleCalendarEntity(CoordinatorEntity, CalendarEntity):
|
||||||
|
|
||||||
def _apply_coordinator_update(self) -> None:
|
def _apply_coordinator_update(self) -> None:
|
||||||
"""Copy state from the coordinator to this entity."""
|
"""Copy state from the coordinator to this entity."""
|
||||||
if (timeline := self.coordinator.data) and (
|
if api_event := next(
|
||||||
api_event := next(
|
filter(
|
||||||
filter(
|
self._event_filter,
|
||||||
self._event_filter,
|
self.coordinator.upcoming or [],
|
||||||
timeline.active_after(dt_util.now()),
|
),
|
||||||
),
|
None,
|
||||||
None,
|
|
||||||
)
|
|
||||||
):
|
):
|
||||||
self._event = _get_calendar_event(api_event)
|
self._event = _get_calendar_event(api_event)
|
||||||
(self._event.summary, self._offset_value) = extract_offset(
|
(self._event.summary, self._offset_value) = extract_offset(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue