MQTT-Display-LaserCutter/include/mqtt_client.h
MaPaLo76 7935dfbba4 feat(mqtt): reset_reason im Heartbeat-JSON hinzugefuegt
- esp_reset_reason() einmalig in begin() gespeichert (_resetReason[32])
- reset_reason-Feld in publishHeartbeat() JSON-Payload
- Moegliche Werte: POWERON, SOFTWARE, PANIC, TASK_WDT, INT_WDT, WDT, BROWNOUT, EXT_PIN, DEEPSLEEP, SDIO, UNKNOWN
- README.md: Status-JSON-Beispiel und Werteliste dokumentiert
2026-03-01 12:10:07 +01:00

113 lines
4.1 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
// =============================================================================
// mqtt_client.h - MQTT-Verbindung, Publish und Subscribe
// Projekt: MQTT-Display LaserCutter
//
// Wrapper um PubSubClient mit Non-Blocking Reconnect.
//
// Publish:
// publishSession() - beim Ende eines Laser-Bursts (aus LaserTracker)
// publishStatus() - Heartbeat alle MQTT_HEARTBEAT_MS
//
// Subscribe:
// lasercutter/reset - Payload "1" oder {"reset":true} -> laserTracker.resetTotal()
// Payload {"reset_session":true} -> laserTracker.resetSessionSum()
//
// Verwendung:
// mqttClient.begin(); // einmalig in setup(), nach WiFi-Connect
// mqttClient.loop(); // in jedem loop()-Aufruf
// =============================================================================
#include <Arduino.h>
#include <PubSubClient.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include "config.h"
#include "settings.h"
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include <esp_system.h>
// Session-Daten die per Queue von Core 1 -> Core 0 übergeben werden
struct SessionPayload {
int sessionSec;
int gratisSec;
time_t startTime; // exakter Startzeitpunkt bei Reconnect korrekt, nicht "jetzt"
uint32_t sessionId; // aufsteigender Zähler, Reset bei resetSessionSum/resetTotal
};
class MqttClient {
public:
MqttClient();
// MQTT konfigurieren und erste Verbindung versuchen (einmalig in setup())
void begin();
// No-Op: Reconnect, Heartbeat und Publish werden vom internen FreeRTOS-Task erledigt.
// Diese Methode bleibt im Interface, damit main.cpp unveraendert bleibt.
void loop();
// Publish: Session-Ende (wird von LaserTracker-Logik in main aufgerufen)
// lastSessionSec : Netto-Sekunden der letzten Session
// gratisSec : konfigurierte Gratiszeit
// JSON-Felder: session_minutes (ceiling int), session_seconds (raw), freetime_s, ip
void publishSession(int lastSessionSec, int gratisSec);
// Verbindungsstatus
bool isConnected();
// Session-Zähler zurücksetzen (bei reset / reset_session Kommando)
void resetSessionCounter();
// Debug-Ausgabe auf Serial
void printToSerial();
private:
// WICHTIG: Diese Objekte werden als nullptr initialisiert und erst in
// _taskLoop() auf Core 0 per 'new' angelegt. mbedtls/WiFiClientSecure
// bindet Heap-Kontexte an den erstellenden Task/Core daher KEIN
// Anlegen im globalen Konstruktor (Core 1)!
WiFiClient* _wifiClient;
WiFiClientSecure* _secureClient;
PubSubClient* _client;
uint32_t _lastReconnectMs;
uint32_t _lastHeartbeatMs;
char _clientId[32]; // MQTT_CLIENT_ID + MAC-Suffix (eindeutig auf Public Broker)
// FreeRTOS-Task: laeuft auf Core 0, erledigt Reconnect/Heartbeat/Publish
TaskHandle_t _taskHandle;
// Session-Queue: Core 1 schreibt per publishSession(), Core 0 liest und publiziert.
// 128 Slots = Worst Case ~2h Offline bei 1 Session/min. ~2 KB RAM.
QueueHandle_t _sessionQueue;
// Aufsteigender Session-Zähler; Reset bei resetSessionSum/resetTotal
// Zugriff nur von Core 1 (publishSession) → kein Mutex nötig
uint32_t _sessionCounter;
// Neustart-Grund (einmalig in begin() gespeichert, bevor er überschrieben wird)
char _resetReason[32];
// Verbindungsaufbau (blockierend - NUR aus MQTT-Task auf Core 0 aufrufen!)
bool reconnect();
// Heartbeat-Publish (lasercutter/status)
void publishHeartbeat();
// Eigentlicher Session-Publish (aus MQTT-Task auf Core 0)
// Gibt true zurück wenn Publish erfolgreich, false bei Fehler (Queue-Eintrag bleibt dann erhalten)
bool _doPublishSession(int lastSessionSec, int gratisSec, time_t startTime, uint32_t sessionId);;
// FreeRTOS-Task
static void _taskFn(void* param);
void _taskLoop();
// Callback fuer eingehende Nachrichten (static wegen PubSubClient-API)
static void onMessage(const char* topic, byte* payload, unsigned int length);
};
// Globale Instanz
extern MqttClient mqttClient;