|
|
пре 1 месец | |
|---|---|---|
| admin | пре 1 месец | |
| api | пре 1 месец | |
| api-docs | пре 1 месец | |
| data | пре 1 месец | |
| docs | пре 1 месец | |
| src | пре 1 месец | |
| .gitignore | пре 1 месец | |
| .htaccess | пре 1 месец | |
| README.md | пре 1 месец | |
| app.js | пре 1 месец | |
| index.php | пре 1 месец | |
| openapi.yaml | пре 1 месец | |
| styles.css | пре 1 месец |
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:
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 Fuellstand und Flaschenanzahl berechnet.data/state.json gespeichert.ok nach critical oder von critical nach ok aendert, 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/
.htaccess gesperrtdocs/
.htaccess gesperrtWichtige Dateien:
index.php: Dashboardadmin/index.php: Login und Adminpanelapi/v1/readings.php: API fuer eingehende Sensorwerteapi/v1/status.php: Status-API fuer Dashboard und Adminpanelapi-docs/index.html: Swagger UIopenapi.yaml: OpenAPI-Specsrc/MonitorService.php: zentrale Orchestrierung fuer Lesen, Berechnen und Statussrc/InventoryService.php: Berechnung von Fuellgrad und Bestandsrc/AlertService.php: Webhook- und Email-Alarmierungdata/config.json: Hauptkonfigurationdata/state.json: letzter bekannter Zustand je Fachdata/alert_log.json: Alarm- und EntwarnungsereignisseFuer den Betrieb wird auf dem Zielsystem benoetigt:
data/.htaccess-Support fuer die Produktionsbereitstellungmail() fuer Email-Alarme genutzt werden sollSobald 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 geschuetzt.
Die Beispiel-Konfiguration bringt absichtlich einfache Startwerte mit:
adminadmin123demo-esp32-tokenDiese Werte sollten direkt nach dem ersten Login angepasst werden.
Das Dashboard ist die oeffentliche Visualisierung der Anlage. Es zeigt:
Die Daten werden regelmaessig per Polling ueber status.php aktualisiert. Das Intervall wird in config.json ueber app.dashboard_refresh_seconds gesteuert.
Das Adminpanel ist ueber /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 ausgeloest, 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 loest also erst dann Alarm aus, wenn nur noch 1 oder 0 Einheiten geschaetzt 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 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.
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 Faecher 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 fuer Sensor-Clientsadmin: Benutzername und Passwort-Hashalerts: wiederverwendbare Webhooks und Email-Empfaengermachines: Automaten mit ihren Faecherndata/state.jsonDiese Datei enthaelt den letzten bekannten Zustand jedes Fachs. Sie wird von der API bei jeder gueltigen Messung aktualisiert.
Typische Inhalte:
data/alert_log.jsonDiese Datei enthaelt die zuletzt ausgeloesten Alarmereignisse und Entwarnungen inklusive Lieferstatus fuer Webhooks und Emails.
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.
data/ sollte nicht direkt oeffentlich ueber den Webserver auslieferbar sein.mail() auf dem Zielsystem korrekt eingerichtet ist.