- 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
126 lines
3.5 KiB
C++
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
|