Dashboard web FastAPI + Chart.js

- 4 vues : spectre temps reel, historique detections, background, timeline CPS
- API REST : /api/status, /api/spectrum/current, /api/spectrum/difference,
  /api/background, /api/background/spectrum, /api/history, /api/cps/timeline
- Frontend vanilla JS + Chart.js (pas de Node.js, leger pour Pi 4)
- Moniteur modifie pour exporter son etat dans /data/monitor_state.json
  et le CPS dans /data/cps_log.jsonl chaque cycle
- Nouveau conteneur Docker 'web' sur port 8080
- Theme sombre, calibration energie (E = 0.33 + 2.97 * canal)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jacquin Antoine
2026-05-19 13:33:07 +02:00
parent 27ef0727e8
commit 1e0c1a5ea5
22 changed files with 1031 additions and 2 deletions

40
web/app/routers/status.py Normal file
View File

@ -0,0 +1,40 @@
import json
from datetime import datetime
from fastapi import APIRouter, HTTPException
from app.config import STATE_PATH
router = APIRouter()
@router.get("/status")
async def get_status():
"""Current monitor status: connected, CPS, last isotopes detected."""
if not STATE_PATH.exists():
raise HTTPException(status_code=503, detail="Monitor not started yet")
try:
with open(STATE_PATH) as f:
state = json.load(f)
except (json.JSONDecodeError, OSError):
raise HTTPException(status_code=503, detail="Monitor state file corrupt")
# Check staleness (> 5 minutes old)
try:
ts = datetime.fromisoformat(state["timestamp"])
age = (datetime.now() - ts).total_seconds()
state["stale"] = age > 300
state["age_seconds"] = int(age)
except (KeyError, ValueError):
state["stale"] = True
return {
"connected": state.get("connected", False),
"stale": state.get("stale", True),
"age_seconds": state.get("age_seconds", 0),
"timestamp": state.get("timestamp", ""),
"cps": state.get("cps", 0),
"cumulated_live_time_h": state.get("cumulated_live_time_h", 0),
"total_counts": state.get("total_counts", 0),
"background_subtracted": state.get("background_subtracted", False),
"isotopes_detected": state.get("isotopes_detected", []),
}