Add power toggle button to LED device cards
WLED: native on/off via JSON API. Adalight: sends all-black frame to blank LEDs (uses existing client if target is running, otherwise opens temporary serial connection). Toggle button placed next to delete button in card top-right corner. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
"""Device routes: CRUD, health state, brightness, calibration."""
|
||||
"""Device routes: CRUD, health state, brightness, power, calibration."""
|
||||
|
||||
import httpx
|
||||
from fastapi import APIRouter, HTTPException, Depends
|
||||
@@ -367,6 +367,63 @@ async def set_device_brightness(
|
||||
raise HTTPException(status_code=502, detail=f"Failed to reach device: {e}")
|
||||
|
||||
|
||||
# ===== POWER ENDPOINTS =====
|
||||
|
||||
@router.get("/api/v1/devices/{device_id}/power", tags=["Settings"])
|
||||
async def get_device_power(
|
||||
device_id: str,
|
||||
_auth: AuthRequired,
|
||||
store: DeviceStore = Depends(get_device_store),
|
||||
):
|
||||
"""Get current power state from the device."""
|
||||
device = store.get_device(device_id)
|
||||
if not device:
|
||||
raise HTTPException(status_code=404, detail=f"Device {device_id} not found")
|
||||
if "power_control" not in get_device_capabilities(device.device_type):
|
||||
raise HTTPException(status_code=400, detail=f"Power control is not supported for {device.device_type} devices")
|
||||
|
||||
try:
|
||||
provider = get_provider(device.device_type)
|
||||
on = await provider.get_power(device.url)
|
||||
return {"on": on}
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get power for {device_id}: {e}")
|
||||
raise HTTPException(status_code=502, detail=f"Failed to reach device: {e}")
|
||||
|
||||
|
||||
@router.put("/api/v1/devices/{device_id}/power", tags=["Settings"])
|
||||
async def set_device_power(
|
||||
device_id: str,
|
||||
body: dict,
|
||||
_auth: AuthRequired,
|
||||
store: DeviceStore = Depends(get_device_store),
|
||||
manager = Depends(get_processor_manager),
|
||||
):
|
||||
"""Turn device on or off."""
|
||||
device = store.get_device(device_id)
|
||||
if not device:
|
||||
raise HTTPException(status_code=404, detail=f"Device {device_id} not found")
|
||||
if "power_control" not in get_device_capabilities(device.device_type):
|
||||
raise HTTPException(status_code=400, detail=f"Power control is not supported for {device.device_type} devices")
|
||||
|
||||
on = body.get("on")
|
||||
if on is None or not isinstance(on, bool):
|
||||
raise HTTPException(status_code=400, detail="'on' must be a boolean")
|
||||
|
||||
try:
|
||||
if device.device_type == "adalight":
|
||||
if not on:
|
||||
await manager.send_black_frame(device_id)
|
||||
# "on" is a no-op for Adalight — next processing frame lights them up
|
||||
else:
|
||||
provider = get_provider(device.device_type)
|
||||
await provider.set_power(device.url, on)
|
||||
return {"on": on}
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to set power for {device_id}: {e}")
|
||||
raise HTTPException(status_code=502, detail=f"Failed to reach device: {e}")
|
||||
|
||||
|
||||
# ===== CALIBRATION ENDPOINTS =====
|
||||
|
||||
@router.get("/api/v1/devices/{device_id}/calibration", response_model=CalibrationSchema, tags=["Calibration"])
|
||||
|
||||
Reference in New Issue
Block a user