Files

85 lines
2.8 KiB
Python

from __future__ import annotations
import os
from dataclasses import dataclass
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
def _float_env(name: str, default: float, minimum: float) -> float:
raw = os.getenv(name, str(default))
try:
value = float(raw)
except ValueError as exc:
raise ValueError(f"{name} must be a number") from exc
if value < minimum:
raise ValueError(f"{name} must be at least {minimum}")
return value
def _int_env(name: str, default: int, minimum: int) -> int:
raw = os.getenv(name, str(default))
try:
value = int(raw)
except ValueError as exc:
raise ValueError(f"{name} must be an integer") from exc
if value < minimum:
raise ValueError(f"{name} must be at least {minimum}")
return value
@dataclass(frozen=True)
class Settings:
tapo_host: str
tapo_username: str
tapo_password: str
timezone_name: str
poll_interval_seconds: float
start_watts: float
stop_watts: float
confirm_samples: int
max_gap_seconds: float
sample_retention_days: int
database_path: str
dashboard_username: str
dashboard_password: str
@classmethod
def from_env(cls) -> "Settings":
timezone_name = os.getenv("TZ", "Europe/Prague")
try:
ZoneInfo(timezone_name)
except ZoneInfoNotFoundError as exc:
raise ValueError(f"TZ is not a known timezone: {timezone_name}") from exc
start_watts = _float_env("START_WATTS", 100.0, 0.1)
stop_watts = _float_env("STOP_WATTS", 30.0, 0.0)
if stop_watts >= start_watts:
raise ValueError("STOP_WATTS must be lower than START_WATTS")
poll_interval = _float_env("POLL_INTERVAL_SECONDS", 2.0, 0.5)
max_gap = _float_env("MAX_GAP_SECONDS", max(20.0, poll_interval * 5), poll_interval * 2)
return cls(
tapo_host=os.getenv("TAPO_HOST", "").strip(),
tapo_username=os.getenv("TAPO_USERNAME", "").strip(),
tapo_password=os.getenv("TAPO_PASSWORD", ""),
timezone_name=timezone_name,
poll_interval_seconds=poll_interval,
start_watts=start_watts,
stop_watts=stop_watts,
confirm_samples=_int_env("CONFIRM_SAMPLES", 2, 1),
max_gap_seconds=max_gap,
sample_retention_days=_int_env("SAMPLE_RETENTION_DAYS", 30, 1),
database_path=os.getenv("DATABASE_PATH", "/data/pump-monitor.sqlite3"),
dashboard_username=os.getenv("DASHBOARD_USERNAME", "water-monitor").strip(),
dashboard_password=os.getenv("DASHBOARD_PASSWORD", ""),
)
@property
def credentials_configured(self) -> bool:
return bool(self.tapo_username and self.tapo_password)
@property
def timezone(self) -> ZoneInfo:
return ZoneInfo(self.timezone_name)