Compare commits
No commits in common. "main" and "fix/mqtt-exponential-backoff" have entirely different histories.
main
...
fix/mqtt-e
@ -46,11 +46,10 @@ void MQTTBridge::begin(const MQTTConfig& config, const uint8_t* self_pubkey) {
|
||||
if (_config.use_tls) {
|
||||
_wifi_client_secure.setInsecure(); // Skip cert verification
|
||||
_mqtt_client.setClient(_wifi_client_secure);
|
||||
Serial.println("[MQTT] TLS enabled");
|
||||
Serial.println("[MQTT] WARNING: Certificate verification DISABLED - vulnerable to MITM attacks!");
|
||||
Serial.printf("[MQTT] TLS enabled\n");
|
||||
} else {
|
||||
_mqtt_client.setClient(_wifi_client);
|
||||
Serial.println("[MQTT] Plain TCP (no encryption)");
|
||||
Serial.printf("[MQTT] Plain TCP\n");
|
||||
}
|
||||
|
||||
_mqtt_client.setServer(_config.broker, _config.port);
|
||||
@ -75,7 +74,7 @@ void MQTTBridge::loop() {
|
||||
if (!_network->isConnected()) {
|
||||
if (_state == MQTTState::CONNECTED) {
|
||||
_state = MQTTState::DISCONNECTED;
|
||||
Serial.println("[MQTT] Network connection lost, disconnecting");
|
||||
Serial.println("[MQTTS] WiFi lost, disconnected");
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -94,7 +93,7 @@ void MQTTBridge::loop() {
|
||||
case MQTTState::CONNECTED:
|
||||
if (!_mqtt_client.connected()) {
|
||||
_state = MQTTState::DISCONNECTED;
|
||||
Serial.println("[MQTT] Connection lost");
|
||||
Serial.println("[MQTTS] Connection lost");
|
||||
_last_connect_attempt = millis();
|
||||
// Don't reset backoff on connection loss - broker might be down
|
||||
} else {
|
||||
@ -130,7 +129,7 @@ void MQTTBridge::end() {
|
||||
|
||||
_state = MQTTState::DISCONNECTED;
|
||||
_initialized = false;
|
||||
Serial.println("[MQTT] Stopped");
|
||||
Serial.println("[MQTTS] Stopped");
|
||||
}
|
||||
|
||||
void MQTTBridge::attemptConnection() {
|
||||
@ -139,7 +138,7 @@ void MQTTBridge::attemptConnection() {
|
||||
_state = MQTTState::CONNECTING;
|
||||
_last_connect_attempt = millis();
|
||||
|
||||
Serial.printf("[MQTT] Connecting to %s:%d (backoff=%lums)...\n",
|
||||
Serial.printf("[MQTTS] Connecting to %s:%d (backoff=%lums)...\n",
|
||||
_config.broker, _config.port, _current_backoff_ms);
|
||||
|
||||
String client_id = String(_config.client_id);
|
||||
@ -165,17 +164,14 @@ void MQTTBridge::attemptConnection() {
|
||||
_reconnect_count++;
|
||||
// Reset backoff on successful connection
|
||||
_current_backoff_ms = BACKOFF_MIN_MS;
|
||||
Serial.println("[MQTT] Connected!");
|
||||
Serial.println("[MQTTS] Connected!");
|
||||
|
||||
subscribeToCommands();
|
||||
publishStatus();
|
||||
_last_status_publish = millis();
|
||||
} else {
|
||||
int rc = _mqtt_client.state();
|
||||
const char* error_str = getMQTTErrorString(rc);
|
||||
Serial.printf("[MQTT] Connection failed: %s (code %d)\n", error_str, rc);
|
||||
Serial.printf("[MQTT] Broker: %s:%d, User: %s\n", _config.broker, _config.port,
|
||||
strlen(_config.user) > 0 ? _config.user : "(none)");
|
||||
Serial.printf("[MQTTS] Connection failed, rc=%d\n", rc);
|
||||
_state = MQTTState::ERROR;
|
||||
|
||||
// Exponential backoff: double the delay (up to max)
|
||||
@ -184,23 +180,6 @@ void MQTTBridge::attemptConnection() {
|
||||
}
|
||||
}
|
||||
|
||||
const char* MQTTBridge::getMQTTErrorString(int rc) {
|
||||
// PubSubClient state() return codes
|
||||
switch (rc) {
|
||||
case -4: return "Connection timeout";
|
||||
case -3: return "Connection lost";
|
||||
case -2: return "Connect failed (network)";
|
||||
case -1: return "Disconnected cleanly";
|
||||
case 0: return "Connected";
|
||||
case 1: return "Bad protocol version";
|
||||
case 2: return "Client ID rejected";
|
||||
case 3: return "Server unavailable";
|
||||
case 4: return "Bad credentials (check username/password)";
|
||||
case 5: return "Not authorized";
|
||||
default: return "Unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
void MQTTBridge::setupTopics() {
|
||||
snprintf(_topic_status, sizeof(_topic_status),
|
||||
"%s/gateway/%s/status", _config.topic_prefix, _gateway_id);
|
||||
@ -220,7 +199,7 @@ void MQTTBridge::subscribeToCommands() {
|
||||
char topic[100];
|
||||
snprintf(topic, sizeof(topic), "%s#", _topic_cmd_prefix);
|
||||
_mqtt_client.subscribe(topic);
|
||||
Serial.printf("[MQTT] Subscribed to: %s\n", topic);
|
||||
Serial.printf("[MQTTS] Subscribed to: %s\n", topic);
|
||||
}
|
||||
|
||||
void MQTTBridge::updateConfig(const MQTTConfig& config) {
|
||||
@ -365,7 +344,7 @@ void MQTTBridge::publishMessage(const char* topic, const char* payload, bool ret
|
||||
if (_mqtt_client.publish(topic, payload, retained)) {
|
||||
_messages_sent++;
|
||||
} else {
|
||||
Serial.printf("[MQTT] Publish failed to %s\n", topic);
|
||||
Serial.printf("[MQTTS] Publish failed to %s\n", topic);
|
||||
}
|
||||
}
|
||||
|
||||
@ -412,10 +391,10 @@ void MQTTBridge::handleMessage(char* topic, uint8_t* payload, unsigned int lengt
|
||||
|
||||
if (strncmp(topic, _topic_cmd_prefix, strlen(_topic_cmd_prefix)) == 0) {
|
||||
const char* cmd = topic + strlen(_topic_cmd_prefix);
|
||||
Serial.printf("[MQTT] Command received: %s\n", cmd);
|
||||
Serial.printf("[MQTTS] Command received: %s\n", cmd);
|
||||
|
||||
if (strcmp(cmd, "reboot") == 0) {
|
||||
Serial.println("[MQTT] Reboot requested");
|
||||
Serial.println("[MQTTS] Reboot requested");
|
||||
publishStatus();
|
||||
delay(100);
|
||||
ESP.restart();
|
||||
|
||||
@ -117,9 +117,6 @@ private:
|
||||
void publishMessage(const char* topic, const char* payload, bool retained = false);
|
||||
void publishJson(const char* topic, JsonDocument& doc, bool retained = false);
|
||||
|
||||
// Error code translation for better diagnostics
|
||||
static const char* getMQTTErrorString(int rc);
|
||||
|
||||
static uint32_t fnv1a_hash(const uint8_t* data, size_t len);
|
||||
bool isDuplicate(const uint8_t* data, size_t len);
|
||||
|
||||
|
||||
@ -733,21 +733,6 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
|
||||
_prefs.adc_multiplier = 0.0f; // 0.0f means use default board multiplier
|
||||
}
|
||||
|
||||
MyMesh::~MyMesh() {
|
||||
// Clean up dynamically allocated resources
|
||||
#ifdef WITH_MQTT
|
||||
delete _web_config;
|
||||
_web_config = nullptr;
|
||||
delete _mqtt_bridge;
|
||||
_mqtt_bridge = nullptr;
|
||||
#endif
|
||||
|
||||
#ifdef WITH_ETHERNET
|
||||
delete _mqtt_bridge;
|
||||
_mqtt_bridge = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
void MyMesh::begin(FILESYSTEM *fs) {
|
||||
mesh::Mesh::begin();
|
||||
_fs = fs;
|
||||
|
||||
11
src/MyMesh.h
11
src/MyMesh.h
@ -125,21 +125,21 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
|
||||
|
||||
#ifdef WITH_MQTT
|
||||
WiFiManager _wifi_mgr;
|
||||
MQTTBridge* _mqtt_bridge = nullptr;
|
||||
WebConfig* _web_config = nullptr;
|
||||
MQTTBridge* _mqtt_bridge;
|
||||
WebConfig* _web_config;
|
||||
WiFiConfig _wifi_config;
|
||||
MQTTConfig _mqtt_config;
|
||||
unsigned long _last_mqtt_stats = 0;
|
||||
unsigned long _last_mqtt_stats;
|
||||
|
||||
void initMQTT();
|
||||
#endif
|
||||
|
||||
#ifdef WITH_ETHERNET
|
||||
EthernetManager _eth_mgr;
|
||||
MQTTBridge* _mqtt_bridge = nullptr;
|
||||
MQTTBridge* _mqtt_bridge;
|
||||
MQTTConfig _mqtt_config;
|
||||
EthernetConfig _eth_config;
|
||||
unsigned long _last_mqtt_stats = 0;
|
||||
unsigned long _last_mqtt_stats;
|
||||
|
||||
void initEthernet();
|
||||
#endif
|
||||
@ -196,7 +196,6 @@ protected:
|
||||
|
||||
public:
|
||||
MyMesh(mesh::MainBoard& board, mesh::Radio& radio, mesh::MillisecondClock& ms, mesh::RNG& rng, mesh::RTCClock& rtc, mesh::MeshTables& tables);
|
||||
~MyMesh(); // Clean up dynamically allocated resources
|
||||
|
||||
void begin(FILESYSTEM* fs);
|
||||
|
||||
|
||||
@ -10,7 +10,6 @@ WiFiManager::WiFiManager()
|
||||
_retry_count(0),
|
||||
_initialized(false) {
|
||||
memset(&_config, 0, sizeof(_config));
|
||||
memset(_cached_ssid, 0, sizeof(_cached_ssid));
|
||||
}
|
||||
|
||||
void WiFiManager::begin(const WiFiConfig& config) {
|
||||
@ -83,9 +82,6 @@ void WiFiManager::loop() {
|
||||
_state = WiFiState::CONNECTED;
|
||||
_connected_since = millis();
|
||||
_retry_count = 0;
|
||||
// Cache SSID to avoid dangling pointer from WiFi.SSID().c_str()
|
||||
strncpy(_cached_ssid, WiFi.SSID().c_str(), sizeof(_cached_ssid) - 1);
|
||||
_cached_ssid[sizeof(_cached_ssid) - 1] = '\0';
|
||||
Serial.printf("[WiFi] Connected! IP: %s, RSSI: %d dBm\n",
|
||||
WiFi.localIP().toString().c_str(), WiFi.RSSI());
|
||||
} else if (status == WL_NO_SSID_AVAIL) {
|
||||
@ -188,9 +184,6 @@ void WiFiManager::startAPMode() {
|
||||
|
||||
if (success) {
|
||||
_state = WiFiState::AP_MODE;
|
||||
// Cache AP SSID to avoid dangling pointer
|
||||
strncpy(_cached_ssid, ap_ssid.c_str(), sizeof(_cached_ssid) - 1);
|
||||
_cached_ssid[sizeof(_cached_ssid) - 1] = '\0';
|
||||
Serial.printf("[WiFi] AP started: SSID='%s', IP=%s\n",
|
||||
ap_ssid.c_str(), WiFi.softAPIP().toString().c_str());
|
||||
} else {
|
||||
@ -228,8 +221,10 @@ int32_t WiFiManager::getRSSI() const {
|
||||
}
|
||||
|
||||
const char* WiFiManager::getSSID() const {
|
||||
if (_state == WiFiState::CONNECTED || _state == WiFiState::AP_MODE) {
|
||||
return _cached_ssid;
|
||||
if (_state == WiFiState::CONNECTED) {
|
||||
return WiFi.SSID().c_str();
|
||||
} else if (_state == WiFiState::AP_MODE) {
|
||||
return WiFi.softAPSSID().c_str();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
@ -269,8 +264,10 @@ NetworkState WiFiManager::getState() const {
|
||||
}
|
||||
|
||||
const char* WiFiManager::getConnectionName() const {
|
||||
if (_state == WiFiState::CONNECTED || _state == WiFiState::AP_MODE) {
|
||||
return _cached_ssid;
|
||||
if (_state == WiFiState::CONNECTED) {
|
||||
return WiFi.SSID().c_str();
|
||||
} else if (_state == WiFiState::AP_MODE) {
|
||||
return WiFi.softAPSSID().c_str();
|
||||
}
|
||||
return "Not connected";
|
||||
}
|
||||
|
||||
@ -61,7 +61,6 @@ private:
|
||||
unsigned long _connected_since;
|
||||
uint8_t _retry_count;
|
||||
bool _initialized;
|
||||
char _cached_ssid[33]; // Cached SSID to avoid dangling pointer from WiFi.SSID().c_str()
|
||||
|
||||
void attemptConnection();
|
||||
void checkConnection();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user