from __future__ import annotations from dataclasses import dataclass from datetime import datetime, time from typing import Awaitable, Callable, Optional from .models import Schedule def _parse_hhmm(value: str) -> time: hh, mm = value.split(":") return time(hour=int(hh), minute=int(mm)) def should_record_now(now: datetime, schedule: Schedule) -> bool: if not schedule.enabled: return False weekday = now.weekday() if weekday in (5, 6) and schedule.weekend_all_day: return True start = _parse_hhmm(schedule.weekdays_from) end = _parse_hhmm(schedule.weekdays_to) now_t = now.time().replace(second=0, microsecond=0) if start == end: return True if start < end: return start <= now_t < end return now_t >= start or now_t < end @dataclass class Scheduler: apply: Callable[[bool], Awaitable[None]] _last_state: Optional[bool] = None async def tick(self, schedule: Schedule) -> None: now = datetime.now() state = should_record_now(now, schedule) # Always enforce desired state to recover from external/manual drift. await self.apply(state) self._last_state = state