Sin descripción

Josef Straßl 326201c7fd Add shared hosting deployment documentation hace 1 mes
data 0fed6302d7 initial commit hace 1 mes
docs 326201c7fd Add shared hosting deployment documentation hace 1 mes
public 14b52d18b6 adding swagger docs hace 1 mes
src 0fed6302d7 initial commit hace 1 mes
README.md 326201c7fd Add shared hosting deployment documentation hace 1 mes

README.md

Getraenkeautomat Monitor

Getraenkeautomat Monitor ist eine kleine PHP/HTML/JS-Anwendung zur Ueberwachung von Fuellstaenden in Getraenkeautomaten. Ein ESP32 oder ein anderer Sensor-Client sendet Messwerte an eine einfache REST-nahe API. Die Anwendung berechnet daraus den geschaetzten Bestand pro Fach, visualisiert den aktuellen Status im Browser und loest bei kritischen Schwellwerten Alarme aus.

Die Anwendung ist bewusst simpel gehalten:

  • Backend mit plain PHP
  • Frontend mit HTML, CSS und Vanilla JavaScript
  • Persistenz nur in JSON-Dateien
  • keine Datenbank
  • kein Framework

Dokumentation

Funktionsumfang

  • mehrere Automaten in einer Instanz
  • mehrere Faecher pro Automat
  • REST-nahe Eingangs-API fuer Einzelmessungen
  • Dashboard mit visueller Fuellstandsanzeige
  • Alarmierung per Webhook und per Email
  • Adminpanel zur Bearbeitung der JSON-Config
  • statischer Admin-Login mit bcrypt-Hash

Architektur im Ueberblick

Der Datenfluss ist einfach:

  1. Ein Sensor-Client sendet einen Messwert in Millimetern an POST /api/v1/readings.php.
  2. Die Anwendung sucht das passende Fach ueber machine_id und sensor_id.
  3. Aus full_distance_mm, empty_distance_mm und distance_per_unit werden Fuellstand und Flaschenanzahl berechnet.
  4. Der letzte bekannte Zustand wird in data/state.json gespeichert.
  5. Wenn sich der Status von ok nach critical oder von critical nach ok aendert, wird ein Alarmereignis erzeugt.
  6. Dashboard und Adminpanel lesen den aktuellen Zustand ueber GET /api/v1/status.php.

Projektstruktur

  • public/
    • Webroot der Anwendung
    • enthaelt Dashboard, Adminpanel, CSS, JavaScript und API-Endpunkte
  • src/
    • Kernlogik der Anwendung
    • Konfigurationszugriff, Zustandsberechnung, Alarmierung, Authentifizierung
  • data/
    • JSON-Dateien fuer Konfiguration, aktuellen Zustand und Alarmhistorie

Wichtige Dateien:

  • public/index.php: Dashboard
  • public/admin/index.php: Login und Adminpanel
  • public/api/v1/readings.php: API fuer eingehende Sensorwerte
  • public/api/v1/status.php: Status-API fuer Dashboard und Adminpanel
  • src/MonitorService.php: zentrale Orchestrierung fuer Lesen, Berechnen und Status
  • src/InventoryService.php: Berechnung von Fuellgrad und Bestand
  • src/AlertService.php: Webhook- und Email-Alarmierung
  • data/config.json: Hauptkonfiguration
  • data/state.json: letzter bekannter Zustand je Fach
  • data/alert_log.json: Alarm- und Entwarnungsereignisse

Voraussetzungen

Fuer den Betrieb wird auf dem Zielsystem benoetigt:

  • PHP 8.1 oder neuer empfohlen
  • Schreibrechte auf data/
  • funktionierende Mail-Konfiguration, falls mail() fuer Email-Alarme genutzt werden soll
  • Webserver oder PHP Built-in Server

Schnellstart

Sobald PHP auf dem Zielsystem installiert ist:

php -S localhost:8000 -t public

Danach ist die Anwendung erreichbar unter:

  • Dashboard: http://localhost:8000/
  • Adminpanel: http://localhost:8000/admin/
  • Status-API: http://localhost:8000/api/v1/status.php
  • Swagger UI: http://localhost:8000/docs/
  • OpenAPI-Spec: http://localhost:8000/openapi.yaml

Default-Zugangsdaten

Die Beispiel-Konfiguration bringt absichtlich einfache Startwerte mit:

  • Admin-Benutzer: admin
  • Admin-Passwort: admin123
  • API-Bearer-Token: demo-esp32-token

Diese Werte sollten direkt nach dem ersten Login angepasst werden.

Dashboard

Das Dashboard ist die oeffentliche Visualisierung der Anlage. Es zeigt:

  • Anzahl Automaten, Faecher und aktuell kritische Faecher
  • Filter nach Automat
  • pro Fach:
    • Label
    • Produktname
    • visuellen Fuellstand
    • geschaetzte Anzahl Flaschen
    • Alarmgrenze
    • letzten Messwert in Millimetern
    • letzten Messzeitpunkt
  • letzte Alarm- und Entwarnungsereignisse

Die Daten werden regelmaessig per Polling ueber status.php aktualisiert. Das Intervall wird in config.json ueber app.dashboard_refresh_seconds gesteuert.

Adminpanel

Das Adminpanel ist ueber /admin/ erreichbar und erlaubt:

  • Aendern des App-Namens und des Refresh-Intervalls
  • Aendern des API-Bearer-Tokens
  • Aendern von Admin-Benutzername und Passwort
  • Verwalten von Webhooks
  • Verwalten von Email-Empfaengern
  • Verwalten von Automaten und ihren Faechern

Beim Speichern des Admin-Passworts wird immer ein bcrypt-Hash erzeugt. Das Passwort selbst wird nicht im Klartext gespeichert.

Alarmverhalten

Alarme werden nicht bei jeder eingehenden kritischen Messung ausgeloest, sondern nur bei Zustandswechseln:

  • ok -> critical: Alarm
  • critical -> ok: Entwarnung
  • critical -> critical: kein weiterer Alarm
  • ok -> ok: kein Alarm

Dadurch werden doppelte Daueralarme vermieden.

Ein Fach gilt als kritisch, wenn gilt:

units_estimated < alert_below_units

Ein Fach mit alert_below_units = 2 loest also erst dann Alarm aus, wenn nur noch 1 oder 0 Einheiten geschaetzt werden.

Wie die Bestandsberechnung funktioniert

Jedes Fach hat drei wichtige Kalibrierwerte:

  • full_distance_mm
  • empty_distance_mm
  • distance_per_unit

Die App behandelt full_distance_mm als 100 Prozent und empty_distance_mm als 0 Prozent. Dabei ist es egal, ob kleinere oder groessere Zahlen "voll" bedeuten, weil die Berechnung die Sensororientierung automatisch beruecksichtigt.

Die grobe Logik ist:

fill_ratio = (distance_mm - empty_distance_mm) / (full_distance_mm - empty_distance_mm)
fill_ratio wird auf 0..1 begrenzt
max_units = abs(full_distance_mm - empty_distance_mm) / distance_per_unit
units_estimated = round(fill_ratio * max_units)

Damit repraesentiert distance_per_unit die Aenderung des Messwerts pro Flasche oder Einheit.

API-Referenz

Die API ist jetzt auf drei Ebenen dokumentiert:

  • Interaktive Swagger UI unter http://localhost:8000/docs/
  • Maschinenlesbare OpenAPI-Spec unter http://localhost:8000/openapi.yaml
  • Erlaeuternde Referenz in docs/API.md

POST /api/v1/readings.php

Nimmt genau einen Messwert entgegen.

Header:

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

Body:

{
  "machine_id": "automat-lobby",
  "sensor_id": "fach-a1",
  "distance_mm": 184,
  "measured_at": "2026-04-15T19:20:00Z"
}

measured_at ist optional. Wenn der Wert fehlt, setzt der Server die aktuelle Zeit.

Beispiel:

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,
    "measured_at": "2026-04-15T19:20:00Z"
  }'

Erfolg:

{
  "ok": true,
  "machine_id": "automat-lobby",
  "sensor_id": "fach-a1",
  "slot_label": "A1",
  "units_estimated": 4,
  "fill_percent": 63,
  "state": "ok"
}

GET /api/v1/status.php

Liefert den aktuellen aggregierten Zustand aller Automaten und Faecher inklusive letzter Alarmereignisse.

Konfiguration

Die Konfiguration liegt in data/config.json. Eine detaillierte Beschreibung aller Felder steht in docs/CONFIG.md.

Die obersten Bereiche sind:

  • app: Name, Zeitzone, UI-Refresh, Email-Absender
  • api: Bearer-Token fuer Sensor-Clients
  • admin: Benutzername und Passwort-Hash
  • alerts: wiederverwendbare Webhooks und Email-Empfaenger
  • machines: Automaten mit ihren Faechern

Zustandsdateien

data/state.json

Diese Datei enthaelt den letzten bekannten Zustand jedes Fachs. Sie wird von der API bei jeder gueltigen Messung aktualisiert.

Typische Inhalte:

  • letzter Messwert
  • letzter Messzeitpunkt
  • geschaetzter Bestand
  • maximaler Bestand
  • aktueller Status
  • verknuepfte Alarmkanal-IDs

data/alert_log.json

Diese Datei enthaelt die zuletzt ausgeloesten Alarmereignisse und Entwarnungen inklusive Lieferstatus fuer Webhooks und Emails.

JSON-Persistenz und Dateisperren

Die Anwendung nutzt fuer Schreibzugriffe Dateisperren ueber flock(). Das reduziert das Risiko beschaedigter JSON-Dateien bei parallelen Requests, zum Beispiel wenn mehrere Sensoren fast gleichzeitig Messwerte senden.

Betriebshinweise

  • data/ sollte nicht direkt oeffentlich ueber den Webserver auslieferbar sein.
  • Das Bearer-Token sollte nur an bekannte Sensor-Clients verteilt werden.
  • Die Beispiel-Zugangsdaten sollten in echten Umgebungen sofort ersetzt werden.
  • Webhooks sollten mit HTTPS betrieben werden.
  • Email funktioniert nur, wenn mail() auf dem Zielsystem korrekt eingerichtet ist.

Typische Erweiterungen fuer spaetere Versionen

  • Batch-Endpoint fuer mehrere Sensorwerte in einem Request
  • Langzeithistorie mit Zeitreihen oder Charts
  • Benutzerverwaltung statt statischem Admin-Login
  • Retry-Mechanismus fuer fehlgeschlagene Webhooks
  • Healthcheck-Endpunkte
  • CSV- oder PDF-Export

Weitere Dokumentation