diff --git a/src/helpers/MQTTPresets.h b/src/helpers/MQTTPresets.h index 2b91cbe0b..1a461bd20 100644 --- a/src/helpers/MQTTPresets.h +++ b/src/helpers/MQTTPresets.h @@ -87,7 +87,7 @@ static const char ISRG_ROOT_X1[] PROGMEM = "-----END CERTIFICATE-----\n"; // Number of built-in presets -static const int MQTT_PRESET_COUNT = 6; +static const int MQTT_PRESET_COUNT = 7; // Built-in preset definitions (stored in flash) static const MQTTPresetDef MQTT_PRESETS[MQTT_PRESET_COUNT] = { @@ -96,6 +96,7 @@ static const MQTTPresetDef MQTT_PRESETS[MQTT_PRESET_COUNT] = { { "meshmapper", "wss://mqtt.meshmapper.cc:443/mqtt", "mqtt.meshmapper.cc", ISRG_ROOT_X1, MQTT_AUTH_JWT, MQTT_TOPIC_MESHCORE, 0, true, 55 }, { "meshrank", "mqtts://meshrank.net:8883", nullptr, ISRG_ROOT_X1, MQTT_AUTH_NONE, MQTT_TOPIC_MESHRANK, 0, false, 0 }, { "waev", "wss://mqtt.waev.app:443/mqtt", "mqtt.waev.app", GTS_ROOT_R4, MQTT_AUTH_JWT, MQTT_TOPIC_MESHCORE, 3300, false, 55 }, + { "meshomatic", "wss://us-east.meshomatic.net:443/mqtt", "us-east.meshomatic.net", ISRG_ROOT_X1, MQTT_AUTH_JWT, MQTT_TOPIC_MESHCORE, 0, true, 55 }, { "cascadiamesh", "mqtt://cascadiamesh.ddns.net:1883", nullptr, nullptr, MQTT_AUTH_NONE, MQTT_TOPIC_MESHCORE, 0, true, 0 }, }; diff --git a/src/helpers/bridges/MQTTBridge.cpp b/src/helpers/bridges/MQTTBridge.cpp index 65a12d453..f4e2e5fa8 100644 --- a/src/helpers/bridges/MQTTBridge.cpp +++ b/src/helpers/bridges/MQTTBridge.cpp @@ -327,10 +327,15 @@ void MQTTBridge::begin() { if (preset_name[0] != '\0' && strcmp(preset_name, MQTT_PRESET_NONE) != 0) { if (strcmp(preset_name, MQTT_PRESET_CUSTOM) == 0) { // Custom broker: copy host/port/username/password from prefs - _slots[i].enabled = true; _slots[i].preset = nullptr; strncpy(_slots[i].host, _prefs->mqtt_slot_host[i], sizeof(_slots[i].host) - 1); _slots[i].host[sizeof(_slots[i].host) - 1] = '\0'; + if (strlen(_slots[i].host) == 0) { + MQTT_DEBUG_PRINTLN("MQTT%d: custom preset has no server configured, disabling", i + 1); + _slots[i].enabled = false; + continue; + } + _slots[i].enabled = true; _slots[i].port = _prefs->mqtt_slot_port[i]; strncpy(_slots[i].username, _prefs->mqtt_slot_username[i], sizeof(_slots[i].username) - 1); _slots[i].username[sizeof(_slots[i].username) - 1] = '\0'; @@ -807,7 +812,13 @@ void MQTTBridge::setupSlot(int index) { updateCachedConnectionStatus(); }); slot.client->onError([this, index](esp_mqtt_error_codes error) { - MQTT_DEBUG_PRINTLN("MQTT%d error: %d", index + 1, error.esp_tls_last_esp_err); + if (error.esp_tls_last_esp_err != 0 || error.esp_tls_stack_err != 0 || error.esp_transport_sock_errno != 0) { + MQTT_DEBUG_PRINTLN("MQTT%d error: tls=%d, tls_stack=%d, sock=%d, type=%d", + index + 1, error.esp_tls_last_esp_err, error.esp_tls_stack_err, + error.esp_transport_sock_errno, error.error_type); + } else { + MQTT_DEBUG_PRINTLN("MQTT%d error: type=%d", index + 1, error.error_type); + } }); if (slot.preset) { @@ -850,6 +861,14 @@ void MQTTBridge::setupSlot(int index) { snprintf(slot.broker_uri, sizeof(slot.broker_uri), "%s://%s:%d", proto, slot.host, slot.port); } slot.client->setServer(slot.broker_uri); + + // Custom TLS/WSS slots need the system CA cert bundle for server verification + bool needs_tls = (strncmp(slot.broker_uri, "mqtts://", 8) == 0 || + strncmp(slot.broker_uri, "wss://", 6) == 0); + if (needs_tls) { + slot.client->attachArduinoCACertBundle(true); + } + if (strlen(slot.username) > 0) { slot.client->setCredentials(slot.username, slot.password); }