Server: lifetime stats counters in a collapsed web UI section
Build and push server image / build-and-push (push) Successful in 34s
Build and push server image / build-and-push (push) Successful in 34s
New FrameStats (first_seen, device_wakes, photos_displayed, photos_removed, battery_reports, recharge_cycles, ota_updates_applied, config_saves), persisted alongside everything else in config.json. Incremented at the existing route/photo_queue.py call sites that already own each event -- no new instrumentation plumbing, no behavior depends on these, purely informational. GET /api/stats serves them; the web UI renders them into a native <details> "Stats" card (collapsed by default, no JS needed for the expand/collapse), fetched once on page load like the battery-history chart. Verified: TestClient run through /frame/config (wakes + first_seen + OTA-applied detection), /frame/battery (reports + recharge detection), /api/config (saves); direct photo_queue.py unit checks for advance/back/remove covering the "did the current photo actually change" distinction (removing a queued-but-not-current photo bumps photos_removed but not photos_displayed).
This commit is contained in:
@@ -19,6 +19,21 @@ CONFIG_PATH = Path(os.environ.get("CONFIG_PATH", "/data/config.json"))
|
||||
_lock = RLock()
|
||||
|
||||
|
||||
class FrameStats(BaseModel):
|
||||
"""Cumulative, lifetime counters -- purely informational, never read
|
||||
back to drive any behavior, so there's no harm in them being a little
|
||||
approximate at the edges. Shown in a collapsed "Stats" section in the
|
||||
web UI (GET /api/stats). Never reset except by deleting config.json."""
|
||||
first_seen: float = 0.0 # first time this frame ever checked in
|
||||
device_wakes: int = 0 # wake cycles, counted once each via GET /frame/config
|
||||
photos_displayed: int = 0 # times the current photo actually changed (any cause)
|
||||
photos_removed: int = 0 # times a photo was permanently excluded from rotation
|
||||
battery_reports: int = 0 # POST /frame/battery calls
|
||||
recharge_cycles: int = 0 # times a battery recharge was detected
|
||||
ota_updates_applied: int = 0 # times the device's reported firmware version changed
|
||||
config_saves: int = 0 # POST /api/config calls
|
||||
|
||||
|
||||
class FrameConfig(BaseModel):
|
||||
immich_url: str = ""
|
||||
immich_api_key: str = ""
|
||||
@@ -84,6 +99,8 @@ class FrameConfig(BaseModel):
|
||||
# (POST /api/firmware); "" = none uploaded yet.
|
||||
firmware_available_version: str = ""
|
||||
|
||||
stats: FrameStats = FrameStats()
|
||||
|
||||
|
||||
def load() -> FrameConfig:
|
||||
with _lock:
|
||||
|
||||
Reference in New Issue
Block a user