56bd3041cf
feat: Location no longer assigned directly to unit, locations and coords are assigned to location only, unit only is deployed or benched.
125 lines
4.5 KiB
Python
125 lines
4.5 KiB
Python
"""
|
|
Sound Level Meter UI Router
|
|
|
|
Provides endpoints for SLM dashboard cards, detail pages, and real-time data.
|
|
"""
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Request
|
|
from fastapi.responses import HTMLResponse
|
|
from sqlalchemy.orm import Session
|
|
from datetime import datetime
|
|
import httpx
|
|
import logging
|
|
import os
|
|
|
|
from backend.database import get_db
|
|
from backend.models import RosterUnit
|
|
from backend.services.unit_location import get_active_location
|
|
from backend.templates_config import templates
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
router = APIRouter(prefix="/slm", tags=["slm-ui"])
|
|
|
|
SLMM_BASE_URL = os.getenv("SLMM_BASE_URL", "http://172.19.0.1:8100")
|
|
|
|
|
|
@router.get("/{unit_id}", response_class=HTMLResponse)
|
|
async def slm_detail_page(request: Request, unit_id: str, db: Session = Depends(get_db)):
|
|
"""Sound level meter detail page with controls."""
|
|
|
|
# Get roster unit
|
|
unit = db.query(RosterUnit).filter_by(id=unit_id).first()
|
|
if not unit or unit.device_type != "slm":
|
|
raise HTTPException(status_code=404, detail="Sound level meter not found")
|
|
|
|
return templates.TemplateResponse("slm_detail.html", {
|
|
"request": request,
|
|
"unit": unit,
|
|
"unit_id": unit_id
|
|
})
|
|
|
|
|
|
@router.get("/api/{unit_id}/summary")
|
|
async def get_slm_summary(unit_id: str, db: Session = Depends(get_db)):
|
|
"""Get SLM summary data for dashboard card."""
|
|
|
|
# Get roster unit
|
|
unit = db.query(RosterUnit).filter_by(id=unit_id).first()
|
|
if not unit or unit.device_type != "slm":
|
|
raise HTTPException(status_code=404, detail="Sound level meter not found")
|
|
|
|
# Try to get live status from SLMM
|
|
status_data = None
|
|
try:
|
|
async with httpx.AsyncClient(timeout=3.0) as client:
|
|
response = await client.get(f"{SLMM_BASE_URL}/api/nl43/{unit_id}/status")
|
|
if response.status_code == 200:
|
|
status_data = response.json().get("data")
|
|
except Exception as e:
|
|
logger.warning(f"Failed to get SLM status for {unit_id}: {e}")
|
|
|
|
loc = get_active_location(db, unit_id)
|
|
return {
|
|
"unit_id": unit_id,
|
|
"device_type": "slm",
|
|
"deployed": unit.deployed,
|
|
"model": unit.slm_model or "NL-43",
|
|
"location": (loc or {}).get("address") or (loc or {}).get("name") or "",
|
|
"coordinates": (loc or {}).get("coordinates") or "",
|
|
"note": unit.note,
|
|
"status": status_data,
|
|
"last_check": unit.slm_last_check.isoformat() if unit.slm_last_check else None,
|
|
}
|
|
|
|
|
|
@router.get("/partials/{unit_id}/card", response_class=HTMLResponse)
|
|
async def slm_dashboard_card(request: Request, unit_id: str, db: Session = Depends(get_db)):
|
|
"""Render SLM dashboard card partial."""
|
|
|
|
summary = await get_slm_summary(unit_id, db)
|
|
|
|
return templates.TemplateResponse("partials/slm_card.html", {
|
|
"request": request,
|
|
"slm": summary
|
|
})
|
|
|
|
|
|
@router.get("/partials/{unit_id}/controls", response_class=HTMLResponse)
|
|
async def slm_controls_partial(request: Request, unit_id: str, db: Session = Depends(get_db)):
|
|
"""Render SLM control panel partial."""
|
|
|
|
unit = db.query(RosterUnit).filter_by(id=unit_id).first()
|
|
if not unit or unit.device_type != "slm":
|
|
raise HTTPException(status_code=404, detail="Sound level meter not found")
|
|
|
|
# Get current status from SLMM
|
|
measurement_state = None
|
|
battery_level = None
|
|
try:
|
|
async with httpx.AsyncClient(timeout=3.0) as client:
|
|
# Get measurement state
|
|
state_response = await client.get(
|
|
f"{SLMM_BASE_URL}/api/nl43/{unit_id}/measurement-state"
|
|
)
|
|
if state_response.status_code == 200:
|
|
measurement_state = state_response.json().get("measurement_state")
|
|
|
|
# Get battery level
|
|
battery_response = await client.get(
|
|
f"{SLMM_BASE_URL}/api/nl43/{unit_id}/battery"
|
|
)
|
|
if battery_response.status_code == 200:
|
|
battery_level = battery_response.json().get("battery_level")
|
|
except Exception as e:
|
|
logger.warning(f"Failed to get SLM control data for {unit_id}: {e}")
|
|
|
|
return templates.TemplateResponse("partials/slm_controls.html", {
|
|
"request": request,
|
|
"unit_id": unit_id,
|
|
"unit": unit,
|
|
"measurement_state": measurement_state,
|
|
"battery_level": battery_level,
|
|
"is_measuring": measurement_state == "Start"
|
|
})
|