#pragma once #if defined(WITH_MQTT) || defined(WITH_ETHERNET) #include #include #include #include #include #include #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