99 lines
2.8 KiB
Python
99 lines
2.8 KiB
Python
"""
|
|
Demeter Server — CoAP-to-REST Bridge
|
|
|
|
Proxies HTTP requests to CoAP endpoints on ESP devices, allowing
|
|
the dashboard and external tools to query devices via standard HTTP.
|
|
|
|
Routes:
|
|
GET /api/devices/{device_id}/coap/{resource_path} — proxy CoAP GET
|
|
PUT /api/devices/{device_id}/coap/{resource_path} — proxy CoAP PUT
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from fastapi import APIRouter, HTTPException, Request
|
|
|
|
router = APIRouter(prefix="/api", tags=["coap-bridge"])
|
|
|
|
|
|
def _get_store(request: Request):
|
|
return request.app.state.store
|
|
|
|
|
|
def _get_observer(request: Request):
|
|
return request.app.state.observer
|
|
|
|
|
|
@router.get("/devices/{device_id}/coap/{resource_path:path}")
|
|
async def coap_proxy_get(
|
|
device_id: str,
|
|
resource_path: str,
|
|
request: Request,
|
|
) -> dict[str, Any]:
|
|
"""
|
|
Proxy a CoAP GET request to an ESP device.
|
|
|
|
Example: GET /api/devices/esp32-plant-01/coap/sensors/temperature
|
|
→ CoAP GET coap://192.168.1.100:5683/sensors/temperature
|
|
"""
|
|
store = _get_store(request)
|
|
observer = _get_observer(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")
|
|
|
|
try:
|
|
result = await observer.coap_get(
|
|
device.config.ip, device.config.port, resource_path
|
|
)
|
|
return {
|
|
"device_id": device_id,
|
|
"resource": resource_path,
|
|
"method": "GET",
|
|
"response": result,
|
|
}
|
|
except ConnectionError as e:
|
|
raise HTTPException(status_code=504, detail=str(e))
|
|
except ValueError as e:
|
|
raise HTTPException(status_code=502, detail=str(e))
|
|
|
|
|
|
@router.put("/devices/{device_id}/coap/{resource_path:path}")
|
|
async def coap_proxy_put(
|
|
device_id: str,
|
|
resource_path: str,
|
|
body: dict[str, Any],
|
|
request: Request,
|
|
) -> dict[str, Any]:
|
|
"""
|
|
Proxy a CoAP PUT request to an ESP device.
|
|
|
|
Example: PUT /api/devices/esp32-plant-01/coap/config/interval
|
|
Body: {"interval": 10}
|
|
→ CoAP PUT coap://192.168.1.100:5683/config/interval
|
|
"""
|
|
store = _get_store(request)
|
|
observer = _get_observer(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")
|
|
|
|
try:
|
|
result = await observer.coap_put(
|
|
device.config.ip, device.config.port, resource_path, body
|
|
)
|
|
return {
|
|
"device_id": device_id,
|
|
"resource": resource_path,
|
|
"method": "PUT",
|
|
"response": result,
|
|
}
|
|
except ConnectionError as e:
|
|
raise HTTPException(status_code=504, detail=str(e))
|
|
except ValueError as e:
|
|
raise HTTPException(status_code=502, detail=str(e))
|