|
|
1 bulan lalu | |
|---|---|---|
| admin | 1 bulan lalu | |
| api | 1 bulan lalu | |
| api-docs | 1 bulan lalu | |
| data | 1 bulan lalu | |
| docs | 1 bulan lalu | |
| src | 1 bulan lalu | |
| .gitignore | 1 bulan lalu | |
| .htaccess | 1 bulan lalu | |
| README.md | 1 bulan lalu | |
| app.js | 1 bulan lalu | |
| index.php | 1 bulan lalu | |
| openapi.yaml | 1 bulan lalu | |
| setup_testenv.sh | 1 bulan lalu | |
| styles.css | 1 bulan lalu |
Getränkeautomat Monitor ist eine kleine PHP/HTML/JS-Anwendung zur Überwachung von Füllständen in Getränkeautomaten. Ein ESP32 oder ein anderer Sensor-Client sendet Messwerte an eine einfache REST-nahe API. Die Anwendung berechnet daraus den geschätzten Bestand pro Fach, visualisiert den aktuellen Status im Browser und löst bei kritischen Schwellwerten Alarme aus.
Die Anwendung ist bewusst simpel gehalten:
Der Datenfluss ist einfach:
POST /api/v1/readings.php.machine_id und sensor_id.full_distance_mm, empty_distance_mm und distance_per_unit werden Füllstand und Flaschenanzahl berechnet.data/state.json gespeichert.ok nach critical oder von critical nach ok ändert, wird ein Alarmereignis erzeugt.GET /api/v1/status.php.Die Anwendung ist jetzt so aufgebaut, dass der gesamte Projektordner direkt als Apache-Unterordner deployt werden kann.
index.php, admin/, api/, api-docs/, app.js, styles.css, openapi.yaml
src/
.htaccess gesperrtdata/
php_errors.log für PHP-Fehler.htaccess gesperrtdocs/
.htaccess gesperrtWichtige Dateien:
index.php: Dashboardadmin/index.php: Login und Adminpanelapi/v1/readings.php: API für eingehende Sensorwerteapi/v1/status.php: Status-API für Dashboard und Adminpanelapi-docs/index.html: Swagger UIopenapi.yaml: OpenAPI-Specsrc/MonitorService.php: zentrale Orchestrierung für Lesen, Berechnen und Statussrc/InventoryService.php: Berechnung von Füllgrad und Bestandsrc/AlertService.php: Webhook- und Email-Alarmierungdata/config.json: Hauptkonfigurationdata/state.json: letzter bekannter Zustand je Fachdata/alert_log.json: Alarm- und Entwarnungsereignissedata/php_errors.log: PHP-Fehlerlog der AnwendungFür den Betrieb wird auf dem Zielsystem benötigt:
data/.htaccess-Support für die Produktionsbereitstellungmail() für Email-Alarme genutzt werden sollPHP schreibt Laufzeitfehler in data/php_errors.log.
Sobald PHP auf dem Zielsystem installiert ist:
php -S localhost:8000
Danach ist die Anwendung erreichbar unter:
http://localhost:8000/http://localhost:8000/admin/http://localhost:8000/api/v1/status.phphttp://localhost:8000/api-docs/http://localhost:8000/openapi.yamlHinweis: Der PHP Built-in Server wertet .htaccess nicht aus. Die Verzeichnisse src/, data/ und docs/ werden auf Shared Hosting erst durch Apache geschützt.
Die Beispiel-Konfiguration bringt absichtlich einfache Startwerte mit:
adminadmin123demo-esp32-tokenDiese Werte sollten direkt nach dem ersten Login angepasst werden.
Das Dashboard ist die öffentliche Visualisierung der Anlage. Es zeigt:
Die Daten werden regelmäßig per Polling über status.php aktualisiert. Das Intervall wird in config.json über app.dashboard_refresh_seconds gesteuert.
Das Adminpanel ist über /admin/ erreichbar und erlaubt:
Beim Speichern des Admin-Passworts wird immer ein bcrypt-Hash erzeugt. Das Passwort selbst wird nicht im Klartext gespeichert.
Alarme werden nicht bei jeder eingehenden kritischen Messung ausgelöst, sondern nur bei Zustandswechseln:
ok -> critical: Alarmcritical -> ok: Entwarnungcritical -> critical: kein weiterer Alarmok -> ok: kein AlarmDadurch werden doppelte Daueralarme vermieden.
Ein Fach gilt als kritisch, wenn gilt:
units_estimated < alert_below_units
Ein Fach mit alert_below_units = 2 löst also erst dann Alarm aus, wenn nur noch 1 oder 0 Einheiten geschätzt werden.
Jedes Fach hat drei wichtige Kalibrierwerte:
full_distance_mmempty_distance_mmdistance_per_unitDie App behandelt full_distance_mm als 100 Prozent und empty_distance_mm als 0 Prozent. Dabei ist es egal, ob kleinere oder größere Zahlen "voll" bedeuten, weil die Berechnung die Sensororientierung automatisch berücksichtigt.
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 repräsentiert distance_per_unit die Änderung des Messwerts pro Flasche oder Einheit.
Die API ist jetzt auf drei Ebenen dokumentiert:
http://localhost:8000/api-docs/http://localhost:8000/openapi.yamlPOST /api/v1/readings.phpNimmt genau einen Messwert entgegen.
Header:
Authorization: Bearer <token>Content-Type: application/jsonBody:
{
"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.phpLiefert den aktuellen aggregierten Zustand aller Automaten und Fächer inklusive letzter Alarmereignisse.
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-Absenderapi: Bearer-Token für Sensor-Clientsadmin: Benutzername und Passwort-Hashalerts: wiederverwendbare Webhooks und Email-Empfängermachines: Automaten mit ihren Fächerndata/state.jsonDiese Datei enthält den letzten bekannten Zustand jedes Fachs. Sie wird von der API bei jeder gültigen Messung aktualisiert.
Typische Inhalte:
data/alert_log.jsonDiese Datei enthält die zuletzt ausgelösten Alarmereignisse und Entwarnungen inklusive Lieferstatus für Webhooks und Emails.
Die Anwendung nutzt für Schreibzugriffe Dateisperren über flock(). Das reduziert das Risiko beschädigter JSON-Dateien bei parallelen Requests, zum Beispiel wenn mehrere Sensoren fast gleichzeitig Messwerte senden.
data/ sollte nicht direkt öffentlich über den Webserver auslieferbar sein.mail() auf dem Zielsystem korrekt eingerichtet ist.