from dataclasses import dataclass, field, fields from datetime import datetime, time from enum import StrEnum from typing import Any class ScheduleActionType(StrEnum): SET = "set" AUTO = "auto" @dataclass(frozen=True, slots=True) class ScheduledSettings: power: bool | None = None speed: int | None = None heater: bool | None = None target_temp: int | None = None mode: str | None = None sound: bool | None = None light: bool | None = None def merged( self, newer: "ScheduledSettings", ) -> "ScheduledSettings": """ Наложить более новые настройки поверх старых. None означает: параметр в данной точке расписания не менялся. """ values: dict[str, Any] = {} for item in fields(self): old_value = getattr(self, item.name) new_value = getattr(newer, item.name) values[item.name] = ( old_value if new_value is None else new_value ) return ScheduledSettings(**values) @property def empty(self) -> bool: return all( getattr(self, item.name) is None for item in fields(self) ) def to_dict( self, *, skip_none: bool = True, ) -> dict: result = {} for item in fields(self): value = getattr(self, item.name) if skip_none and value is None: continue result[item.name] = value return result @dataclass(frozen=True, slots=True) class ScheduleAction: type: ScheduleActionType settings: ScheduledSettings = field( default_factory=ScheduledSettings ) @dataclass(frozen=True, slots=True) class SchedulePoint: at: time action: ScheduleAction @dataclass(frozen=True, slots=True) class ScheduleConfig: version: int enabled: bool timezone: str templates: dict[ str, tuple[SchedulePoint, ...] ] days: dict[str, str] @dataclass(frozen=True, slots=True) class ScheduleOccurrence: """ Конкретная точка расписания уже с датой. """ when: datetime weekday: str template: str point: SchedulePoint @dataclass(frozen=True, slots=True) class ScheduleResolution: enabled: bool current: ScheduleOccurrence | None next: ScheduleOccurrence | None scheduled_settings: ScheduledSettings auto_active: bool