meshcore-repeater/src/MQTTBridge.h
Ryan Malloy 7516c808a7 Add ENC28J60 Ethernet support with INetworkManager abstraction
- Create INetworkManager interface for network abstraction
- Add EthernetManager for ENC28J60 module using EthernetENC library
- Update WiFiManager to implement INetworkManager interface
- Update MQTTBridge to use INetworkManager* instead of WiFiManager&
- Add heltec_v3_ethernet PlatformIO environment
- Uses HSPI bus (GPIO 19/20/47/48) separate from LoRa SPI
2026-02-05 09:45:16 -07:00

126 lines
3.5 KiB
C++

#pragma once
#if defined(WITH_MQTT) || defined(WITH_ETHERNET)
#include <Arduino.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <Mesh.h>
#include "INetworkManager.h"
// Forward declarations
struct NodePrefs;
// MQTT connection states
enum class MQTTState {
DISCONNECTED,
CONNECTING,
CONNECTED,
ERROR
};
// MQTT configuration
struct MQTTConfig {
char broker[64];
uint16_t port;
char user[32];
char password[64];
char topic_prefix[32];
char client_id[24];
uint8_t enabled;
uint8_t use_tls;
uint16_t keepalive_secs;
uint16_t publish_interval_ms;
};
class MQTTBridge {
public:
MQTTBridge(INetworkManager* network, mesh::PacketManager* mgr, mesh::RTCClock* rtc);
void begin(const MQTTConfig& config, const uint8_t* self_pubkey);
void loop();
void end();
MQTTState getState() const { return _state; }
bool isConnected() const { return _state == MQTTState::CONNECTED; }
bool isEnabled() const { return _config.enabled; }
void updateConfig(const MQTTConfig& config);
// Publish methods
void publishStatus();
void publishStats(uint32_t uptime_secs, uint32_t packets_rx, uint32_t packets_tx,
uint32_t air_time_secs, int16_t noise_floor);
void publishPacketRx(mesh::Packet* pkt, int len, float snr, float rssi);
void publishPacketTx(mesh::Packet* pkt, int len);
void publishAdvert(const uint8_t* pubkey, uint32_t timestamp,
const uint8_t* app_data, size_t app_data_len);
const char* getBroker() const { return _config.broker; }
uint16_t getPort() const { return _config.port; }
uint32_t getMessagesSent() const { return _messages_sent; }
uint32_t getMessagesReceived() const { return _messages_received; }
uint32_t getReconnectCount() const { return _reconnect_count; }
using CommandCallback = void (*)(const char* topic, const uint8_t* payload, size_t len);
void setCommandCallback(CommandCallback cb) { _command_callback = cb; }
private:
INetworkManager* _network;
WiFiClient _wifi_client; // Works for both WiFi and Ethernet!
WiFiClientSecure _wifi_client_secure;
PubSubClient _mqtt_client;
MQTTConfig _config;
MQTTState _state;
mesh::PacketManager* _mgr;
mesh::RTCClock* _rtc;
uint8_t _self_pubkey[32];
char _gateway_id[17];
unsigned long _last_connect_attempt;
unsigned long _last_status_publish;
unsigned long _last_stats_publish;
unsigned long _connected_since;
uint32_t _messages_sent;
uint32_t _messages_received;
uint32_t _reconnect_count;
// Deduplication
static const size_t HASH_TABLE_SIZE = 64;
uint32_t _seen_hashes[HASH_TABLE_SIZE];
size_t _hash_index;
CommandCallback _command_callback;
bool _initialized;
// Topic buffers
char _topic_status[80];
char _topic_packets_rx[80];
char _topic_packets_tx[80];
char _topic_adverts[80];
char _topic_stats[80];
char _topic_cmd_prefix[80];
void attemptConnection();
void setupTopics();
void subscribeToCommands();
void publishMessage(const char* topic, const char* payload, bool retained = false);
void publishJson(const char* topic, JsonDocument& doc, bool retained = false);
static uint32_t fnv1a_hash(const uint8_t* data, size_t len);
bool isDuplicate(const uint8_t* data, size_t len);
// Static callback for PubSubClient
static void mqttCallback(char* topic, uint8_t* payload, unsigned int length);
static MQTTBridge* _instance;
void handleMessage(char* topic, uint8_t* payload, unsigned int length);
const char* getTimestamp();
};
#endif // WITH_MQTT || WITH_ETHERNET