- 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
93 lines
3.2 KiB
C++
93 lines
3.2 KiB
C++
#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; |