API.md 5.4 KB

API Reference

Diese Datei beschreibt die HTTP-Schnittstellen der Anwendung.

Swagger / OpenAPI

Zusätzlich zur textuellen Referenz gibt es jetzt zwei API-Dokumentationsziele in der laufenden Anwendung:

  • Swagger UI: /api-docs/
  • OpenAPI-Spec: /openapi.yaml

Beim lokalen Start mit php -S localhost:8000 sind die URLs:

  • http://localhost:8000/api-docs/
  • http://localhost:8000/openapi.yaml

Die OpenAPI-Datei ist handgeschrieben und dient als maschinenlesbare Quelle für die Swagger UI.

Basis

  • API-Stil: REST-nah
  • Datenformat: JSON
  • Authentifizierung für eingehende Messwerte: Bearer-Token
  • Charset: UTF-8

Endpunkt: POST /api/v1/readings.php

Nimmt genau einen Sensorwert für genau ein Fach entgegen.

Request-Header

  • Authorization: Bearer <token>
  • Content-Type: application/json

Request-Body

{
  "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 für Preflight-Requests mit 204 No Content.
  • Bei fehlendem oder falschem Bearer-Token antwortet die API mit 401.
  • Bei ungültigem JSON antwortet die API mit 400.
  • Bei ungültigen 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 zusätzlich Alarmierung ausgelöst.

Erfolgsantwort

Status: 200 OK

{
  "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

{
  "ok": false,
  "error": "Nicht autorisiert."
}

Unbekannter Sensor oder Automat

Status: 404 Not Found

{
  "ok": false,
  "error": "Unbekannter Automat oder Sensor."
}

Validierungsfehler

Status: 422 Unprocessable Entity

{
  "ok": false,
  "error": "distance_mm muss numerisch sein."
}

Falsche Methode

Status: 405 Method Not Allowed

{
  "ok": false,
  "error": "Nur POST ist erlaubt."
}

Ungültiger JSON-Body

Status: 400 Bad Request

{
  "ok": false,
  "error": "Ungültiger JSON-Body."
}

Interner Fehler

Status: 500 Internal Server Error

{
  "ok": false,
  "error": "Interner Fehler."
}

Beispiel mit curl

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
  }'

Bei einer Apache-Unterordner-Installation unter https://example.com/monitor/ lautet derselbe Endpunkt:

POST https://example.com/monitor/api/v1/readings.php

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 für die Auto-Aktualisierung genutzt.

Erfolgsantwort

Status: 200 OK

Beispielstruktur:

{
  "ok": true,
  "generated_at": "2026-04-15T20:10:00+00:00",
  "app": {
    "name": "Getränkeautomat 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": []
}

Bei einer Apache-Unterordner-Installation unter https://example.com/monitor/ lautet der Status-Endpunkt:

GET https://example.com/monitor/api/v1/status.php

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

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

{
  "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 über Browser-Tools senden, ist das hilfreich. Eine vollständige CORS-Konfiguration mit Access-Control-Allow-Origin ist aktuell noch nicht Teil der App.