From 79b3bc257398b83ce1af90f652f1ea3564679caf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Sat, 12 Jul 2025 15:37:53 +0200 Subject: [PATCH 1/4] Add mDNS support for MQTT server - fixes wled#4671 - reduce some topic string parsing - moves LWT into onConnect --- wled00/mqtt.cpp | 56 ++++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/wled00/mqtt.cpp b/wled00/mqtt.cpp index 62f296104..d825957a5 100644 --- a/wled00/mqtt.cpp +++ b/wled00/mqtt.cpp @@ -11,6 +11,11 @@ #warning "MQTT topics length > 32 is not recommended for compatibility with usermods!" #endif +static const char* sTopicFormat PROGMEM = "%.*s/%s"; + +// parse payload for brightness, ON/OFF or toggle +// briLast is used to remember last brightness value in case of ON/OFF or toggle +// bri is set to 0 if payload is "0" or "OFF" or "false" static void parseMQTTBriPayload(char* payload) { if (strstr(payload, "ON") || strstr(payload, "on") || strstr(payload, "true")) {bri = briLast; stateUpdated(CALL_MODE_DIRECT_CHANGE);} @@ -30,22 +35,18 @@ static void onMqttConnect(bool sessionPresent) char subuf[MQTT_MAX_TOPIC_LEN + 9]; if (mqttDeviceTopic[0] != 0) { - strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1); + mqtt->subscribe(mqttDeviceTopic, 0); + snprintf_P(subuf, sizeof(subuf)-1, sTopicFormat, MQTT_MAX_TOPIC_LEN, mqttDeviceTopic, "col"); mqtt->subscribe(subuf, 0); - strcat_P(subuf, PSTR("/col")); - mqtt->subscribe(subuf, 0); - strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1); - strcat_P(subuf, PSTR("/api")); + snprintf_P(subuf, sizeof(subuf)-1, sTopicFormat, MQTT_MAX_TOPIC_LEN, mqttDeviceTopic, "api"); mqtt->subscribe(subuf, 0); } if (mqttGroupTopic[0] != 0) { - strlcpy(subuf, mqttGroupTopic, MQTT_MAX_TOPIC_LEN + 1); + mqtt->subscribe(mqttGroupTopic, 0); + snprintf_P(subuf, sizeof(subuf)-1, sTopicFormat, MQTT_MAX_TOPIC_LEN, mqttGroupTopic, "col"); mqtt->subscribe(subuf, 0); - strcat_P(subuf, PSTR("/col")); - mqtt->subscribe(subuf, 0); - strlcpy(subuf, mqttGroupTopic, MQTT_MAX_TOPIC_LEN + 1); - strcat_P(subuf, PSTR("/api")); + snprintf_P(subuf, sizeof(subuf)-1, sTopicFormat, MQTT_MAX_TOPIC_LEN, mqttGroupTopic, "api"); mqtt->subscribe(subuf, 0); } @@ -54,9 +55,8 @@ static void onMqttConnect(bool sessionPresent) DEBUG_PRINTLN(F("MQTT ready")); #ifndef USERMOD_SMARTNEST - strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1); - strcat_P(subuf, PSTR("/status")); - mqtt->publish(subuf, 0, true, "online"); // retain message for a LWT + snprintf_P(mqttStatusTopic, sizeof(mqttStatusTopic)-1, sTopicFormat, MQTT_MAX_TOPIC_LEN, mqttDeviceTopic, "status"); + mqtt->setWill(mqttStatusTopic, 0, true, "offline"); // LWT message #endif publishMqtt(); @@ -136,7 +136,7 @@ static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProp } // Print adapter for flat buffers -namespace { +namespace { class bufferPrint : public Print { char* _buf; size_t _size, _offset; @@ -172,21 +172,21 @@ void publishMqtt() char subuf[MQTT_MAX_TOPIC_LEN + 16]; sprintf_P(s, PSTR("%u"), bri); - strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1); - strcat_P(subuf, PSTR("/g")); + snprintf_P(subuf, sizeof(subuf)-1, sTopicFormat, MQTT_MAX_TOPIC_LEN, mqttDeviceTopic, "g"); mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263) sprintf_P(s, PSTR("#%06X"), (colPri[3] << 24) | (colPri[0] << 16) | (colPri[1] << 8) | (colPri[2])); - strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1); - strcat_P(subuf, PSTR("/c")); + snprintf_P(subuf, sizeof(subuf)-1, sTopicFormat, MQTT_MAX_TOPIC_LEN, mqttDeviceTopic, "c"); mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263) + snprintf_P(subuf, sizeof(subuf)-1, sTopicFormat, MQTT_MAX_TOPIC_LEN, mqttDeviceTopic, "status"); + mqtt->publish(subuf, 0, true, "online"); // retain message for a LWT + // TODO: use a DynamicBufferList. Requires a list-read-capable MQTT client API. DynamicBuffer buf(1024); bufferPrint pbuf(buf.data(), buf.size()); XML_response(pbuf); - strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1); - strcat_P(subuf, PSTR("/v")); + snprintf_P(subuf, sizeof(subuf)-1, sTopicFormat, MQTT_MAX_TOPIC_LEN, mqttDeviceTopic, "v"); mqtt->publish(subuf, 0, retainMqttMsg, buf.data(), pbuf.size()); // optionally retain message (#2263) #endif } @@ -213,16 +213,20 @@ bool initMqtt() { mqtt->setServer(mqttIP, mqttPort); } else { - mqtt->setServer(mqttServer, mqttPort); + #ifdef ARDUINO_ARCH_ESP32 + if (strlen(cmDNS) > 0 && strchr(mqttServer, '.') == nullptr) { // if mDNS is enabled and server does not have domain + mqttIP = MDNS.queryHost(mqttServer); + if (mqttIP != IPAddress()) // if MDNS resolved the hostname + mqtt->setServer(mqttIP, mqttPort); + else + mqtt->setServer(mqttServer, mqttPort); + } else + #endif + mqtt->setServer(mqttServer, mqttPort); } mqtt->setClientId(mqttClientID); if (mqttUser[0] && mqttPass[0]) mqtt->setCredentials(mqttUser, mqttPass); - #ifndef USERMOD_SMARTNEST - strlcpy(mqttStatusTopic, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1); - strcat_P(mqttStatusTopic, PSTR("/status")); - mqtt->setWill(mqttStatusTopic, 0, true, "offline"); // LWT message - #endif mqtt->setKeepAlive(MQTT_KEEP_ALIVE_TIME); mqtt->connect(); return true; From 24f2306129c2e8e08505bd55346b65aa0700508f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Tue, 15 Jul 2025 10:32:10 +0200 Subject: [PATCH 2/4] Strip .local from mDNS resolution --- wled00/mqtt.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/wled00/mqtt.cpp b/wled00/mqtt.cpp index d825957a5..06247ac58 100644 --- a/wled00/mqtt.cpp +++ b/wled00/mqtt.cpp @@ -214,8 +214,10 @@ bool initMqtt() mqtt->setServer(mqttIP, mqttPort); } else { #ifdef ARDUINO_ARCH_ESP32 - if (strlen(cmDNS) > 0 && strchr(mqttServer, '.') == nullptr) { // if mDNS is enabled and server does not have domain - mqttIP = MDNS.queryHost(mqttServer); + String mqttMDNS = mqttServer; + mqttMDNS.replace(F(".local"), ""); // remove .local if present + if (strlen(cmDNS) > 0 && mqttMDNS.length() > 0 && mqttMDNS.indexOf('.') < 0) { // if mDNS is enabled and server does not have domain + mqttIP = MDNS.queryHost(mqttMDNS.c_str()); if (mqttIP != IPAddress()) // if MDNS resolved the hostname mqtt->setServer(mqttIP, mqttPort); else From 07e303bcc13670ff024e2276c24d5f5d6e1e5cee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Tue, 15 Jul 2025 13:36:44 +0200 Subject: [PATCH 3/4] Remove anything behind .local and ignore case --- wled00/mqtt.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/wled00/mqtt.cpp b/wled00/mqtt.cpp index 06247ac58..01773d9fd 100644 --- a/wled00/mqtt.cpp +++ b/wled00/mqtt.cpp @@ -215,7 +215,9 @@ bool initMqtt() } else { #ifdef ARDUINO_ARCH_ESP32 String mqttMDNS = mqttServer; - mqttMDNS.replace(F(".local"), ""); // remove .local if present + mqttMDNS.toLowerCase(); // make sure we have a lowercase hostname + int pos = mqttMDNS.indexOf(F(".local")); + if (pos > 0) mqttMDNS.remove(pos); // remove .local domain if present (and anything following it) if (strlen(cmDNS) > 0 && mqttMDNS.length() > 0 && mqttMDNS.indexOf('.') < 0) { // if mDNS is enabled and server does not have domain mqttIP = MDNS.queryHost(mqttMDNS.c_str()); if (mqttIP != IPAddress()) // if MDNS resolved the hostname From ecc3eae247850c38c05539c2b2ae44ed06627d29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Wed, 16 Jul 2025 11:18:04 +0200 Subject: [PATCH 4/4] Revert status message change --- wled00/mqtt.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/wled00/mqtt.cpp b/wled00/mqtt.cpp index 01773d9fd..ea42297bf 100644 --- a/wled00/mqtt.cpp +++ b/wled00/mqtt.cpp @@ -55,8 +55,8 @@ static void onMqttConnect(bool sessionPresent) DEBUG_PRINTLN(F("MQTT ready")); #ifndef USERMOD_SMARTNEST - snprintf_P(mqttStatusTopic, sizeof(mqttStatusTopic)-1, sTopicFormat, MQTT_MAX_TOPIC_LEN, mqttDeviceTopic, "status"); - mqtt->setWill(mqttStatusTopic, 0, true, "offline"); // LWT message + snprintf_P(subuf, sizeof(subuf)-1, sTopicFormat, MQTT_MAX_TOPIC_LEN, mqttDeviceTopic, "status"); + mqtt->publish(subuf, 0, true, "online"); // retain message for a LWT #endif publishMqtt(); @@ -231,6 +231,10 @@ bool initMqtt() mqtt->setClientId(mqttClientID); if (mqttUser[0] && mqttPass[0]) mqtt->setCredentials(mqttUser, mqttPass); + #ifndef USERMOD_SMARTNEST + snprintf_P(mqttStatusTopic, sizeof(mqttStatusTopic)-1, sTopicFormat, MQTT_MAX_TOPIC_LEN, mqttDeviceTopic, "status"); + mqtt->setWill(mqttStatusTopic, 0, true, "offline"); // LWT message + #endif mqtt->setKeepAlive(MQTT_KEEP_ALIVE_TIME); mqtt->connect(); return true;