docs: add project description and server setup instructions to README
This commit is contained in:
90
server/app/devices_api.py
Normal file
90
server/app/devices_api.py
Normal file
@@ -0,0 +1,90 @@
|
||||
"""
|
||||
Demeter Server — REST API Endpoints
|
||||
|
||||
Provides JSON endpoints for querying device metadata and sensor
|
||||
readings from the in-memory store.
|
||||
|
||||
Routes:
|
||||
GET /api/devices — list all devices + latest readings
|
||||
GET /api/devices/{device_id} — single device detail
|
||||
GET /api/devices/{device_id}/readings — sensor readings only
|
||||
GET /api/status — server status summary
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
from typing import Any
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Request
|
||||
|
||||
router = APIRouter(prefix="/api", tags=["devices"])
|
||||
|
||||
|
||||
def _get_store(request: Request):
|
||||
"""Retrieve the DeviceStore from app state."""
|
||||
return request.app.state.store
|
||||
|
||||
|
||||
def _get_observer(request: Request):
|
||||
"""Retrieve the CoapObserverClient from app state."""
|
||||
return request.app.state.observer
|
||||
|
||||
|
||||
@router.get("/devices")
|
||||
async def list_devices(request: Request) -> dict[str, Any]:
|
||||
"""List all registered devices with their latest readings."""
|
||||
store = _get_store(request)
|
||||
snapshot = await store.snapshot()
|
||||
return {
|
||||
"devices": list(snapshot.values()),
|
||||
"count": len(snapshot),
|
||||
"timestamp": time.time(),
|
||||
}
|
||||
|
||||
|
||||
@router.get("/devices/{device_id}")
|
||||
async def get_device(device_id: str, request: Request) -> dict[str, Any]:
|
||||
"""Get a single device's full state."""
|
||||
store = _get_store(request)
|
||||
device = await store.get_device(device_id)
|
||||
if device is None:
|
||||
raise HTTPException(status_code=404, detail=f"Device {device_id!r} not found")
|
||||
return device.to_dict()
|
||||
|
||||
|
||||
@router.get("/devices/{device_id}/readings")
|
||||
async def get_readings(device_id: str, request: Request) -> dict[str, Any]:
|
||||
"""Get sensor readings for a specific device."""
|
||||
store = _get_store(request)
|
||||
device = await store.get_device(device_id)
|
||||
if device is None:
|
||||
raise HTTPException(status_code=404, detail=f"Device {device_id!r} not found")
|
||||
return {
|
||||
"device_id": device_id,
|
||||
"online": device.online,
|
||||
"readings": {
|
||||
uri: reading.to_dict()
|
||||
for uri, reading in device.readings.items()
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@router.get("/status")
|
||||
async def server_status(request: Request) -> dict[str, Any]:
|
||||
"""Server status: subscription count, device overview."""
|
||||
store = _get_store(request)
|
||||
observer = _get_observer(request)
|
||||
|
||||
devices = await store.get_all_devices()
|
||||
online = sum(1 for d in devices if d.online)
|
||||
|
||||
return {
|
||||
"server": "demeter",
|
||||
"version": request.app.state.settings.app_version,
|
||||
"devices_total": len(devices),
|
||||
"devices_online": online,
|
||||
"active_subscriptions": observer.active_subscriptions,
|
||||
"subscriptions": observer.subscription_status(),
|
||||
"timestamp": time.time(),
|
||||
}
|
||||
Reference in New Issue
Block a user