update to 0.16.0 #72

Merged
serversdown merged 32 commits from dev into main 2026-06-23 00:59:46 -04:00
Showing only changes of commit c049ac8a41 - Show all commits
+22 -7
View File
@@ -207,24 +207,39 @@ async def control_slm(unit_id: str, action: str):
return {"status": "error", "detail": f"Invalid action. Must be one of: {valid_actions}"} return {"status": "error", "detail": f"Invalid action. Must be one of: {valid_actions}"}
try: try:
async with httpx.AsyncClient(timeout=10.0) as client: # 30s: a real device start confirms over cellular in a few seconds, but
# leave headroom so a healthy start is never cut off mid-flight (which
# surfaced to users as a misleading "Unknown error").
async with httpx.AsyncClient(timeout=30.0) as client:
response = await client.post( response = await client.post(
f"{SLMM_BASE_URL}/api/nl43/{unit_id}/{action}" f"{SLMM_BASE_URL}/api/nl43/{unit_id}/{action}"
) )
if response.status_code == 200: if response.status_code == 200:
return response.json() return response.json()
else:
# Surface SLMM's own error detail when it provides one.
detail = f"SLMM returned status {response.status_code}"
try:
body = response.json()
if isinstance(body, dict) and body.get("detail"):
detail = body["detail"]
except Exception:
pass
return {"status": "error", "detail": detail}
except httpx.TimeoutException:
logger.error(f"Timeout controlling {unit_id} (action={action}) via SLMM")
return { return {
"status": "error", "status": "error",
"detail": f"SLMM returned status {response.status_code}" "detail": (
f"Timed out waiting for the device to {action}. "
f"The command may still have been applied — refresh to confirm."
),
} }
except Exception as e: except Exception as e:
logger.error(f"Failed to control {unit_id}: {e}") logger.error(f"Failed to control {unit_id}: {e}")
return { # Never return an empty detail — it renders to users as "Unknown error".
"status": "error", return {"status": "error", "detail": str(e) or f"{type(e).__name__}"}
"detail": str(e)
}
@router.get("/config/{unit_id}", response_class=HTMLResponse) @router.get("/config/{unit_id}", response_class=HTMLResponse)
async def get_slm_config(request: Request, unit_id: str, db: Session = Depends(get_db)): async def get_slm_config(request: Request, unit_id: str, db: Session = Depends(get_db)):