84 lines
2.1 KiB
Python
84 lines
2.1 KiB
Python
from __future__ import annotations
|
|
|
|
import pathlib
|
|
from dataclasses import dataclass, field
|
|
from datetime import datetime, time
|
|
from typing import Any
|
|
from zoneinfo import ZoneInfo
|
|
|
|
import yaml
|
|
|
|
from server.settings import settings
|
|
|
|
|
|
@dataclass
|
|
class Med:
|
|
name: str
|
|
dose: str
|
|
|
|
|
|
@dataclass
|
|
class Slot:
|
|
id: str
|
|
time: time
|
|
label: str
|
|
meds: list[Med]
|
|
reminder_window_minutes: int = 90
|
|
|
|
|
|
@dataclass
|
|
class MedsConfig:
|
|
timezone: ZoneInfo
|
|
slots: list[Slot] = field(default_factory=list)
|
|
|
|
|
|
_config: MedsConfig | None = None
|
|
|
|
|
|
def load_meds_config(path: str | None = None) -> MedsConfig:
|
|
global _config
|
|
if _config is not None:
|
|
return _config
|
|
p = pathlib.Path(path or settings.meds_path)
|
|
raw = yaml.safe_load(p.read_text(encoding="utf-8"))
|
|
tz = ZoneInfo(raw.get("timezone", "Europe/Berlin"))
|
|
slots: list[Slot] = []
|
|
for item in raw.get("slots", []):
|
|
h, m = str(item["time"]).split(":")
|
|
slots.append(
|
|
Slot(
|
|
id=item["id"],
|
|
time=time(int(h), int(m)),
|
|
label=item.get("label", item["id"]),
|
|
meds=[Med(**m) for m in item.get("meds", [])],
|
|
reminder_window_minutes=int(item.get("reminder_window_minutes", 90)),
|
|
)
|
|
)
|
|
_config = MedsConfig(timezone=tz, slots=slots)
|
|
return _config
|
|
|
|
|
|
def reload_meds_config() -> MedsConfig:
|
|
global _config
|
|
_config = None
|
|
return load_meds_config()
|
|
|
|
|
|
def slot_datetime(day: datetime, slot: Slot, tz: ZoneInfo) -> datetime:
|
|
local = day.astimezone(tz) if day.tzinfo else day.replace(tzinfo=tz)
|
|
return local.replace(hour=slot.time.hour, minute=slot.time.minute, second=0, microsecond=0)
|
|
|
|
|
|
def today_str(tz: ZoneInfo) -> str:
|
|
return datetime.now(tz).strftime("%Y-%m-%d")
|
|
|
|
|
|
def slot_to_dict(slot: Slot) -> dict[str, Any]:
|
|
return {
|
|
"id": slot.id,
|
|
"time": slot.time.strftime("%H:%M"),
|
|
"label": slot.label,
|
|
"meds": [{"name": m.name, "dose": m.dose} for m in slot.meds],
|
|
"reminder_window_minutes": slot.reminder_window_minutes,
|
|
}
|