device state fix 3
This commit is contained in:
144
apps/api/main.py
144
apps/api/main.py
@@ -1,146 +1,3 @@
|
||||
|
||||
"""API main entry point.
|
||||
|
||||
API-Analyse für HomeKit-Bridge Kompatibilität
|
||||
==============================================
|
||||
|
||||
1) GET /devices
|
||||
Status: ✅ VORHANDEN (Zeile 325-343)
|
||||
|
||||
Aktuelles Response-Modell (DeviceInfo, Zeile 189-194):
|
||||
{
|
||||
"device_id": str, ✅ OK
|
||||
"type": str, ✅ OK
|
||||
"name": str, ⚠️ ABWEICHUNG: Erwartet wurde "short_name" (optional)
|
||||
"features": dict ✅ OK
|
||||
}
|
||||
|
||||
Bewertung:
|
||||
- ✅ Liefert device_id, type, features wie erwartet
|
||||
- ⚠️ Verwendet "name" statt "short_name"
|
||||
- ✅ Fallback auf device_id wenn name nicht vorhanden
|
||||
- Kompatibilität: HOCH - einfach "name" als "short_name" verwenden
|
||||
|
||||
|
||||
2) GET /layout
|
||||
Status: ✅ VORHANDEN (Zeile 354-387)
|
||||
|
||||
Aktuelles Response-Format:
|
||||
{
|
||||
"rooms": [
|
||||
{
|
||||
"name": "Schlafzimmer",
|
||||
"devices": [
|
||||
{
|
||||
"device_id": "thermostat_wolfgang",
|
||||
"title": "Thermostat Wolfgang", ← friendly_name
|
||||
"icon": "thermometer",
|
||||
"rank": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Mapping device_id -> room, friendly_name:
|
||||
- room: Durch Iteration über rooms[].devices[] ableitbar
|
||||
- friendly_name: Im Feld "title" enthalten
|
||||
|
||||
Bewertung:
|
||||
- ✅ Alle erforderlichen Informationen vorhanden
|
||||
- ⚠️ ABWEICHUNG: Verschachtelte Struktur (rooms -> devices)
|
||||
- ⚠️ ABWEICHUNG: friendly_name heißt "title"
|
||||
- Kompatibilität: HOCH - einfache Transformation möglich:
|
||||
```python
|
||||
for room in layout["rooms"]:
|
||||
for device in room["devices"]:
|
||||
mapping[device["device_id"]] = {
|
||||
"room": room["name"],
|
||||
"friendly_name": device["title"]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
3) POST /devices/{device_id}/set
|
||||
Status: ✅ VORHANDEN (Zeile 406-504)
|
||||
|
||||
Aktuelles Request-Modell (SetDeviceRequest, Zeile 182-185):
|
||||
{
|
||||
"type": str, ✅ OK - muss zum Gerätetyp passen
|
||||
"payload": dict ✅ OK - abstraktes Kommando
|
||||
}
|
||||
|
||||
Beispiel Light:
|
||||
POST /devices/leselampe_esszimmer/set
|
||||
{"type": "light", "payload": {"power": "on", "brightness": 80}}
|
||||
|
||||
Beispiel Thermostat:
|
||||
POST /devices/thermostat_wolfgang/set
|
||||
{"type": "thermostat", "payload": {"target": 21.0}}
|
||||
|
||||
Validierung:
|
||||
- ✅ Type-spezifische Payload-Validierung (Zeile 437-487)
|
||||
- ✅ Read-only Check → 405 METHOD_NOT_ALLOWED (Zeile 431-435)
|
||||
- ✅ Ungültige Payload → 422 UNPROCESSABLE_ENTITY
|
||||
- ✅ Device nicht gefunden → 404 NOT_FOUND
|
||||
|
||||
Bewertung:
|
||||
- ✅ Exakt wie erwartet implementiert
|
||||
- ✅ Alle geforderten Error Codes vorhanden
|
||||
- Kompatibilität: PERFEKT
|
||||
|
||||
|
||||
4) Realtime-Endpoint (SSE)
|
||||
Status: ✅ VORHANDEN als GET /realtime (Zeile 608-632)
|
||||
|
||||
Implementierung:
|
||||
- ✅ Server-Sent Events (media_type="text/event-stream")
|
||||
- ✅ Redis Pub/Sub basiert (event_generator, Zeile 510-607)
|
||||
- ✅ Safari-kompatibel (Heartbeats, Retry-Hints)
|
||||
|
||||
Aktuelles Event-Format (aus apps/abstraction/main.py:250-256):
|
||||
{
|
||||
"type": "state", ✅ OK
|
||||
"device_id": str, ✅ OK
|
||||
"payload": dict, ✅ OK - z.B. {"power":"on","brightness":80}
|
||||
"ts": str ✅ OK - ISO-8601 format von datetime.now(timezone.utc)
|
||||
}
|
||||
|
||||
Beispiel-Event:
|
||||
{
|
||||
"type": "state",
|
||||
"device_id": "thermostat_wolfgang",
|
||||
"payload": {"current": 19.5, "target": 21.0},
|
||||
"ts": "2025-11-17T14:23:45.123456+00:00"
|
||||
}
|
||||
|
||||
Bewertung:
|
||||
- ✅ Alle geforderten Felder vorhanden
|
||||
- ✅ Timestamp im korrekten Format
|
||||
- ✅ SSE mit proper headers und error handling
|
||||
- Kompatibilität: PERFEKT
|
||||
|
||||
|
||||
ZUSAMMENFASSUNG
|
||||
===============
|
||||
|
||||
Alle 4 geforderten Endpunkte sind implementiert!
|
||||
|
||||
Kompatibilität mit HomeKit-Bridge Anforderungen:
|
||||
- GET /devices: HOCH (nur Name-Feld unterschiedlich)
|
||||
- GET /layout: HOCH (Struktur-Transformation nötig)
|
||||
- POST /devices/{id}/set: PERFEKT (1:1 wie gefordert)
|
||||
- GET /realtime (SSE): PERFEKT (1:1 wie gefordert)
|
||||
|
||||
Erforderliche Anpassungen für Bridge:
|
||||
1. GET /devices: "name" als "short_name" interpretieren ✓ trivial
|
||||
2. GET /layout: Verschachtelte Struktur zu flat mapping umwandeln ✓ einfach
|
||||
|
||||
Keine Code-Änderungen in der API erforderlich!
|
||||
Die Bridge kann die bestehenden Endpoints direkt nutzen.
|
||||
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
@@ -232,6 +89,7 @@ async def get_device_layout(device_id: str):
|
||||
@app.get("/devices/{device_id}/state")
|
||||
async def get_device_state(device_id: str):
|
||||
try:
|
||||
logger.debug(f"Fetching state for device {device_id}")
|
||||
state = device_states[device_id]
|
||||
return state
|
||||
except KeyError:
|
||||
|
||||
Reference in New Issue
Block a user