mDNS in NodeMCU
Basic Infos
- [X] This issue complies with the issue POLICY doc.
- [X] I have read the documentation at readthedocs and the issue is not addressed there.
- [ ] I have tested that the issue is present in current master branch (aka latest git).
- [X] I have searched the issue tracker for a similar issue.
- [ ] If there is a stack dump, I have decoded it.
- [ ] I have filled out all fields below.
Platform
- Hardware: ESP8266
- Core Version: 3.1.2
- Development Env: Arduino IDE 2.1.0
- Operating System: Windows
Settings in IDE
- Module: Nodemcu|other
- Flash Mode: ? (couldn't find)
- Flash Size: 4MB
- lwip Variant: v2 Lower Memory
- Reset Method: nodemcu
- Flash Frequency: 40Mhz
- CPU Frequency: 80Mhz and 160MHz
- Upload Using: SERIAL
- Upload Speed: 115200 and 460800
Problem Description
None of the mDNS samples work for me. I can connect through the IP address, but I am not able to find the device using mDNS.
The sample that works the "best" so far is the HelloServer. After it connects and prints
.......
Connected to Network
IP address: 192.168.50.43
MDNS responder started
HTTP server started
I start pinging esp8266.local and it works once, but then it stops working:
PS C:\Users\silas> ping esp8266.local
Ping request could not find host esp8266.local. Please check the name and try again.
PS C:\Users\silas> ping esp8266.local
Pinging esp8266.local [192.168.50.43] with 32 bytes of data:
Reply from 192.168.50.43: bytes=32 time=491ms TTL=255
Reply from 192.168.50.43: bytes=32 time=88ms TTL=255
Reply from 192.168.50.43: bytes=32 time=769ms TTL=255
Reply from 192.168.50.43: bytes=32 time=214ms TTL=255
Ping statistics for 192.168.50.43:
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 88ms, Maximum = 769ms, Average = 390ms
PS C:\Users\silas> ping esp8266.local
Ping request could not find host esp8266.local. Please check the name and try again.
PS C:\Users\silas> ping esp8266.local
Ping request could not find host esp8266.local. Please check the name and try again.
I didn't do any changes to the sample code (other than the network data) and I couldn't find anyone with a solution to this problem either.
Any ideas of what could be preventing MDNS from working after the first time? I am not using OTA and I am erasing all flash contents.
I am pasting the sample code for completion:
MCVE Sketch
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#ifndef STASSID
#define STASSID "..."
#define STAPSK "..."
#endif
const char* ssid = STASSID;
const char* password = STAPSK;
ESP8266WebServer server(80);
const int led = 13;
void handleRoot() {
digitalWrite(led, 1);
server.send(200, "text/plain", "hello from esp8266!\r\n");
digitalWrite(led, 0);
}
void handleNotFound() {
digitalWrite(led, 1);
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i = 0; i < server.args(); i++) { message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; }
server.send(404, "text/plain", message);
digitalWrite(led, 0);
}
void setup(void) {
pinMode(led, OUTPUT);
digitalWrite(led, 0);
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
if (MDNS.begin("esp8266")) { Serial.println("MDNS responder started"); }
server.on("/", handleRoot);
server.on("/inline", []() {
server.send(200, "text/plain", "this works as well");
});
server.on("/gif", []() {
static const uint8_t gif[] PROGMEM = {
0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x10, 0x00, 0x10, 0x00, 0x80, 0x01,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00, 0x00,
0x10, 0x00, 0x10, 0x00, 0x00, 0x02, 0x19, 0x8c, 0x8f, 0xa9, 0xcb, 0x9d,
0x00, 0x5f, 0x74, 0xb4, 0x56, 0xb0, 0xb0, 0xd2, 0xf2, 0x35, 0x1e, 0x4c,
0x0c, 0x24, 0x5a, 0xe6, 0x89, 0xa6, 0x4d, 0x01, 0x00, 0x3b
};
char gif_colored[sizeof(gif)];
memcpy_P(gif_colored, gif, sizeof(gif));
// Set the background to a random set of colors
gif_colored[16] = millis() % 256;
gif_colored[17] = millis() % 256;
gif_colored[18] = millis() % 256;
server.send(200, "image/gif", gif_colored, sizeof(gif_colored));
});
server.onNotFound(handleNotFound);
/////////////////////////////////////////////////////////
// Hook examples
server.addHook([](const String& method, const String& url, WiFiClient* client, ESP8266WebServer::ContentTypeFunction contentType) {
(void)method; // GET, PUT, ...
(void)url; // example: /root/myfile.html
(void)client; // the webserver tcp client connection
(void)contentType; // contentType(".html") => "text/html"
Serial.printf("A useless web hook has passed\n");
Serial.printf("(this hook is in 0x%08x area (401x=IRAM 402x=FLASH))\n", esp_get_program_counter());
return ESP8266WebServer::CLIENT_REQUEST_CAN_CONTINUE;
});
server.addHook([](const String&, const String& url, WiFiClient*, ESP8266WebServer::ContentTypeFunction) {
if (url.startsWith("/fail")) {
Serial.printf("An always failing web hook has been triggered\n");
return ESP8266WebServer::CLIENT_MUST_STOP;
}
return ESP8266WebServer::CLIENT_REQUEST_CAN_CONTINUE;
});
server.addHook([](const String&, const String& url, WiFiClient* client, ESP8266WebServer::ContentTypeFunction) {
if (url.startsWith("/dump")) {
Serial.printf("The dumper web hook is on the run\n");
// Here the request is not interpreted, so we cannot for sure
// swallow the exact amount matching the full request+content,
// hence the tcp connection cannot be handled anymore by the
// webserver.
#ifdef STREAMSEND_API
// we are lucky
client->sendAll(Serial, 500);
#else
auto last = millis();
while ((millis() - last) < 500) {
char buf[32];
size_t len = client->read((uint8_t*)buf, sizeof(buf));
if (len > 0) {
Serial.printf("(<%d> chars)", (int)len);
Serial.write(buf, len);
last = millis();
}
}
#endif
// Two choices: return MUST STOP and webserver will close it
// (we already have the example with '/fail' hook)
// or IS GIVEN and webserver will forget it
// trying with IS GIVEN and storing it on a dumb WiFiClient.
// check the client connection: it should not immediately be closed
// (make another '/dump' one to close the first)
Serial.printf("\nTelling server to forget this connection\n");
static WiFiClient forgetme = *client; // stop previous one if present and transfer client refcounter
return ESP8266WebServer::CLIENT_IS_GIVEN;
}
return ESP8266WebServer::CLIENT_REQUEST_CAN_CONTINUE;
});
// Hook examples
/////////////////////////////////////////////////////////
server.begin();
Serial.println("HTTP server started");
}
void loop(void) {
server.handleClient();
MDNS.update();
}
Latency always that high?
Reply from 192.168.50.43: bytes=32 time=491ms TTL=255 Reply from 192.168.50.43: bytes=32 time=88ms TTL=255 Reply from 192.168.50.43: bytes=32 time=769ms TTL=255 Reply from 192.168.50.43: bytes=32 time=214ms TTL=255
Any difference when dealing with DNS client directly?
> Resolve-DnsName -llmnronly ESP-4A2914.local
Name Type TTL Section IPAddress
---- ---- --- ------- ---------
ESP-4A2914.local A 120 Answer 10.10.10.137
(check out get-help resolve-dnsname and dnsmodule docs)
afaik we are dealing with multicast replies; looking at ping, there is a single query. PS cmdlet sends out more than one, thus also receiving more than one reply (with consideration that it might miss some requests in the process)
@mcspr Thanks for the response! I think I found a solution, so I am detailing it here.
Latency always that high?
I am afraid so... I placed the device close to the router and ran the ping command again. This is the result:
> ping esp8266.local -n 30
Pinging esp8266.local [192.168.50.43] with 32 bytes of data:
Reply from 192.168.50.43: bytes=32 time=289ms TTL=255
Reply from 192.168.50.43: bytes=32 time=270ms TTL=255
Reply from 192.168.50.43: bytes=32 time=1259ms TTL=255
Reply from 192.168.50.43: bytes=32 time=4ms TTL=255
Reply from 192.168.50.43: bytes=32 time=640ms TTL=255
Reply from 192.168.50.43: bytes=32 time=5ms TTL=255
Reply from 192.168.50.43: bytes=32 time=149ms TTL=255
Reply from 192.168.50.43: bytes=32 time=60ms TTL=255
Reply from 192.168.50.43: bytes=32 time=274ms TTL=255
Reply from 192.168.50.43: bytes=32 time=185ms TTL=255
Reply from 192.168.50.43: bytes=32 time=99ms TTL=255
Reply from 192.168.50.43: bytes=32 time=308ms TTL=255
Reply from 192.168.50.43: bytes=32 time=212ms TTL=255
Reply from 192.168.50.43: bytes=32 time=126ms TTL=255
Reply from 192.168.50.43: bytes=32 time=46ms TTL=255
Reply from 192.168.50.43: bytes=32 time=254ms TTL=255
Reply from 192.168.50.43: bytes=32 time=167ms TTL=255
Reply from 192.168.50.43: bytes=32 time=73ms TTL=255
Reply from 192.168.50.43: bytes=32 time=282ms TTL=255
Reply from 192.168.50.43: bytes=32 time=192ms TTL=255
Reply from 192.168.50.43: bytes=32 time=105ms TTL=255
Reply from 192.168.50.43: bytes=32 time=12ms TTL=255
Reply from 192.168.50.43: bytes=32 time=228ms TTL=255
Reply from 192.168.50.43: bytes=32 time=139ms TTL=255
Reply from 192.168.50.43: bytes=32 time=48ms TTL=255
Reply from 192.168.50.43: bytes=32 time=282ms TTL=255
Reply from 192.168.50.43: bytes=32 time=165ms TTL=255
Reply from 192.168.50.43: bytes=32 time=81ms TTL=255
Reply from 192.168.50.43: bytes=32 time=297ms TTL=255
Reply from 192.168.50.43: bytes=32 time=210ms TTL=255
Ping statistics for 192.168.50.43:
Packets: Sent = 30, Received = 30, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 4ms, Maximum = 1259ms, Average = 215ms
Is there anything that can be done to improve this?
Any difference when dealing with DNS client directly?
Without any changes to the code, not really. It couldn't be found:
> Resolve-DnsName -llmnronly esp8266.local
Resolve-DnsName : esp8266.local : This operation returned because the timeout period expired
At line:1 char:1
+ Resolve-DnsName -llmnronly esp8266.local
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationTimeout: (esp8266.local:String) [Resolve-DnsName], Win32Exception
+ FullyQualifiedErrorId : ERROR_TIMEOUT,Microsoft.DnsClient.Commands.ResolveDnsName
What was bothering me is that the MDNS worked for a short while before stopping completely, so I decided to read the source code and see if there was anything there that could help me. That's how I found the bool MDNSResponder::announce(void) which seemed worth try using -- maybe MDNS was announcing just once and that is why it worked only once as well, who knows? Then I created a quick-and-dirty workaround to test this hypothesis.
First, I added this to the beginning of the file:
// counter used for delaying the call to MDNS.announce()
long int advertiseCounter = 0;
and then I changed the loop() function to:
void loop(void) {
server.handleClient();
MDNS.update();
// call MDNS.announce() periodically when the counter exceeds the threshold, then resets the counter.
if (advertiseCounter++ > 100000)
{
MDNS.announce();
advertiseCounter = 0;
}
}
And now I can find the device successfully on Windows =)
> Resolve-DnsName -llmnronly esp8266.local
Name Type TTL Section IPAddress
---- ---- --- ------- ---------
esp8266.local A 120 Answer 192.168.50.43
Name : 43.50.168.192.in-addr.arpa
QueryType : PTR
TTL : 120
Section : Answer
NameHost : esp8266.local
The browser can also find it, so I think this issue is at least partially solved... And the reason for the "partial" is that although it works in Windows, it doesn't work at all with Android... On Windows it works whether I use http://esp8266.local or http://192.168.50.43; in Android, both fail, no matter the browser I am using (Firefox or Chrome). The phone just returns ERR_ADDRESS_UNREACHABLE and that's it. Any ideas? I wonder if it's related to the high latency.
https://stackoverflow.com/questions/30449988/how-to-enable-mdns-support-in-android-browser-address-bar Now mdns support avilable in android 12 or higher (I'm not tested)
https://stackoverflow.com/questions/30449988/how-to-enable-mdns-support-in-android-browser-address-bar Now mdns support avilable in android 12 or higher (I'm not tested)
It's not a MDNS error; it fails even when I use the IP itself. I will try with a different phone and see what happens.