MQTT-Display-LaserCutter/include/laser_tracker.h
MaPaLo76 99b5c25e37 feat(tracker): resetSessionSum + MQTT reset_session + UI-Verbesserungen
- resetSession() umbenannt in resetSessionSum() (klarere Semantik)
- Bug fix: resetSessionSum() setzt laufende Session-Timer korrekt zurueck
  (vorher: getAllSessionsSumMinutes() blieb > 0 nach Reset)
- consumeSessionReset() nach consumeSessionEnd()-Muster (consume-Semantik)
- Vor Reset: akkumulierte Netto-Sekunden sichern -> publishSession() wie Session-Ende
- MQTT: payload {reset_session:true} via lasercutter/reset loest resetSessionSum() aus
- MQTT: Session-Reset publiziert identisches JSON wie normales Session-Ende
- Web: Button-Layout ueberarbeitet (alle 3 Buttons blau, uebereinander, gleich breit)
- Docs: README.md + Implementation-Plan.md aktualisiert
2026-02-23 22:49:30 +01:00

139 lines
6.0 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
// =============================================================================
// laser_tracker.h - Laser-Signaldetektion, Debounce & Zeitmessung
// Projekt: MQTT-Display LaserCutter
//
// Zwei getrennte Zeitkreise:
// SESSION (RAM, reset bei Neustart / resetSession()):
// Minuten-Anzeige auf dem Display. Akkumuliert Netto-Sekunden aller
// Sessions der aktuellen Betriebssitzung.
// Jede Session startet mit einem Gratis-Countdown.
// Erst nach Ablauf der Gratiszeit zaehlt die Zeit zur Session.
// Minuten-Inkrement: erst nach vollen 60 Netto-Sekunden (hart).
//
// GESAMT (NVS, persistiert):
// Lifetime-Gesamtzeit fuer Wartungsstatistiken / Web-UI.
// Wird nur nach jeder abgeschlossenen Session aktualisiert.
// Wird NICHT auf dem Display angezeigt.
//
// Anzeige-Logik:
// Module 1-3 (oben): getAllSessionsSumMinutes() - Summe aller Sessions seit Reset
// Module 5-7 (unten): getCountdownRemaining() > 0 -> Countdown anzeigen
// sonst -> showIdle()
//
// Verwendung:
// laserTracker.begin(); // einmalig in setup()
// laserTracker.loop(); // in jedem loop()-Aufruf
// laserTracker.getAllSessionsSumMinutes(); // fuer Display Module 1-3
// laserTracker.getCountdownRemaining();// fuer Display Module 5-7
// laserTracker.resetSession(); // per MQTT / Web-Reset
// =============================================================================
#include <Arduino.h>
#include <time.h>
#include "config.h"
#include "settings.h"
// Session-Zustaende (eine "Session" = ein Laser-AN-Ereignis)
enum class SessionState {
INACTIVE, // Laser aus
GRATIS, // Laser an, Gratiszeit laeuft
NET_COUNTING, // Laser an, Gratiszeit abgelaufen, Netto-Zeit wird gezaehlt
};
class LaserTracker {
public:
LaserTracker();
// GPIO konfigurieren, NVS laden (einmalig in setup())
void begin();
// Debounce + Burst-Zustandsmaschine - in jedem loop()-Aufruf aufrufen
void loop();
// ---- Display-Getter -----------------------------------------------------
// Summe aller Sessions seit Neustart/resetSession() in ganzen Minuten
// Entspricht: Summe Netto-Sekunden aller Sessions / 60 (hart, ganzzahlig)
int getAllSessionsSumMinutes() const;
// Verbleibende Gratiszeit des aktuellen Bursts in Sekunden
// 0 wenn: Gratiszeit abgelaufen, Laser aus, oder NET_COUNTING
int getCountdownRemaining() const;
// ---- Zustandsabfragen ---------------------------------------------------
// true = Laser ist physisch aktiv (nach Debounce)
bool isActive() const;
// Lifetime-Gesamtzeit aus NVS (fuer Web-UI / MQTT, nicht fuer Display)
float getTotalMinutes() const;
// Netto-Sekunden des zuletzt abgeschlossenen Session (fuer MQTT Publish)
int getLastSessionSeconds() const;
// Laufende Netto-Sekunden der aktuellen Session (live, waehrend NET_COUNTING)
// 0 wenn GRATIS oder INACTIVE
int getRunningSessionSeconds() const;
// Unix-Timestamp (UTC) des letzten Session-Starts (0 wenn noch keine Session)
time_t getSessionStartTime() const;
// ---- Reset --------------------------------------------------------------
// Session-Summe auf 0 (RAM). NVS-Gesamtzeit bleibt unveraendert.
// Setzt Minuten, Sekunden und laufende Session-Timer zurueck.
// Aufruf: automatisch in begin(), per MQTT oder Weboberflaeche.
void resetSessionSum();
// Gesamtzeit (NVS + RAM-Session) auf 0 zuruecksetzen (Wartungsreset)
void resetTotal();
// Prueft ob seit dem letzten Aufruf eine Session beendet wurde ("consume").
// Gibt true zurueck, wenn eine neue Session abgeschlossen ist danach
// kann getLastSessionSeconds() + getTotalMinutes() sicher gelesen werden.
// Wird in main.cpp fuer mqttClient.publishSession() verwendet.
bool consumeSessionEnd();
// Prueft ob seit dem letzten Aufruf ein Session-Reset ausgeloest wurde.
// Gibt true zurueck wenn resetSessionSum() aufgerufen wurde.
// Wird in main.cpp genutzt um die akkumulierten Sekunden via publishSession() zu senden.
bool consumeSessionReset();
// Debug-Ausgabe auf Serial
void printToSerial() const;
private:
// ---- Debounce -----------------------------------------------------------
bool _debouncedActive; // bestaedigter Laser-Zustand
bool _pendingActive; // zu bestaetigender Zustand
bool _debounceRunning; // laeuft gerade ein Debounce-Fenster
uint32_t _debounceStartMs;
// ---- Session-Zustand ---------------------------------------------------
SessionState _state; // aktueller Session-Zustand
uint32_t _sessionStartMs; // millis() beim Laser-AN (Session-Start)
time_t _sessionStartTime; // Unix-Timestamp (UTC) beim Laser-AN
uint32_t _netStartMs; // millis() beim Uebergang GRATIS -> NET_COUNTING
// ---- Zeitakkumulatoren --------------------------------------------------
int _sessionNetSec; // Netto-Sekunden der Session (RAM, 0 nach begin/resetSession)
int _sessionNetMin; // Aufgerundete Minuten je Session aufsummiert (Ceiling pro Session)
float _totalMinutesBase; // NVS-Gesamtzeit (nach jedem Burst aktualisiert)
int _lastSessionSec; // Netto-Sekunden der letzten abgeschlossenen Session
bool _sessionEndPending; // true = Session gerade beendet, noch nicht consumed
bool _sessionResetPending; // true = resetSessionSum() wurde aufgerufen, noch nicht consumed
// ---- Hilfsmethoden ------------------------------------------------------
bool readRaw() const; // GPIO lesen + Polaritaet anwenden
void onSessionStart(); // Laser AN (nach Debounce)
void onSessionEnd(); // Laser AUS (nach Debounce)
int gratisSeconds() const; // Gratiszeit aus Settings
// Laufende Netto-Sekunden der aktuellen Session (0 wenn GRATIS oder INACTIVE)
int currentSessionNetSec() const;
};
// Globale Instanz
extern LaserTracker laserTracker;