Spaces:
Configuration error
Configuration error
| from __future__ import annotations | |
| from datetime import datetime | |
| from enum import Enum, IntEnum | |
| from typing import Final | |
| from pydantic import BaseModel, ConfigDict, Field | |
| class Trend(IntEnum): | |
| FALLING = -1 | |
| STABLE = 0 | |
| RISING = 1 | |
| def symbol(self) -> str: | |
| return {self.FALLING: "↓", self.STABLE: "→", self.RISING: "↑"}[self] | |
| def color(self) -> str: | |
| return {self.FALLING: "badge-falling", self.STABLE: "badge-stable", self.RISING: "badge-rising"}[self] | |
| class WarningLevel(str, Enum): | |
| NORMAL = "normal" | |
| ATTENTION = "attention" | |
| WARNING = "warning" | |
| ALARM = "alarm" | |
| def label(self) -> str: | |
| return { | |
| self.NORMAL: "Normal", | |
| self.ATTENTION: "Aufmerksamkeit", | |
| self.WARNING: "Warnung", | |
| self.ALARM: "Alarm", | |
| }[self] | |
| def color(self) -> str: | |
| return { | |
| self.NORMAL: "badge-normal", | |
| self.ATTENTION: "badge-attention", | |
| self.WARNING: "badge-warning", | |
| self.ALARM: "badge-alarm", | |
| }[self] | |
| WARN_THRESHOLDS: Final[tuple[tuple[int, WarningLevel], ...]] = ( | |
| (400, WarningLevel.NORMAL), | |
| (600, WarningLevel.ATTENTION), | |
| (800, WarningLevel.WARNING), | |
| ) | |
| def determine_warning(level_cm: int) -> WarningLevel: | |
| for threshold, level in WARN_THRESHOLDS: | |
| if level_cm < threshold: | |
| return level | |
| return WarningLevel.ALARM | |
| class Measurement(BaseModel): | |
| model_config = ConfigDict(frozen=True) | |
| level_cm: int = Field(ge=0, description="Water level in centimeters") | |
| timestamp: datetime = Field(description="Timestamp of the measurement with tz info") | |
| trend: Trend = Field(description="Trend indicator: -1 falling, 0 stable, 1 rising") | |
| is_demo: bool = False | |
| def warning(self) -> WarningLevel: | |
| return determine_warning(self.level_cm) | |
| class HistoryResponse(BaseModel): | |
| data: list[Measurement] | |
| demo_mode: bool = False | |
| class LatestResponse(BaseModel): | |
| measurement: Measurement | |
| history: list[Measurement] = Field(default_factory=list) | |
| latency_ms: float | None = None | |
| error: str | None = None | |
| demo_mode: bool = False | |
| def resolve_trend( | |
| current_level: int, | |
| provided_trend: int | None, | |
| previous: Measurement | None, | |
| ) -> Trend: | |
| if provided_trend in (-1, 0, 1): | |
| return Trend(provided_trend) | |
| if previous is None: | |
| return Trend.STABLE | |
| delta = current_level - previous.level_cm | |
| if delta > 2: | |
| return Trend.RISING | |
| if delta < -2: | |
| return Trend.FALLING | |
| return Trend.STABLE | |