ESP32 ping problems

I'm using an esp32 to ping a local responder which I can turn on and off.
I'm sending a single ping at 6 second intervals. An amber led is turned on when the ping is initiated, and off when its complete.
While the responder is up all works OK, with short flashes.
However when I turn the responder off, so there is no response to a ping, the amber light sooner or later appears to stay on. The serial monitor shows the program is still running

When the amber light "stays on" (actually its off for very short periods) the ping returns a success despite the responder being off.

Is this a fault in the ESP32 ping library?

in loop()

 // do the pings if its time
  if (WiFiUp) {  //only if WiFi up!
    timeNow = millis();
    if (timeNow >= (timeWas + (timeInterval * 1000))) {
      amb(1);  //amber on - showing pinging in progress
      // ***************** ping it
      //pingOK = Ping.ping(remote_ip, pingNumber);  //produces values for pingTime, expectedCount, success, errors
      pingOK = Ping.ping("responder.local", pingNumber);  //for testing
      pingStats();
      amb(0);  //amber off  ping complete
      timeWas = timeNow;
      buildStrings();  //in webData.ino
    }

and the functions called

void pingStats() {  //this is called from the loop() once every timeinterval seconds.  (typically 6 sec)
  if (pingOK) {     //the line is UP so:  OR          //if (pingsLost == 0) {  //the line is UP so
    webIsUp();
    Serial.println("web is up");
  } else {  // the web is DOWN:
    webIsDown();
     Serial.println("web is DOWN");
  }
  prepareStats();
}

void webIsUp() {
  grn(1);
  //timing the ups and downs
  if (webUp == 0) {       //its a new uptime, end of down phase
    mtGoneUp = millis();  //*** record millis time that this uptime starts
    //work out the down phase times
    mtDowntimePrev += mtDnNew;
    mtTimeDn = millis() - mtGoneDn;
    mtTotDnThisH += mtDnNew;
    webUp = 1;
  }
  //update live data for up times
  mtUpNew = millis() - mtGoneUp;           //duration of present up phase
  mtUptimeTotal = mtUptimePrev + mtUpNew;  //running value
  lineDown = 0;                            //reset the linedown counter to 0 - this handles short outages less than threshold
  pingMetrics();                           //only relevant if theres a connection
  //handle red led
  if (webFail > 0) webFail--;
  else red(0);  //turn red off only after maxdown counts
}

void webIsDown() {
  grn(0);
  if (webUp == 1) {       //its a new outage: end of up phase
    mtGoneDn = millis();  // millis time the new outage started
    //work out up phase times
    mtUptimePrev += mtUpNew;
    mtTimeUp = millis() - mtGoneUp;
    mtTotUpThisH += mtUpNew;

    //  *** record dropouts
    dropOuts++;
    pDropOutsThisD++;
    webUp = 0;
  }
  //update live data for downtime
  mtDnNew = millis() - mtGoneDn;
  mtDowntimeTotal = mtDowntimePrev + mtDnNew;

  //handle red led
  lineDown += 1;
  if (lineDown >= threshold) {  //we havent just missed a single ping so ..
    lineDown = threshold;       //dont let it keep counting
    webFail = maxDown;          //initially 60
    red(1);
  }
}

Serial monitor: the responder is OFF and stays OFF

01:22: web is DOWN
01:28: web is DOWN
pSaveStats lineDown, webFail  3 60 
pSaveStats dropOuts, pDropOutsThisH, pDropOutsThisD   1,   0,   1
pSaveStats mtGoneUp, mtGoneDn, mtUptimePrev, mtDowntimePrev   22074,  40454, 238688 126000
01:34: web is DOWN
01:40: web is DOWN
web is DOWN
01:52: web is DOWN
01:58: web is DOWN
02:04: web is DOWN
web is DOWN
02:16: web is DOWN
02:28: web is up
pSaveStats lineDown, webFail  0 59 
pSaveStats dropOuts, pDropOutsThisH, pDropOutsThisD   1,   0,   1
pSaveStats mtGoneUp, mtGoneDn, mtUptimePrev, mtDowntimePrev  148644,  40454, 238688 222000
02:35: web is up
02:43: web is up
02:50: web is up
02:57: web is up
03:04: web is up
03:11: web is up
03:18: web is up
03:26: web is up

Show ALL the code in code tags. Is there any wiring? If so a picture of a hand drawn wiring diagram is needed.
BTW, this is considered poor form as it can overflow. Rearrange so it doesn't. FYI.

(timeNow >= (timeWas + (timeInterval * 1000)))

could be..
under the Tools menu, Core Debug Level: set it to like information, maybe you see something..

good luck.. ~q

I'd also suggest that you create a minimal sketch that just has enough features to demonstrate the problem aka: minimal reproducible example (abbreviated MRE) best with no specific hardware requirements like LEDs on specific pins etc.
You'd have to do this anyway if you submit a problem report.

Thanks @6v6gt & @qubits-us

I couldnt believe it would really be a bug - but it looks as if it is unless there is something about pinging that I dont understand (ie LOTS)

MRE and results

/*
*minimum example for ping lockup issue
*/

#include <WiFi.h>  //WiFi functions - supports wifi.ino
#include <time.h>  //support for time functions
#include <FS.h>           // 
#include <ESPmDNS.h>      //support for multicast to assign name to ip address
#include "ESP32Ping.h"    //handles the ping functions   https://github.com/marian-craciunescu/ESP32Ping

#include "creds.h"     //my wifi credentials
#define mDNSname "testmon"   //set the hostname here
#define BAUDRATE 115200
#define LED_BUILTIN 2

//Configuration of NTP 
#define MY_NTP_SERVER "pool.ntp.org"
time_t now;  // this is the epoch
tm tm;


const long int timeInterval = 6000;  // time in msec between ping requests
long int timeWas, timeNow;
bool pingOK;


void connectWiFi() {
  //get connection
  WiFi.begin(ssid, pass);
  Serial.print("Connecting to WiFi ..");
  digitalWrite(LED_BUILTIN, HIGH);
  while (WiFi.status() != WL_CONNECTED) {  //must allow interrupt to break out of potentially infinite loops
  delay(200);
    Serial.print('w');
  }  //got connection
  //get time
  configTime(0, 0, MY_NTP_SERVER);      // --> Here is the IMPORTANT ONE LINER needed in your sketch!
  while (time(nullptr) < 1600000000) {  // wait for the first time sync
    Serial.print("t");
    delay(100);
  }  //got time
  digitalWrite(LED_BUILTIN, LOW);
  Serial.print("\nWiFi.localIP: ");
  Serial.print(WiFi.localIP());
  Serial.print("  RRSI: ");
  Serial.println(WiFi.RSSI());
}

void pingStats() {  //this is called from the loop() once every timeinterval seconds.  (typically 6 sec)
  if (pingOK) {     //the line is UP so:  OR          //if (pingsLost == 0) {  //the line is UP so
     Serial.println("web is up");
  } else {  // the web is DOWN:
        Serial.println("web is DOWN");
  }
}


void setup() {
  pinMode(LED_BUILTIN,OUTPUT);
  Serial.begin(BAUDRATE);
  delay(5000);  //allow to start & clear serial monitor
  Serial.println();
  Serial.println(__FILE__);  //print name of sketch for easy identification
  connectWiFi();             //also gets time from time server ntp

  // Initialize mDNS
  if (!MDNS.begin(mDNSname)) {  // Set the hostname
    Serial.println("Error setting up MDNS responder!");
  }
  Serial.println("mDNS responder started");
  timeWas = millis();
}


void loop() {
  timeNow = millis();
  if (timeNow >= (timeWas + timeInterval )) {
    digitalWrite(LED_BUILTIN, HIGH);  //amber on - showing pinging in progress
    // ***************** ping it
    //pingOK = Ping.ping(remote_ip, pingNumber);  //produces values for pingTime, expectedCount, success, errors
    pingOK = Ping.ping("responder.local", 1);  //for testing
    pingStats();
     digitalWrite(LED_BUILTIN, LOW); //LED off  ping complete
    timeWas = timeNow;
  }
}

Initially the responder is turned on, then at 7:59:27 tuned off and remains off.

07:58:39.023 -> WiFi.localIP: 192.168.1.57  RRSI: -39
07:58:39.023 -> mDNS responder started
07:58:45.605 -> web is up
07:58:50.982 -> web is up
07:58:57.156 -> web is up
07:59:03.189 -> web is up
07:59:08.990 -> web is up
07:59:15.018 -> web is up
07:59:21.005 -> web is up
07:59:27.187 -> web is up
07:59:33.992 -> web is DOWN
07:59:39.974 -> web is DOWN
07:59:45.990 -> web is DOWN
07:59:51.977 -> web is DOWN
07:59:57.973 -> web is DOWN
08:00:04.002 -> web is DOWN
08:00:10.006 -> web is DOWN
08:00:15.974 -> web is DOWN
08:00:21.994 -> web is DOWN
08:00:27.992 -> web is DOWN
08:00:33.974 -> web is DOWN
08:00:40.007 -> web is DOWN
08:00:52.138 -> web is up
08:00:59.306 -> web is up
08:01:06.510 -> web is up
08:01:13.676 -> web is up
08:01:20.850 -> web is up
08:01:27.995 -> web is up

Do you see anything more if you add this before the include statement for ESP32Ping library ?

#define ENABLE_DEBUG_PING

The ESP32Ping library also comes with an example sketch which you could try but it does look like your own MRE is quite basic.

Strange..
also recommend defining the ENABLE_DEBUG_PING..
and under the tools menu crank the Core Debug Level: to like information..
ping.h is using log_d and log_i, you'll pick these up by setting the Code Debug Level..
You should see allot more information on the serial monitor..

~q

The mystery deepens: when the pinger tries to ping the responder the DNS fails; then the pinger tries to ping 0.0.0.0 - and gets a response!
but - confirming the response from a windows command prompt I see as expected

PING: transmit failed. General failure.
PING: transmit failed. General failure.
PING: transmit failed. General failure.
PING: transmit failed. General failure.

Ping statistics for 0.0.0.0:
    Packets: Sent = 4, Received = 0, Lost = 4 (100% loss),

I've added the ENABLE_DEBUG_PING and some more code to the "pingstats()" function

void pingStats() {  //this is called from the loop() once every timeinterval seconds.  (typically 6 sec)
  if (pingOK) {     //the line is UP so:  OR          //if (pingsLost == 0) {  //the line is UP so
     Serial.println("web is up");
      Serial.print("  Ping success in  ");
  float avg_time_ms = Ping.averageTime();
  Serial.print(avg_time_ms);
  Serial.print(" msec:  expected count is ");
  byte expectedCount = Ping.expectedCount();
  Serial.print(expectedCount);
  Serial.print(" errors: ");
  byte errors = Ping.errors();
  Serial.print(errors);

  Serial.print(" success: ");
  byte success = Ping.success();
  Serial.println(success);
  } else {  // the web is DOWN:
        Serial.println("web is DOWN");
  }
}

with the responder turned off

  Ping success in  30.40 msec:  expected count is 1 errors: 0 success: 1
[194732][E][NetworkManager.cpp:136] hostByName(): DNS Failed for 'responder.local' with error '-54'
[194741][I][ping.cpp:324] ping_start(): PING 0.0.0.0: 32 data bytes

[194778][I][ping.cpp:340] ping_start(): 1 packets transmitted, 1 packets received, 0.0% packet loss

[194787][I][ping.cpp:349] ping_start(): round-trip min/avg/max/stddev = 29.754/29.754/29.754/0.000 ms

web is up
  Ping success in  29.75 msec:  expected count is 1 errors: 0 success: 1
[201796][E][NetworkManager.cpp:136] hostByName(): DNS Failed for 'responder.local' with error '-54'
[201805][I][ping.cpp:324] ping_start(): PING 0.0.0.0: 32 data bytes

[201843][I][ping.cpp:340] ping_start(): 1 packets transmitted, 1 packets received, 0.0% packet loss

[201852][I][ping.cpp:349] ping_start(): round-trip min/avg/max/stddev = 31.472/31.472/31.472/0.000 ms

and if I change the ping target to be 0.0.0.0 the ping program gives the same results - and even the ping response time is not constant.

mDNS responder started
[ 18446][I][ping.cpp:324] ping_start(): PING 0.0.0.0: 32 data bytes
[ 18487][I][ping.cpp:340] ping_start(): 1 packets transmitted, 1 packets received, 0.0% packet loss
[ 18496][I][ping.cpp:349] ping_start(): round-trip min/avg/max/stddev = 33.731/33.731/33.731/0.000 ms

web is up
  Ping success in  197.51 msec:  expected count is 1 errors: 0 success: 1
[312446][I][ping.cpp:324] ping_start(): PING 0.0.0.0: 32 data bytes
[312486][I][ping.cpp:340] ping_start(): 1 packets transmitted, 1 packets received, 0.0% packet loss
[312495][I][ping.cpp:349] ping_start(): round-trip min/avg/max/stddev = 33.129/33.129/33.129/0.000 ms

web is up
  Ping success in  33.13 msec:  expected count is 1 errors: 0 success: 1
[318446][I][ping.cpp:324] ping_start(): PING 0.0.0.0: 32 data bytes
[318629][I][ping.cpp:340] ping_start(): 1 packets transmitted, 1 packets received, 0.0% packet loss
[318638][I][ping.cpp:349] ping_start(): round-trip min/avg/max/stddev = 176.868/176.868/176.868/0.000 ms

I see here that the URL 0.0.0.0 can be a valid address and will find responders on the system. However I'm not sure that this should defaullt to that value if the dns lookup fails.

pingOK = Ping.ping("responder.local", 1);

https://superuser.com/questions/949428/whats-the-difference-between-127-0-0-1-and-0-0-0-0

Sure, I can get around it by using a numeric url eg 192.168.1.23, but the responder wont always be at that address.

Is there a way to do a dns lookup to check the reponder before trying the ping?

interesting..

don't see why not..

can see how they do this in the lib..

bool PingClass::ping(const char *host, byte count) {
    IPAddress remote_addr;

    if (WiFi.hostByName(host, remote_addr))
        return ping(remote_addr, count);

    return false;
}

wonder if the call to hostByName returns false??

~q

1 Like

How have you defined this host name to map to an IP address and is this host name also visible to other devices in your network ?

1 Like

Initially when I turn off the responder the WiFi.hostByName(host, remote_addr) returns the original assigned IP address; however seemingly the router must soon recognise its no longer there, and it looks as if the router then returns the 0.0.0.0 adddress. Code for my test program below.

05:54:33.808 -> IP address of responder.local is: 192.168.1.23
05:54:39.783 -> IP address of responder.local is: 192.168.1.23
05:54:45.785 -> IP address of responder.local is: 192.168.1.23
05:54:58.826 -> IP address of responder.local is: 0.0.0.0
05:55:11.802 -> IP address of responder.local is: 0.0.0.0

/*
* testing mDNS lookup on local network
*/

#include <WiFi.h>
#include "creds.h"

const char* hostname = "responder.local";
IPAddress remote_addr;

void connectWiFi() {
  WiFi.begin(ssid, password);
  delay(200); //allow time to connect
  // Wait until connection completed
  Serial.print("Connecting to AP...");
  while (WiFi.status() != WL_CONNECTED)  {
    delay(200);
    Serial.print(".");
  }
  Serial.println("Ok\n");
  Serial.print("IP number is ");
  Serial.print(WiFi.localIP());
  Serial.print("  MAC address is ");
  Serial.println(WiFi.macAddress());
}

void setup() {
  Serial.begin(115200);
  delay(5000);
  connectWiFi();
}

void loop() {
   if (WiFi.hostByName(hostname, remote_addr)) {
    Serial.print("IP address of ");
    Serial.print(hostname);
    Serial.print(" is: ");
    Serial.println(remote_addr);
  } else {
    Serial.print("Could not resolve hostname: ");
    Serial.println(hostname);
  }
  delay(6000);
}

I'm assuming that the reason I dont see the "Could not resolve hostname: " is because the router has just returned 0.0.0.0 as the IP address.

So I just need to test the returned IP address before I do the ping, and if its 0.0.0.0 I declare the ping has failed.

1 Like

I've included the code for my "ping responder" here just to complete the thread.

/*
ping responder on NodeMCU ESp8266: switch on d2, BLUE LED to ground on d1 via 1k: 
wifi doesnt turn back on very quickly compared to esp32 "restart"
very quick response to ping to URL, sometimes slower via mdns
added simple static web page
NB some data pins will prevent upload if connected.
*/

#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>       //support for multicast to assign name to ip address
#include <ESP8266WebServer.h>  //to create a web page response so a browser can see the unit
#include "creds.h"             // my wifi credentials
#include "webpage.h"           //simple web page to display

ESP8266WebServer server(80);  //create instance of server: need web page to give name on port scanner

constexpr int offOn = D2;  //
constexpr int bLED = D1;   //blue LED to show wifi state
bool oldX;                 //for checking / debouncing switch


void flashLed(int rate) {  //indicate wifi connecting
  digitalWrite(bLED, 1);
  delay(rate);
  digitalWrite(bLED, 0);
  delay(rate);
}

bool connectWiFi(int rate, String message) {
  bool success = 0;
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    flashLed(rate);  //fast flash to show we are in the loop and trying to connect
  }
  success=1;
  Serial.println(message);
  digitalWrite(bLED, 1);
  // Initialize mDNS
  if (!MDNS.begin("responder")) {
    Serial.println("Error setting up MDNS responder!");
  }
  Serial.println("mDNS responder started");
  return (success);
}

//Handles http request
void handleRoot() {
  String s = MAIN_page;
  server.send(200, "text/html", s);
}

void setup() {
  Serial.begin(115200);
  delay(5000);  //allow me time to clear serial monitor
  Serial.println("\n\n\n\n serial comms established");  //space after reset "junk"
  pinMode(offOn, INPUT_PULLUP);
  pinMode(bLED, OUTPUT);
  connectWiFi(200, "Connecting to WiFi network");
  Serial.print("Local IP: ");
  Serial.print(WiFi.localIP());
    Serial.print("Signal strength - RSSI: ");
  Serial.println(WiFi.RSSI());
  server.on("/", handleRoot);  //Associate handler function to path
  server.begin();              //Start server
  Serial.println("HTTP server started");
  oldX = digitalRead(offOn);
}

void loop() {
  server.handleClient();
  MDNS.update();

  bool newX = digitalRead(offOn);  //debounce?
  if (newX != oldX) {
    Serial.printf("Switch has changed now state %i \n", newX);
    oldX = newX;
    if (!newX) {  //switch is now OFF
      if (WiFi.status() == WL_CONNECTED) {
        WiFi.disconnect();
        Serial.println("wifi disconnected");
        digitalWrite(bLED, 0);
      }

    } else if (WiFi.status() != WL_CONNECTED) {  //switch is ON but  wifi not yet connected
      //WiFi.reconnect();  //reconnect doesnt work on esp8266 so start afresh
      connectWiFi(50, "re-connecting WiFi");
    }
  }
  delay(500);  //no need to debounce the switch
}

//web page display
const char MAIN_page[] PROGMEM = R"rawliteral(
  <!DOCTYPE HTML>
<HTML>
	<HEAD>
    <title>ESP8266 ping reponder</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
	</HEAD>
<BODY>
	<CENTER>
			 <h1>ESP8266 Ping Responder at responder.local</h1>
       <h1>&nbsp;</h1?
       <h2> This is just a page to give the unit a title on the network </h2>
       <h2>&nbsp;</h2>
       <h3> code is in the arduino 2 sketchbook, /nodeMCU/pingresponder </h3>
	</CENTER>	
</BODY>
</HTML>
)rawliteral";

OK. I think I see. The responder was responsible for registering and maintaining its own hostname in the network's "DNS" . Clearly this fails if the responder is not running. Good that you now have a solution.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.