diff --git a/src/helpers/CommonCLI.cpp b/src/helpers/CommonCLI.cpp index ef464a7f..57856e7b 100644 --- a/src/helpers/CommonCLI.cpp +++ b/src/helpers/CommonCLI.cpp @@ -1389,33 +1389,58 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep sprintf(reply, "unknown config: %s", config); } } else if (memcmp(config, "mqtt.server ", 12) == 0) { - StrHelper::strncpy(_prefs->mqtt_server, &config[12], sizeof(_prefs->mqtt_server)); + // Legacy single-broker CLI → slot 3 (index 2), same layout as old prefs migration. + const int legacy_slot = 2; + StrHelper::strncpy(_prefs->mqtt_slot_host[legacy_slot], &config[12], sizeof(_prefs->mqtt_slot_host[legacy_slot])); + StrHelper::strncpy(_prefs->mqtt_slot_preset[legacy_slot], MQTT_PRESET_CUSTOM, sizeof(_prefs->mqtt_slot_preset[legacy_slot])); savePrefs(); + _callbacks->restartBridgeSlot(legacy_slot); strcpy(reply, "OK"); } else if (memcmp(config, "mqtt.port ", 10) == 0) { + const int legacy_slot = 2; int port = atoi(&config[10]); if (port > 0 && port <= 65535) { - _prefs->mqtt_port = port; + _prefs->mqtt_slot_port[legacy_slot] = (uint16_t)port; + StrHelper::strncpy(_prefs->mqtt_slot_preset[legacy_slot], MQTT_PRESET_CUSTOM, sizeof(_prefs->mqtt_slot_preset[legacy_slot])); savePrefs(); + _callbacks->restartBridgeSlot(legacy_slot); strcpy(reply, "OK"); } else { strcpy(reply, "Error: port must be between 1 and 65535"); } } else if (memcmp(config, "mqtt.username ", 14) == 0) { - StrHelper::strncpy(_prefs->mqtt_username, &config[14], sizeof(_prefs->mqtt_username)); + const int legacy_slot = 2; + StrHelper::strncpy(_prefs->mqtt_slot_username[legacy_slot], &config[14], sizeof(_prefs->mqtt_slot_username[legacy_slot])); + StrHelper::strncpy(_prefs->mqtt_slot_preset[legacy_slot], MQTT_PRESET_CUSTOM, sizeof(_prefs->mqtt_slot_preset[legacy_slot])); savePrefs(); + _callbacks->restartBridgeSlot(legacy_slot); strcpy(reply, "OK"); } else if (memcmp(config, "mqtt.password ", 14) == 0) { - StrHelper::strncpy(_prefs->mqtt_password, &config[14], sizeof(_prefs->mqtt_password)); + const int legacy_slot = 2; + StrHelper::strncpy(_prefs->mqtt_slot_password[legacy_slot], &config[14], sizeof(_prefs->mqtt_slot_password[legacy_slot])); + StrHelper::strncpy(_prefs->mqtt_slot_preset[legacy_slot], MQTT_PRESET_CUSTOM, sizeof(_prefs->mqtt_slot_preset[legacy_slot])); savePrefs(); + _callbacks->restartBridgeSlot(legacy_slot); strcpy(reply, "OK"); } else if (memcmp(config, "mqtt.analyzer.us ", 17) == 0) { - _prefs->mqtt_analyzer_us_enabled = memcmp(&config[17], "on", 2) == 0; + const int slot = 0; + if (memcmp(&config[17], "on", 2) == 0) { + StrHelper::strncpy(_prefs->mqtt_slot_preset[slot], "analyzer-us", sizeof(_prefs->mqtt_slot_preset[slot])); + } else { + StrHelper::strncpy(_prefs->mqtt_slot_preset[slot], MQTT_PRESET_NONE, sizeof(_prefs->mqtt_slot_preset[slot])); + } savePrefs(); + _callbacks->restartBridgeSlot(slot); strcpy(reply, "OK"); } else if (memcmp(config, "mqtt.analyzer.eu ", 17) == 0) { - _prefs->mqtt_analyzer_eu_enabled = memcmp(&config[17], "on", 2) == 0; + const int slot = 1; + if (memcmp(&config[17], "on", 2) == 0) { + StrHelper::strncpy(_prefs->mqtt_slot_preset[slot], "analyzer-eu", sizeof(_prefs->mqtt_slot_preset[slot])); + } else { + StrHelper::strncpy(_prefs->mqtt_slot_preset[slot], MQTT_PRESET_NONE, sizeof(_prefs->mqtt_slot_preset[slot])); + } savePrefs(); + _callbacks->restartBridgeSlot(slot); strcpy(reply, "OK"); } else if (memcmp(config, "mqtt.owner ", 11) == 0) { const char* owner_key = &config[11]; @@ -1636,13 +1661,13 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep sprintf(reply, "??: %s", config); } } else if (memcmp(config, "mqtt.server", 11) == 0) { - sprintf(reply, "> %s", _prefs->mqtt_server); + sprintf(reply, "> %s", _prefs->mqtt_slot_host[2]); } else if (memcmp(config, "mqtt.port", 9) == 0) { - sprintf(reply, "> %d", _prefs->mqtt_port); + sprintf(reply, "> %d", (int)_prefs->mqtt_slot_port[2]); } else if (memcmp(config, "mqtt.username", 13) == 0) { - sprintf(reply, "> %s", _prefs->mqtt_username); + sprintf(reply, "> %s", _prefs->mqtt_slot_username[2]); } else if (memcmp(config, "mqtt.password", 13) == 0) { - sprintf(reply, "> %s", _prefs->mqtt_password); + sprintf(reply, "> %s", _prefs->mqtt_slot_password[2]); } else if (memcmp(config, "wifi.ssid", 9) == 0) { sprintf(reply, "> %s", _prefs->wifi_ssid); } else if (memcmp(config, "wifi.pwd", 8) == 0) { @@ -1709,9 +1734,9 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep } else if (memcmp(config, "timezone.offset", 15) == 0) { sprintf(reply, "> %d", _prefs->timezone_offset); } else if (memcmp(config, "mqtt.analyzer.us", 17) == 0) { - sprintf(reply, "> %s", _prefs->mqtt_analyzer_us_enabled ? "on" : "off"); + sprintf(reply, "> %s", strcmp(_prefs->mqtt_slot_preset[0], "analyzer-us") == 0 ? "on" : "off"); } else if (memcmp(config, "mqtt.analyzer.eu", 17) == 0) { - sprintf(reply, "> %s", _prefs->mqtt_analyzer_eu_enabled ? "on" : "off"); + sprintf(reply, "> %s", strcmp(_prefs->mqtt_slot_preset[1], "analyzer-eu") == 0 ? "on" : "off"); } else if (sender_timestamp == 0 && memcmp(config, "mqtt.owner", 10) == 0) { if (_prefs->mqtt_owner_public_key[0] != '\0') { sprintf(reply, "> %s", _prefs->mqtt_owner_public_key); diff --git a/src/helpers/bridges/MQTTBridge.cpp b/src/helpers/bridges/MQTTBridge.cpp index 70f23fb0..62831cdd 100644 --- a/src/helpers/bridges/MQTTBridge.cpp +++ b/src/helpers/bridges/MQTTBridge.cpp @@ -51,6 +51,20 @@ static bool isWiFiConfigValid(const NodePrefs* prefs) { #ifdef WITH_MQTT_BRIDGE +bool MQTTBridge::isConfigValid(const NodePrefs* prefs) { + if (!prefs || !isWiFiConfigValid(prefs)) return false; + for (int i = 0; i < RUNTIME_MQTT_SLOTS; i++) { + const char* preset_name = prefs->mqtt_slot_preset[i]; + if (preset_name[0] == '\0' || strcmp(preset_name, MQTT_PRESET_NONE) == 0) continue; + if (strcmp(preset_name, MQTT_PRESET_CUSTOM) == 0) { + if (prefs->mqtt_slot_host[i][0] != '\0' && prefs->mqtt_slot_port[i] != 0) return true; + } else if (findMQTTPreset(preset_name) != nullptr) { + return true; + } + } + return false; +} + // Optional embedded CA bundle symbols produced by board_build.embed_files. // Weak linkage keeps non-bundle builds linkable and allows runtime fallback. extern const uint8_t rootca_crt_bundle_start[] asm("_binary_src_certs_x509_crt_bundle_bin_start") __attribute__((weak)); diff --git a/src/helpers/bridges/MQTTBridge.h b/src/helpers/bridges/MQTTBridge.h index 3e7ad779..3dac7122 100644 --- a/src/helpers/bridges/MQTTBridge.h +++ b/src/helpers/bridges/MQTTBridge.h @@ -379,6 +379,8 @@ public: static unsigned long getWifiConnectedAtMillis(); static void formatMqttStatusReply(char* buf, size_t bufsize, const NodePrefs* prefs); + /** True when WiFi is set and at least one MQTT slot can run (preset + custom host if needed). */ + static bool isConfigValid(const NodePrefs* prefs); static void formatSlotDiagReply(char* buf, size_t bufsize, int slot_index); static uint8_t getLastWifiDisconnectReason(); static unsigned long getLastWifiDisconnectTime();