348 files
This commit is contained in:
@@ -21,13 +21,19 @@ from .coord_badges import BadgeCoordinator
|
||||
from .coord_calendar import CalendarMixin
|
||||
from .coord_challenges import ChallengesMixin
|
||||
from .coord_chores import ChoresMixin
|
||||
from .coord_guests import GuestsMixin
|
||||
from .coord_mandatory import MandatoryMixin
|
||||
from .coord_notifications import NotificationCoordinator
|
||||
from .coord_points import PointsMixin
|
||||
from .coord_quests import QuestsMixin
|
||||
from .coord_reports import ReportsMixin
|
||||
from .coord_rewards import RewardsMixin
|
||||
from .coord_roulette import RouletteMixin
|
||||
from .coord_scheduled import ScheduledChangesMixin
|
||||
from .coord_templates import TemplatesMixin
|
||||
from .coord_timed import TimedMixin
|
||||
from .coord_tts import ReadAloudMixin
|
||||
from .coord_unlocks import UnlocksMixin
|
||||
from .models import Child
|
||||
from .storage import TaskMateStorage
|
||||
|
||||
@@ -46,6 +52,12 @@ class TaskMateCoordinator(
|
||||
TimedMixin,
|
||||
CalendarMixin,
|
||||
TemplatesMixin,
|
||||
ScheduledChangesMixin,
|
||||
ReportsMixin,
|
||||
RouletteMixin,
|
||||
ReadAloudMixin,
|
||||
GuestsMixin,
|
||||
UnlocksMixin,
|
||||
DataUpdateCoordinator,
|
||||
):
|
||||
"""Coordinator to manage TaskMate data."""
|
||||
@@ -66,6 +78,12 @@ class TaskMateCoordinator(
|
||||
self._unsub_prune: Callable[[], None] | None = None
|
||||
self._unsub_availability: Callable[[], None] | None = None
|
||||
self._tracked_availability_entities: set[str] = set()
|
||||
self._tracked_visibility_entities: set[str] = set()
|
||||
# Bumped whenever a tracked external entity (child availability, chore
|
||||
# visibility, chore weather) changes state. The data snapshot is reused
|
||||
# while storage.data_version is unchanged, so sensors that derive
|
||||
# attributes from live entity state need this to invalidate their cache.
|
||||
self.external_state_version: int = 0
|
||||
self._unsub_surprise: Callable[[], None] | None = None
|
||||
self._unsub_weekly: Callable[[], None] | None = None
|
||||
self._unsub_mandatory: list[Callable[[], None]] = []
|
||||
@@ -74,6 +92,8 @@ class TaskMateCoordinator(
|
||||
self._avail_cache: dict | None = None
|
||||
# (data_version, snapshot) cache for _async_update_data (PERF-2).
|
||||
self._data_snapshot_cache: tuple[int, dict[str, Any]] | None = None
|
||||
# Scheduled reverts for timed unlock rewards (#678).
|
||||
self._unlock_timers: list = []
|
||||
|
||||
def difficulty_multiplier(self, tier: str) -> float:
|
||||
"""Return the points multiplier for a difficulty tier.
|
||||
@@ -265,6 +285,11 @@ class TaskMateCoordinator(
|
||||
await self.storage.async_save()
|
||||
await self._async_backfill_career_history()
|
||||
await self._async_stop_stale_timed_sessions()
|
||||
# Catch up on scheduled changes (#675) that came due while HA was off —
|
||||
# the parent still expects "from 1 September" to have happened.
|
||||
await self.async_apply_due_scheduled_changes(refresh=False)
|
||||
# A restart mid-unlock must never strand the TV on (#678).
|
||||
await self.async_resume_unlocks()
|
||||
await self.async_refresh()
|
||||
# Schedule midnight streak check at 00:00:05
|
||||
self._unsub_midnight = async_track_time_change(
|
||||
@@ -607,6 +632,7 @@ class TaskMateCoordinator(
|
||||
|
||||
async def async_shutdown(self) -> None:
|
||||
"""Shutdown the coordinator and clean up listeners."""
|
||||
self.cancel_unlock_timers()
|
||||
if self._unsub_midnight:
|
||||
self._unsub_midnight()
|
||||
self._unsub_midnight = None
|
||||
@@ -640,9 +666,13 @@ class TaskMateCoordinator(
|
||||
saves. One step failing must not stop the rest.
|
||||
"""
|
||||
steps = [
|
||||
self.async_apply_due_scheduled_changes,
|
||||
self.async_prune_roulette_state,
|
||||
self.async_archive_expired_guests,
|
||||
self._async_check_streaks,
|
||||
self._async_expire_one_shot_chores,
|
||||
self._async_expire_dated_chores,
|
||||
self._async_expire_deadline_chores,
|
||||
self._async_restock_rewards,
|
||||
self._async_expire_rewards,
|
||||
self._async_decay_points,
|
||||
@@ -698,6 +728,11 @@ class TaskMateCoordinator(
|
||||
# May stop sessions (mutates + saves -> bumps the version), so run first.
|
||||
await self._async_auto_stop_capped_sessions()
|
||||
await self._async_check_family_goal()
|
||||
# Reactive-chore deadlines are minutes long, so they can't wait for
|
||||
# midnight maintenance like the date-based expiries do. refresh=False:
|
||||
# we are already inside the refresh, and the snapshot below picks the
|
||||
# change up in this same tick.
|
||||
await self._async_expire_deadline_chores(refresh=False)
|
||||
self._refresh_tracked_availability_entities()
|
||||
version = self.storage.data_version
|
||||
cached = getattr(self, "_data_snapshot_cache", None)
|
||||
|
||||
Reference in New Issue
Block a user