# API Reference Diese Datei beschreibt die HTTP-Schnittstellen der Anwendung. ## Swagger / OpenAPI Zusatzlich zur textuellen Referenz gibt es jetzt zwei API-Dokumentationsziele in der laufenden Anwendung: - Swagger UI: `/docs/` - OpenAPI-Spec: `/openapi.yaml` Beim lokalen Start mit `php -S localhost:8000 -t public` sind die URLs: - `http://localhost:8000/docs/` - `http://localhost:8000/openapi.yaml` Die OpenAPI-Datei ist handgeschrieben und dient als maschinenlesbare Quelle fuer die Swagger UI. ## Basis - API-Stil: REST-nah - Datenformat: JSON - Authentifizierung fuer eingehende Messwerte: Bearer-Token - Charset: UTF-8 ## Endpunkt: `POST /api/v1/readings.php` Nimmt genau einen Sensorwert fuer genau ein Fach entgegen. ### Request-Header - `Authorization: Bearer ` - `Content-Type: application/json` ### Request-Body ```json { "machine_id": "automat-lobby", "sensor_id": "fach-a1", "distance_mm": 184, "measured_at": "2026-04-15T19:20:00Z" } ``` ### Felder - `machine_id` - Typ: String - Pflichtfeld: ja - Bedeutung: ID des Automaten aus `config.json` - `sensor_id` - Typ: String - Pflichtfeld: ja - Bedeutung: ID des Sensors bzw. Fachs innerhalb des Automaten - `distance_mm` - Typ: Zahl - Pflichtfeld: ja - Bedeutung: gemessene Entfernung in Millimetern - `measured_at` - Typ: String - Pflichtfeld: nein - Bedeutung: Zeitstempel der Messung - Format: ISO-8601-kompatibel empfohlen ### Verhalten - Der Endpunkt akzeptiert nur `POST`. - Der Endpunkt beantwortet `OPTIONS` fuer Preflight-Requests mit `204 No Content`. - Bei fehlendem oder falschem Bearer-Token antwortet die API mit `401`. - Bei ungueltigem JSON antwortet die API mit `400`. - Bei ungueltigen Feldern antwortet die API mit `422`. - Wenn `machine_id` oder `sensor_id` nicht bekannt sind, antwortet die API mit `404`. - Bei erfolgreicher Verarbeitung wird `state.json` aktualisiert. - Bei einem Statuswechsel wird zusaetzlich Alarmierung ausgeloest. ### Erfolgsantwort Status: `200 OK` ```json { "ok": true, "machine_id": "automat-lobby", "sensor_id": "fach-a1", "slot_label": "A1", "units_estimated": 4, "fill_percent": 63, "state": "ok" } ``` ### Fehlerantworten #### Nicht autorisiert Status: `401 Unauthorized` ```json { "ok": false, "error": "Nicht autorisiert." } ``` #### Unbekannter Sensor oder Automat Status: `404 Not Found` ```json { "ok": false, "error": "Unbekannter Automat oder Sensor." } ``` #### Validierungsfehler Status: `422 Unprocessable Entity` ```json { "ok": false, "error": "distance_mm muss numerisch sein." } ``` #### Falsche Methode Status: `405 Method Not Allowed` ```json { "ok": false, "error": "Nur POST ist erlaubt." } ``` #### Ungueltiger JSON-Body Status: `400 Bad Request` ```json { "ok": false, "error": "Ungueltiger JSON-Body." } ``` #### Interner Fehler Status: `500 Internal Server Error` ```json { "ok": false, "error": "Interner Fehler." } ``` ### Beispiel mit `curl` ```bash curl -X POST http://localhost:8000/api/v1/readings.php \ -H 'Authorization: Bearer demo-esp32-token' \ -H 'Content-Type: application/json' \ -d '{ "machine_id": "automat-lobby", "sensor_id": "fach-a1", "distance_mm": 184 }' ``` ## Endpunkt: `GET /api/v1/status.php` Liefert den aktuellen Zustand der gesamten Anwendung. ### Verhalten - Der Endpunkt akzeptiert nur `GET`. - Es ist keine Authentifizierung implementiert. - Der Endpunkt wird vom Dashboard fuer die Auto-Aktualisierung genutzt. ### Erfolgsantwort Status: `200 OK` Beispielstruktur: ```json { "ok": true, "generated_at": "2026-04-15T20:10:00+00:00", "app": { "name": "Getraenkeautomat Monitor", "dashboard_refresh_seconds": 15 }, "summary": { "machine_count": 2, "slot_count": 3, "critical_count": 1 }, "machines": [ { "id": "automat-lobby", "name": "Lobby Automat", "location": "Erdgeschoss", "slots": [] } ], "alerts": [] } ``` ### Wichtige Felder in `machines[].slots[]` - `machine_id` - `machine_name` - `sensor_id` - `slot_label` - `product_name` - `fill_percent` - `units_estimated` - `max_units` - `distance_mm` - `state` - `measured_at` - `updated_at` - `alert_below_units` - `webhook_ids` - `email_ids` ### Wichtige Felder in `alerts[]` - `id` - `created_at` - `payload.event` - `payload.machine_id` - `payload.machine_name` - `payload.sensor_id` - `payload.slot_label` - `payload.product_name` - `payload.distance_mm` - `payload.units_estimated` - `payload.max_units` - `payload.fill_percent` - `payload.state` - `payload.previous_state` - `payload.measured_at` - `deliveries.webhooks[]` - `deliveries.emails[]` ### Falsche Methode Status: `405 Method Not Allowed` ```json { "ok": false, "error": "Nur GET ist erlaubt." } ``` ## CORS und Preflight `readings.php` beantwortet `OPTIONS` mit `204 No Content` und gibt folgende Header aus: - `Access-Control-Allow-Methods: POST, OPTIONS` - `Access-Control-Allow-Headers: Authorization, Content-Type` Falls Sensor-Clients aus einem anderen Netzsegment oder ueber Browser-Tools senden, ist das hilfreich. Eine vollstaendige CORS-Konfiguration mit `Access-Control-Allow-Origin` ist aktuell noch nicht Teil der App.