MQTT-Display-LaserCutter/include/mqtt_client.h
MaPaLo76 b91b3ca96f fix(mqtt): Netzwerk-Objekte per new auf Core 0 anlegen - Heap-Korruption behoben
- WiFiClient, WiFiClientSecure, PubSubClient als Pointer deklariert (nullptr init)
- Objekte werden erst in _taskLoop() auf Core 0 per 'new' erstellt
- mbedtls bindet Heap-Allokationen an den erstellenden Core/Task
  -> Anlegen auf Core 1 (globaler Konstruktor) + Nutzung auf Core 0 = Heap-Korruption
  -> Fix: Anlegen UND Nutzung ausschliesslich auf Core 0
- isConnected(), printToSerial(): Null-Checks ergaenzt
2026-02-28 19:05:09 +01:00

93 lines
3.2 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>
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();
// 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;
// Pending-Session-Daten: von Core 1 (main) gesetzt, von Core 0 (Task) gelesen
volatile bool _pendingSession;
volatile int _pendingSessionSec;
volatile int _pendingGratisSec;
// 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)
void _doPublishSession(int lastSessionSec, int gratisSec);
// 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;