|
|
@@ -25,13 +25,11 @@ from .const import (
|
|
|
DOMAIN,
|
|
|
RESERVATION_TITLE_PREFIX,
|
|
|
SCAN_INTERVAL_MINUTES,
|
|
|
- SENSOR_KEYS,
|
|
|
STORE_CURRENT,
|
|
|
STORE_NEXT,
|
|
|
X_DATA_PROP,
|
|
|
- default_option_key,
|
|
|
)
|
|
|
-from .models import ReservationData, merge
|
|
|
+from .models import ReservationData
|
|
|
from .store import ReservationStore
|
|
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
@@ -68,49 +66,34 @@ class RoomCalCoordinator(DataUpdateCoordinator[CoordinatorData]):
|
|
|
def inject_guest_mode_switch(self, switch: Any) -> None:
|
|
|
self._guest_mode_switch = switch
|
|
|
|
|
|
- def _option_defaults(self) -> ReservationData:
|
|
|
- opts = self.entry.options
|
|
|
- kwargs: dict[str, Any] = {}
|
|
|
- for key in SENSOR_KEYS:
|
|
|
- kwargs[key] = opts.get(default_option_key(key))
|
|
|
- return ReservationData(**kwargs)
|
|
|
-
|
|
|
async def _async_update_data(self) -> CoordinatorData:
|
|
|
- option_defaults = self._option_defaults()
|
|
|
-
|
|
|
caldav_current: ReservationData | None = None
|
|
|
caldav_next: ReservationData | None = None
|
|
|
+ caldav_fetched = False
|
|
|
|
|
|
if self.entry.options.get(CONF_CALDAV_ENABLED):
|
|
|
try:
|
|
|
caldav_current, caldav_next = await self.hass.async_add_executor_job(
|
|
|
self._fetch_caldav
|
|
|
)
|
|
|
+ caldav_fetched = True
|
|
|
except caldav_error.AuthorizationError:
|
|
|
self.entry.async_start_reauth(self.hass)
|
|
|
raise UpdateFailed("CalDAV authorization failed; re-auth required")
|
|
|
except Exception as exc:
|
|
|
_LOGGER.warning("CalDAV fetch failed, using cached data: %s", exc)
|
|
|
|
|
|
- stored_current = self.store.get(STORE_CURRENT)
|
|
|
- stored_next = self.store.get(STORE_NEXT)
|
|
|
-
|
|
|
now = dt_util.utcnow()
|
|
|
|
|
|
- # When CalDAV returned data, always persist it and refresh the timestamp.
|
|
|
- # When CalDAV was skipped/failed, serve from store without touching the timestamp.
|
|
|
- if caldav_current is not None:
|
|
|
+ if caldav_fetched:
|
|
|
+ # Calendar is authoritative: write its result including None (clears the slot).
|
|
|
await self.store.async_set(STORE_CURRENT, caldav_current)
|
|
|
- stored_current = caldav_current
|
|
|
- self._current_last_refresh = now
|
|
|
-
|
|
|
- if caldav_next is not None:
|
|
|
await self.store.async_set(STORE_NEXT, caldav_next)
|
|
|
- stored_next = caldav_next
|
|
|
+ self._current_last_refresh = now
|
|
|
self._next_last_refresh = now
|
|
|
|
|
|
- new_current = merge(option_defaults, stored_current)
|
|
|
- new_next = merge(option_defaults, stored_next)
|
|
|
+ new_current = self.store.get(STORE_CURRENT) or ReservationData()
|
|
|
+ new_next = self.store.get(STORE_NEXT) or ReservationData()
|
|
|
|
|
|
self._reschedule_mode_sync(new_current)
|
|
|
|
|
|
@@ -229,20 +212,15 @@ class RoomCalCoordinator(DataUpdateCoordinator[CoordinatorData]):
|
|
|
updated = stored.apply_partial(partial)
|
|
|
await self.store.async_set(target, updated)
|
|
|
|
|
|
- option_defaults = self._option_defaults()
|
|
|
now = dt_util.utcnow()
|
|
|
-
|
|
|
if target == STORE_CURRENT:
|
|
|
self._current_last_refresh = now
|
|
|
else:
|
|
|
self._next_last_refresh = now
|
|
|
|
|
|
- current = merge(option_defaults, self.store.get(STORE_CURRENT))
|
|
|
- nxt = merge(option_defaults, self.store.get(STORE_NEXT))
|
|
|
-
|
|
|
self.async_set_updated_data(CoordinatorData(
|
|
|
- current=current,
|
|
|
- next=nxt,
|
|
|
+ current=self.store.get(STORE_CURRENT) or ReservationData(),
|
|
|
+ next=self.store.get(STORE_NEXT) or ReservationData(),
|
|
|
current_last_refresh=self._current_last_refresh,
|
|
|
next_last_refresh=self._next_last_refresh,
|
|
|
))
|