get value from ESP8266-ping library

OK please be patient, I'm just learning about OOP!
The object of my code is to ping a set of URLs and flash leds to show each performance.
I'm using the Leoncini ESP8266-ping library, and developing from the only example program.
It all works, but I cant see how I can get EITHER the individual ping time - or better still the average ping time as a parameter in my program to control an LED.

I've tried setting a parameter inside the pinger.OnReceive or pinger.OnEnd functions, (bold)
to get the value in my program (in CASE ONE ) but it does not work - reports a zero.

Here is my program. The state machine works fine; the serial print is just for debugging.

BTW I know its clunky, when it works I'm hoping to put all the code to send the 5 pings, get the average, and manage the associated LED into a function. So any help there would be appreciated.

#include <Pinger.h>
#include <ESP8266WiFi.h>
extern "C"
{
#include <lwip/icmp.h> // needed for icmp packet definitions
}



const char* ssid     = "XXXXXXXXXXXXXX";
const char* password = "XXXXXXXXXXX";

int pingTime, pingAvg;

// Set global to avoid object removing after setup() routine
Pinger pinger;

void setup()
{
  // Begin serial connection at 9600 baud
  Serial.begin(115200);
  delay(1000); // serial comms is disturbed during a restart

  // Connect to WiFi access point
  bool stationConnected = WiFi.begin(ssid, password);
  delay(200); //allow time to connect

  // Check if connection errors
  if (!stationConnected)
  {
    Serial.println("Error, unable to connect specified WiFi network.");
  }

  // Wait until connection completed
  Serial.print("Connecting to AP...");
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(200);
    Serial.print(".");
  }
  Serial.print("Ok\n");

  //Next bits from sketch_jun27b  edited

  pinger.OnReceive([](const PingerResponse & response)
  {
    if (response.ReceivedResponse)
    {
      Serial.print("ping response time is ");
      Serial.print(response.ResponseTime);
      Serial.println(" msec");
    }
    else
    {
      Serial.printf("Request timed out.\n");
    }

    // Return true to continue the ping sequence.
    // If current event returns false, the ping sequence is interrupted.
    return true;
  });

  pinger.OnEnd([](const PingerResponse & response)
  {
    // Evaluate lost packet percentage
    float loss = 100;
    if (response.TotalReceivedResponses > 0)
    {
      loss = (response.TotalSentRequests - response.TotalReceivedResponses) * 100 / response.TotalSentRequests;
    }

    // Print packet trip data
    Serial.printf(
      "Ping statistics for %s:\n",
      response.DestIPAddress.toString().c_str());
    Serial.printf(
      "    Packets: Sent = %lu, Received = %lu, Lost = %lu (%.2f%% loss),\n",
      response.TotalSentRequests,
      response.TotalReceivedResponses,
      response.TotalSentRequests - response.TotalReceivedResponses,
      loss);

    // Print time information
    if (response.TotalReceivedResponses > 0)
    {
      Serial.printf("Approximate round trip times in milli-seconds:\n");
      Serial.printf(
        "    Minimum = %lums, Maximum = %lums, Average = %.2fms\n",
        response.MinResponseTime,
        response.MaxResponseTime,
        response.AvgResponseTime);
    }

    // Print host data
    Serial.printf("Destination host data:\n");
    Serial.printf(
      "    IP address: %s\n",
      response.DestIPAddress.toString().c_str());
    if (response.DestMacAddress != nullptr)
    {
      Serial.printf(
        "    MAC address: " MACSTR "\n",
        MAC2STR(response.DestMacAddress->addr));
    }
    if (response.DestHostname != "")
    {
      Serial.printf(
        "    DNS name: %s\n",
        response.DestHostname.c_str());
    }
   [b] pingAvg = response.AvgResponseTime;[/b]
    return true;
  });
}

void loop()
{

  static unsigned long timeReady, timeNow, timeLost = 0, timeASM = 0; //recording millis() times
  enum target { ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX }; //different targets to ping
  static byte target = ZERO;
  static bool ASMStatus = 0;
  int pingAvg = 0;

  switch ( target ) {
    case ZERO: {
        Serial.println("zero:");
        target = ONE;
        timeASM = millis();
      }

    case ONE: {
        timeReady = millis() - timeASM;
        if (timeReady >= 10000 )
        {
          // Ping default gateway
          Serial.printf("\n\nPinging default gateway with IP %s\n",
                        WiFi.gatewayIP().toString().c_str());
          if (pinger.Ping(WiFi.gatewayIP(), 5, 200) == false)
          {
            Serial.println("Error during last ping command.");
          }

          
          Serial.print("Average ping is ");
          Serial.println(pingAvg);
          // then I'd have some code to use the parameter to control LED1.
          

          //done this ping, get ready for next
          target = TWO;
          timeASM = millis();
        }
        break;
      }


    case TWO: {
      timeReady = millis() - timeASM;
        if (timeReady >= 6000 )
        {
          // Ping RYZEN5
          Serial.printf("\n\nPinging RYZEN5 on ip 192.168.1.11\n");
          if (pinger.Ping(IPAddress(192, 168, 1, 11), 5, 200) == false)
          {
            Serial.println("Error during ping command.");
          }
          Serial.print("Average ping is ");
          Serial.println(pingAvg);

          // then I'd have some code to use the parameter to control LED2.

          //done this ping, get ready for next
          target = THREE;
          timeASM = millis();
        }
        break;
      }

    case THREE: {
      timeReady = millis() - timeASM;
        if (timeReady >= 3000 )
        {
          // Ping network printer
          Serial.printf("\n\nPinging network printer on ip 192.168.1.22\n");
          if (pinger.Ping(IPAddress(192, 168, 1, 22), 5, 200) == false)
          {
            Serial.println("Error during ping command.");
          }
          Serial.print("Average ping is ");
          Serial.println(pingAvg);
          //done this ping, get ready for next
          target = FOUR;
          timeASM = millis();
        }
        break;
      }

    case FOUR: {
      timeReady = millis() - timeASM;
        if (timeReady >= 3000 )
        {
          // Ping technologytourist.com
          Serial.printf("\n\nPinging technologytourist.com\n");
          if (pinger.Ping("technologytourist.com", 5, 200) == false)
          {
            Serial.println("Error during ping command.");
          }
          Serial.print("Average ping is ");
          Serial.println(pingAvg);
          //done this ping, get ready for next
          target = FIVE;
          timeASM = millis();
        }
        break;
      }

    case FIVE: {
      timeReady = millis() - timeASM;
        if (timeReady >= 3000 )
        {
          // Ping NAS box
          Serial.printf("\n\nPinging NAS box on ip 192.168.1.24\n");
          if (pinger.Ping(IPAddress(192, 168, 1, 24), 5, 200) == false)
          {
            Serial.println("Error during ping command.");
          }
          Serial.print("Average ping is ");
          Serial.println(pingAvg);
          //done this ping, get ready for next
          target = SIX;
          timeASM = millis();
        }
        break;
      }

    case SIX: {
       timeReady = millis() - timeASM;
        if (timeReady >= 2000 )
        {
          // Ping GEOBRDG
          Serial.printf("\n\nPinging GEOBRDG on ip 192.168.1.14\n");
          if (pinger.Ping(IPAddress(192, 168, 1, 14), 5, 200) == false)
          {
            Serial.println("Error during ping command.");
          }
          Serial.print("Average ping is ");
          Serial.println(pingAvg);
        Serial.println("Completed one set of pings to all targets");
        target = ZERO;
        timeASM = millis();
      }
    }
  }//switch


}

Output on serial monitor (case 6) follows:
Pinging GEOBRDG on ip 192.168.1.14
Average ping is 0
ping response time is 72 msec
Request timed out.
ping response time is 151 msec
ping response time is 109 msec
ping response time is 68 msec
Ping statistics for 192.168.1.14:
Packets: Sent = 5, Received = 4, Lost = 1 (20.00% loss),
Approximate round trip times in milli-seconds:
Minimum = 68ms, Maximum = 151ms, Average = 100.00ms

"Does not work" is never a helpful description of a problem. What where you expecting? What did you get instead?

A quick glance at the library shows that response.AvgResponseTime is a variable of type 'float' but you are assigning it to an 'int' so any fraction will be truncated.

Thanks BLH comments noted and I've edited my q . I'm happy to truncate as I'll be using the integer value to control an LED. Average<80 good (solid light) 80-199 slow, flashing LED, 200 = time out LED off.

A couple of things.

  1. you declare a local variable inside loop called pingAvg which will hide your global version. The global version is what is getting set by your response.end() function.

  2. That call to ping() will return immediately, before the actual ping'ing is complete. That is why you are seeing the "Average ping is 0" line before any of the pings. You have to wait, Rather than just use time, I introduced a variable called isFinished which gets set to true by the pinger.onEnd() function. Now your case statements can just stay in their current state until that variable is true and you know you are finished so print the average and move on.

  3. Have't tried the code since I don't have the ESP8266 stuff installed.

#include <Pinger.h>
#include <ESP8266WiFi.h>
extern "C"
{
#include <lwip/icmp.h> // needed for icmp packet definitions
}

const char* ssid     = "XXXXXXXXXXXXXX";
const char* password = "XXXXXXXXXXX";

int pingTime, pingAvg;
bool isFinsihed;

// Set global to avoid object removing after setup() routine
Pinger pinger;

void setup()
{
  // Begin serial connection at 9600 baud
  Serial.begin(115200);
  delay(1000); // serial comms is disturbed during a restart

  // Connect to WiFi access point
  bool stationConnected = WiFi.begin(ssid, password);
  delay(200); //allow time to connect

  // Check if connection errors
  if (!stationConnected)
  {
    Serial.println("Error, unable to connect specified WiFi network.");
  }

  // Wait until connection completed
  Serial.print("Connecting to AP...");
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(200);
    Serial.print(".");
  }
  Serial.print("Ok\n");

  //Next bits from sketch_jun27b  edited

  pinger.OnReceive([](const PingerResponse & response)
  {
    if (response.ReceivedResponse)
    {
      Serial.print("ping response time is ");
      Serial.print(response.ResponseTime);
      Serial.println(" msec");
    }
    else
    {
      Serial.printf("Request timed out.\n");
    }

    // Return true to continue the ping sequence.
    // If current event returns false, the ping sequence is interrupted.
    return true;
  });

  pinger.OnEnd([](const PingerResponse & response)
  {
    // Evaluate lost packet percentage
    float loss = 100;
    if (response.TotalReceivedResponses > 0)
    {
      loss = (response.TotalSentRequests - response.TotalReceivedResponses) * 100 / response.TotalSentRequests;
    }

    // Print packet trip data
    Serial.printf(
      "Ping statistics for %s:\n",
      response.DestIPAddress.toString().c_str());
    Serial.printf(
      "    Packets: Sent = %lu, Received = %lu, Lost = %lu (%.2f%% loss),\n",
      response.TotalSentRequests,
      response.TotalReceivedResponses,
      response.TotalSentRequests - response.TotalReceivedResponses,
      loss);

    // Print time information
    if (response.TotalReceivedResponses > 0)
    {
      Serial.printf("Approximate round trip times in milli-seconds:\n");
      Serial.printf(
        "    Minimum = %lums, Maximum = %lums, Average = %.2fms\n",
        response.MinResponseTime,
        response.MaxResponseTime,
        response.AvgResponseTime);
    }

    // Print host data
    Serial.printf("Destination host data:\n");
    Serial.printf(
      "    IP address: %s\n",
      response.DestIPAddress.toString().c_str());
    if (response.DestMacAddress != nullptr)
    {
      Serial.printf(
        "    MAC address: " MACSTR "\n",
        MAC2STR(response.DestMacAddress->addr));
    }
    if (response.DestHostname != "")
    {
      Serial.printf(
        "    DNS name: %s\n",
        response.DestHostname.c_str());
    }
    pingAvg = int(response.AvgResponseTime + 0.5);
    isFinished = true;
    return true;
  });
}

void loop()
{

  static unsigned long timeReady, timeNow, timeLost = 0, timeASM = 0; //recording millis() times
  enum target { ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX }; //different targets to ping
  static byte target = ZERO;
  static bool ASMStatus = 0;
  //  int pingAvg = 0;

  switch ( target ) {
    case ZERO: {
        Serial.println("zero:");
        target = ONE;
        timeASM = millis();
        isFinished = false;
        // Ping default gateway
        Serial.printf("\n\nPinging default gateway with IP %s\n",
                      WiFi.gatewayIP().toString().c_str());
        if (pinger.Ping(WiFi.gatewayIP(), 5, 200) == false)
        {
          Serial.println("Error during last ping command.");
        }
      }
      break;

    case ONE:
      if (isFinished == true )
      {
        Serial.print("Average ping is ");
        Serial.println(pingAvg);
        // then I'd have some code to use the parameter to control LED1.
        //done this ping, get ready for next
        target = TWO;
        isFinished = false;
        // Ping RYZEN5
        Serial.printf("\n\nPinging RYZEN5 on ip 192.168.1.11\n");
        if (pinger.Ping(IPAddress(192, 168, 1, 11), 5, 200) == false)
        {
          Serial.println("Error during ping command.");
        }
      }
      break;

    case TWO:
      if (isFinished == true )
      {
        Serial.print("Average ping is ");
        Serial.println(pingAvg);

        // then I'd have some code to use the parameter to control LED2.

        //done this ping, get ready for next
        target = THREE;
        isFinished = false;
        // Ping network printer
        Serial.printf("\n\nPinging network printer on ip 192.168.1.22\n");
        if (pinger.Ping(IPAddress(192, 168, 1, 22), 5, 200) == false)
        {
          Serial.println("Error during ping command.");
        }
      }
      break;

    case THREE:
      if (isFinished == true )
      {
        Serial.print("Average ping is ");
        Serial.println(pingAvg);

        //done this ping, get ready for next
        target = FOUR;
        isFinished = false;
        // Ping technologytourist.com
        Serial.printf("\n\nPinging technologytourist.com\n");
        if (pinger.Ping("technologytourist.com", 5, 200) == false)
        {
          Serial.println("Error during ping command.");
        }
      }
      break;

    case FOUR:
      if (isFinished == true )
      {
        Serial.print("Average ping is ");
        Serial.println(pingAvg);

        //done this ping, get ready for next
        target = FIVE;
        isFinished = false;
        // Ping NAS box
        Serial.printf("\n\nPinging NAS box on ip 192.168.1.24\n");
        if (pinger.Ping(IPAddress(192, 168, 1, 24), 5, 200) == false)
        {
          Serial.println("Error during ping command.");
        }
      }
      break;

    case FIVE:
      if (isFinished == true )
      {
        Serial.print("Average ping is ");
        Serial.println(pingAvg);
        target = SIX;
        isFinished = false;
        // Ping GEOBRDG
        Serial.printf("\n\nPinging GEOBRDG on ip 192.168.1.14\n");
        if (pinger.Ping(IPAddress(192, 168, 1, 14), 5, 200) == false)
        {
          Serial.println("Error during ping command.");
        }
      }
      break;

    case SIX:
      if (isFinished == true )
      {
        Serial.print("Average ping is ");
        Serial.println(pingAvg);
        Serial.println("Completed one set of pings to all targets");
        target = ZERO;
        isFinished = false;
      }
      break;
  }//switch
}

Thanks BLH you fixed it AND I can understand your solution; youre a star!
Working now on using the LEDs and creating an array of struct for the IP addresses.
May need your help again soon!

BLH, could I ask your help again?
The esp8266 library ESP8266-ping - Arduino Libraries

is giving me wrong answers to the average ping time;
I have timeout set to 200ms, and I'm pinging a device that responds erratically.
Its reporting an average ping time that is mostly believable - but sometimes as much as 350msec.

I checked Alessandro's website and github, they arent active.

I wonder if you would have a quick look at his code? I'm not OOP savvy!

I can look at the library, but that is useless without the context of your sketch that is giving you wrong information. Post your code.

Thanks BLH

/*****************************************************************************
  Arduino library handling ping messages for the esp8266 platform
  MIT License  Copyright (c) 2018 Alessio Leoncini

  Rui Santos: Complete project details at https://randomnerdtutorials.com/esp32-ntp-client-date-time-arduino-ide/
  This requires the  NTP Client library forked by Taranais. https://github.com/taranais/NTPClient

****************************************************************************
*/

#include <Pinger.h>
#include <ESP8266WiFi.h>
#include <core_esp8266_waveform.h>
#include <NTPClient.h>
#include <WiFiUdp.h>

extern "C"
{
#include <lwip/icmp.h> // needed for icmp packet definitions
}

// to do the pin mapping for the Lolin NodeMCU pins D0 - D8
const int dPin[] = {16, 5, 4, 0, 2, 14, 12, 13, 15};

const char* ssid     = "TALKTALKCC34C4";
const char* password = "MVGGX799";

//recording millis() times & set to repeat every 10 second
unsigned long previousMillis = 0;
unsigned long currentMillis;
const long interval = 1000;
bool roundComplete, setComplete = 0; //flags all 1 round to a single target,  or all 1 set of pings done

//data for ping:
int pingNumber = 5; //do 5 pings per set
int pingTime = 200; //200ms timeout
byte target = 0; //state machine control and select url to ping

struct host {
  byte IP[4];
  int tPing;
  int nLost;
};

//create data set of type host, &  initialise our struct for all cases
host host1[7] = {
  {{192, 168, 1, 1}, 0, 0 } ,  //0; router
  {{192, 168, 1, 11}, 0, 0 } , //1: RYZEN5
  {{192, 168, 1, 21}, 0, 0 } , //2: FILES
  {{192, 168, 1, 22}, 0, 0 } , //3: LP
  {{192, 168, 1, 14}, 0, 0 } , //4: GeoBRDG
  {{192, 168, 1, 24}, 0, 0 } , //5: NAS
  {{107, 162, 133, 62}, 0, 0 } //6: TalkTalk
};

// Define NTP Client to get time
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org");
String formattedDate, myFormattedDate;
String dayStamp;
String timeStamp;
const int nRounds = 43; //number of full rounds to complete before calling ntp
//1 round takes 7 sec. approx; so 1 min = 8.6 rounds; 5 min = 43 rounds
int count = 0; // number of rounds completed:  call ntp and save to SD every 5 min

int pingAvg;
int pingsLost;
bool isFinished;

// Set global to avoid object removing after setup() routine
Pinger pinger;

bool PerformPing()
{
  if (roundComplete)  //ready for next set of pings
  {
    //Serial.print(" target ");     Serial.print(target);     Serial.println(" sending ping ");
    isFinished = false;
    int url = target;
    bool pingOK = pinger.Ping(IPAddress(host1[url].IP), pingNumber, pingTime);
    roundComplete = false;
  }
  else if (isFinished) // one set of pings to a single target complete and results in
  { //Serial.print(" target ");     Serial.print(target);     Serial.println(" values in ");
    isFinished = false;
    host1[target].tPing = pingAvg;
    host1[target].nLost = pingsLost;
    roundComplete = true;
    target++;
    if (target == 7) {
      setComplete = true; //done 1 round to all targets
      //Serial.print(" target ");     Serial.print(target);     Serial.println(" set complete ");
    } else {
      setComplete = false;
    }
  }
  return true;
}

int showLEDs()
{
  //flash LEDs according to number of lost (or good) pings.
  Serial.print("loss values: ");
  for (int n = 0; n <= 6; n++) {
    //print loss values and ping averages
    Serial.print(n); Serial.print(": "); Serial.print(host1[n].nLost); Serial.print(" / "); Serial.print(host1[n].tPing); Serial.print(";    ");
    //the lower limit on analogWrite() is 100Hz, but startWaveform() doesn’t have that limit:
    startWaveform(dPin[7-n], (host1[n].nLost * 50000) + 10, ((5 - host1[n].nLost ) * 50000) + 10, 0); //using lost pings: 0=LED ON, 1-4 = flashing, 5=LED OFF
  }
  Serial.println("");
  target++;
  return target;
}

void getTime()
{
  if (count >= nRounds) { //we have done nRounds of sets of pings to all targets so get date and time
    timeClient.update();
    formattedDate = timeClient.getFormattedDate();
    // Extract date
    int splitT = formattedDate.indexOf("T");
    dayStamp = formattedDate.substring(0, splitT);
    //Serial.println(dayStamp);
    // Extract time
    timeStamp = formattedDate.substring(splitT + 1, formattedDate.length() - 1);
    //Serial.println(timeStamp);
    myFormattedDate = String(dayStamp) + ", " +  String(timeStamp);
    Serial.print("my Formatted Date: ");
    Serial.println(myFormattedDate);
    Serial.println("");
    count = 0;
  } else {
    count++;
  }
  target = 0;
}

void setup()
{
  // Begin serial connection at 74880 baud
  Serial.begin(74880);
  delay(1000); // serial comms is disturbed during a restart

  //set up LED pins as outputs & HIGH (LEDs all off)
  for (int i = 0; i <= 8; i++) {
    pinMode(dPin[i], OUTPUT);
    digitalWrite(dPin[i], 1);
  }

  // Connect to WiFi access point
  digitalWrite(dPin[0], 1); //indicate wifi not connected
  bool stationConnected = WiFi.begin(ssid, password);
  delay(200); //allow time to connect

  // Check if connection errors
  if (!stationConnected)
  {
    Serial.println("Error, unable to connect specified WiFi network.");
  }

  // Wait until connection completed
  Serial.print("Connecting to AP...");
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(200);
    Serial.print(".");
  }
  Serial.print("Ok\n");
  digitalWrite(dPin[0], 0); //indicate wifi connected

  // Initialize a NTPClient to get time
  timeClient.begin();
  // Set offset time in seconds to adjust for your timezone, eg GMT +1 = 3600
  timeClient.setTimeOffset(0);

  roundComplete = true;  //ready to start a new set of pings

  pinger.OnReceive([](const PingerResponse & response)
  {
    return true;  // Return true to continue the ping sequence. If current event returns false, the ping sequence is interrupted.
  });

  pinger.OnEnd([](const PingerResponse & response)
  {
    pingAvg = int(response.AvgResponseTime + 0.5); //ensure pingAvg can not be zero as zero will be used to flag no response.
    pingsLost = response.TotalSentRequests - response.TotalReceivedResponses;
    isFinished = true;  //marks all pings to that target completed
    return true;
  });
}

void loop()
{
  if (WiFi.status() == WL_CONNECTED) digitalWrite(dPin[0], 0); else digitalWrite(dPin[0], 1);

  if (target >= 0 && target <= 6) {
    PerformPing();  //ping each target in turn starting at zero
  }

  if (target == 7) showLEDs();

  if (target == 8) getTime();

}//loop

I'm not sure the problem is in the library. You have a lot of different flow control spread out throughout your code. It is better to have a function do a single thing (like ping one IP address) and have the control inside of loop. Give this code a try and see if it performs any better.

/*****************************************************************************
  Arduino library handling ping messages for the esp8266 platform
  MIT License  Copyright (c) 2018 Alessio Leoncini

  Rui Santos: Complete project details at https://randomnerdtutorials.com/esp32-ntp-client-date-time-arduino-ide/
  This requires the  NTP Client library forked by Taranais. https://github.com/taranais/NTPClient

****************************************************************************
*/

#include <Pinger.h>
#include <ESP8266WiFi.h>
#include <core_esp8266_waveform.h>
#include <NTPClient.h>
#include <WiFiUdp.h>

extern "C"
{
#include <lwip/icmp.h> // needed for icmp packet definitions
}

// to do the pin mapping for the Lolin NodeMCU pins D0 - D8
const int dPin[] = {16, 5, 4, 0, 2, 14, 12, 13, 15};
const int numPins = sizeof(dPin) / sizeof(dPin[0]);

const char* ssid     = "TALKTALKCC34C4";
const char* password = "MVGGX799";

//recording millis() times to update NTP
unsigned long lastNTPUpdateTime = 0;
const unsigned long NTPInterval = 5 * 60000UL;


//data for ping:
const int pingNumber = 5; //do 5 pings per set
const int pingTime = 200; //200ms timeout
byte target = 0; //state machine control and select url to ping

struct host {
  byte IP[4];
  int tPing;
  int nLost;
};

//create data set of type host, &  initialise our struct for all cases
struct host hostList[] = {
  {{192, 168, 1, 1}, 0, 0 } ,  //0; router
  {{192, 168, 1, 11}, 0, 0 } , //1: RYZEN5
  {{192, 168, 1, 21}, 0, 0 } , //2: FILES
  {{192, 168, 1, 22}, 0, 0 } , //3: LP
  {{192, 168, 1, 14}, 0, 0 } , //4: GeoBRDG
  {{192, 168, 1, 24}, 0, 0 } , //5: NAS
  {{107, 162, 133, 62}, 0, 0 } //6: TalkTalk
};
const int numHosts = sizeof(hostList) / sizeof(hostList[0]);
int target = 0;  // current index into hostList[].  Needs to be global to use inside .onEnd()

// Define NTP Client to get time
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org");
String formattedDate, myFormattedDate;
String dayStamp;
String timeStamp;
const int nRounds = 43; //number of full rounds to complete before calling ntp
//1 round takes 7 sec. approx; so 1 min = 8.6 rounds; 5 min = 43 rounds
int count = 0; // number of rounds completed:  call ntp and save to SD every 5 min

volatile bool isFinished;

// Set global to avoid object removing after setup() routine
Pinger pinger;

void setup()
{
  // Begin serial connection at 74880 baud
  Serial.begin(74880);
  delay(1000); // serial comms is disturbed during a restart

  //set up LED pins as outputs & HIGH (LEDs all off)
  for (int i = 0; i < numPins; i++) {
    pinMode(dPin[i], OUTPUT);
    digitalWrite(dPin[i], HIGH);
  }

  // Connect to WiFi access point
  digitalWrite(dPin[0], HIGH); //indicate wifi not connected
  bool stationConnected = WiFi.begin(ssid, password);
  delay(200); //allow time to connect

  // Check if connection errors
  if (!stationConnected) {
    Serial.println("Error, unable to connect specified WiFi network.");
  }

  // Wait until connection completed
  Serial.print("Connecting to AP...");
  while (WiFi.status() != WL_CONNECTED) {
    delay(200);
    Serial.print(".");
  }
  Serial.print("Ok\n");
  digitalWrite(dPin[0], LOW); //indicate wifi connected

  // Initialize a NTPClient to get time
  timeClient.begin();
  // Set offset time in seconds to adjust for your timezone, eg GMT +1 = 3600
  timeClient.setTimeOffset(0);
  lastNTPUpdateTime = millis() - NTPInterval - 1;   // force initial time fetch
  getTime();
  
  pinger.OnReceive([](const PingerResponse & response)
  {
    return true;  // Return true to continue the ping sequence. If current event returns false, the ping sequence is interrupted.
  });

  pinger.OnEnd([](const PingerResponse & response)
  {
    hostList[target].tPing = int(response.AvgResponseTime + 0.5);
    hostList[target].nLost = response.TotalSentRequests - response.TotalReceivedResponses;
    isFinished = true;  //marks all pings to that target completed
    return true;
  });
}

void loop()
{
  if (WiFi.status() == WL_CONNECTED) {
    digitalWrite(dPin[0], LOW);
  } else {
    digitalWrite(dPin[0], HIGH);
  }

  bool resultOK = PerformPing();
  if ( resultOK == false ) {
    Serial.println("Bad Ping");
  }
  target++;
  if (target == numHosts ) {
    // all done, show results
    showLEDs();
    target = 0;
  }
  getTime();

}//loop

bool PerformPing()
{
  Serial.print("Pinging target ");
  Serial.print(target);
  Serial.print(": ");
  Serial.println(hostList[target].IP);
  isFinished = false;
  hostList[target].tPing = -1;
  hostList[target].nLost = -1;
  bool pingOK = pinger.Ping(hostList[target].IP), pingNumber, pingTime);
  if ( pingOK == false ) return false;

  // wait here for isFinished to get set on by the Pinger.onEnd() function
  while ( isFinished == false ) {
    delay(50);
    }
  // one set of pings to a single target complete and results in
  //Serial.print(" target ");     Serial.print(target);     Serial.println(" values in ");
  hostList[target].tPing = pingAvg;
  hostList[target].nLost = pingsLost;
  return true;
}

void showLEDs()
{
  //flash LEDs according to number of lost (or good) pings.
  Serial.print("loss values: ");
  for (int n = 0; n < numHosts; n++) {
    //print loss values and ping averages
    Serial.print(n);
    Serial.print(": ");
    Serial.print(hostList[n].nLost);
    Serial.print(" / ");
    Serial.print(hostList[n].tPing);
    Serial.print(";    ");
    //the lower limit on analogWrite() is 100Hz, but startWaveform() doesn't have that limit:
    startWaveform(dPin[numHosts - n], (hostList[n].nLost * 50000) + 10, ((5 - hostList[n].nLost ) * 50000) + 10, 0); //using lost pings: 0=LED ON, 1-4 = flashing, 5=LED OFF
  }
  Serial.println("");
}

void getTime()
{
  if ( millis() - lastNTPUpdateTime >= NTPInterval ) {
    lastNTPUpdateTime += NTPInterval;
    timeClient.update();
    formattedDate = timeClient.getFormattedDate();
    // Extract date
    int splitT = formattedDate.indexOf("T");
    dayStamp = formattedDate.substring(0, splitT);
    //Serial.println(dayStamp);
    // Extract time
    timeStamp = formattedDate.substring(splitT + 1, formattedDate.length() - 1);
    //Serial.println(timeStamp);
    myFormattedDate = String(dayStamp) + ", " +  String(timeStamp);
    Serial.print("my Formatted Date: ");
    Serial.println(myFormattedDate);
    Serial.println("");
  }
}

Thanks BLH (name?)
I had a few errors to put right - listed here; just variable declarations (below) and a missed opening bracket.

//byte target = 0; //state machine control and select url to ping
int pingAvg;
int pingsLost;

Serial.println(hostList[target].IP);
call of overloaded 'println(byte [4])' is ambiguous (I commented it out)

bool pingOK = pinger.Ping(hostList[target].IP), pingNumber, pingTime);

I see what you mean about flow control puting it in the loop makes it more obvious.

I think I've made it hard for myself by writing it as a state machine, but I'm hoping it will store times to spiffs memory from ntp and I will need to access them via the network - so I dont think I can use the "wait for Is Finished".

// wait here for isFinished to get set on by the Pinger.onEnd() function
  while ( isFinished == false ) {
    delay(50);
    }

Thanks also for showing me how to get the size of an array.

However the flow control in your program is not working, and I'm not getting any results.
Here is the output

Pinging target 0: Pinging target 1: Pinging target 2: Pinging target 3: Pinging target 4: Pinging target 5: Pinging target 6: loss values: 0: 0 / 0;    1: 0 / 0;    2: 0 / 0;    3: 0 / 0;    4: 0 / 0;    5: 0 / 0;    6: 0 / 0;    
Pinging target 0: Pinging target 1: Pinging target 2: Pinging target 3: Pinging target 4: Pinging target 5: Pinging target 6: loss values: 0: 0 / 0;    1: 0 / 0;    2: 0 / 0;    3: 0 / 0;    4: 0 / 0;    5: 0 / 0;    6: 0 / 0;    
Pinging target 0: Pinging target 1: Pinging target 2: Pinging target 3: Pinging target 4: Pinging target 5: my Formatted Date: 2020-07-08, 05:06:36

Pinging target 6: loss values: 0: 0 / 0;    1: 0 / 0;    2: 0 / 0;    3: 0 / 0;    4: 0 / 0;    5: 0 / 0;    6: 0 / 0;

I've reposted the code here in case my corrections have broken it.

/*****************************************************************************
  Arduino library handling ping messages for the esp8266 platform
  MIT License  Copyright (c) 2018 Alessio Leoncini

  Rui Santos: Complete project details at https://randomnerdtutorials.com/esp32-ntp-client-date-time-arduino-ide/
  This requires the  NTP Client library forked by Taranais. https://github.com/taranais/NTPClient

****************************************************************************
*/

#include <Pinger.h>
#include <ESP8266WiFi.h>
#include <core_esp8266_waveform.h>
#include <NTPClient.h>
#include <WiFiUdp.h>

extern "C"
{
#include <lwip/icmp.h> // needed for icmp packet definitions
}

// to do the pin mapping for the Lolin NodeMCU pins D0 - D8
const int dPin[] = {16, 5, 4, 0, 2, 14, 12, 13, 15};
const int numPins = sizeof(dPin) / sizeof(dPin[0]);

const char* ssid     = "TALKTALKCC34C4";
const char* password = "MVGGX799";

//recording millis() times to update NTP
unsigned long lastNTPUpdateTime = 0;
const unsigned long NTPInterval = 5 * 60000UL;


//data for ping:
const int pingNumber = 5; //do 5 pings per set
const int pingTime = 200; //200ms timeout
//byte target = 0; //state machine control and select url to ping
int pingAvg;
int pingsLost;

struct host {
  byte IP[4];
  int tPing;
  int nLost;
};

//create data set of type host, &  initialise our struct for all cases
struct host hostList[] = {
  {{192, 168, 1, 1}, 0, 0 } ,  //0; router
  {{192, 168, 1, 11}, 0, 0 } , //1: RYZEN5
  {{192, 168, 1, 21}, 0, 0 } , //2: FILES
  {{192, 168, 1, 22}, 0, 0 } , //3: LP
  {{192, 168, 1, 14}, 0, 0 } , //4: GeoBRDG
  {{192, 168, 1, 24}, 0, 0 } , //5: NAS
  {{107, 162, 133, 62}, 0, 0 } //6: TalkTalk
};
const int numHosts = sizeof(hostList) / sizeof(hostList[0]);
int target = 0;  // current index into hostList[].  Needs to be global to use inside .onEnd()

// Define NTP Client to get time
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org");
String formattedDate, myFormattedDate;
String dayStamp;
String timeStamp;
const int nRounds = 43; //number of full rounds to complete before calling ntp
//1 round takes 7 sec. approx; so 1 min = 8.6 rounds; 5 min = 43 rounds
int count = 0; // number of rounds completed:  call ntp and save to SD every 5 min

volatile bool isFinished;

// Set global to avoid object removing after setup() routine
Pinger pinger;

void setup()
{
  // Begin serial connection at 74880 baud
  Serial.begin(74880);
  delay(1000); // serial comms is disturbed during a restart

  //set up LED pins as outputs & HIGH (LEDs all off)
  for (int i = 0; i < numPins; i++) {
    pinMode(dPin[i], OUTPUT);
    digitalWrite(dPin[i], HIGH);
  }

  // Connect to WiFi access point
  digitalWrite(dPin[0], HIGH); //indicate wifi not connected
  bool stationConnected = WiFi.begin(ssid, password);
  delay(200); //allow time to connect

  // Check if connection errors
  if (!stationConnected) {
    Serial.println("Error, unable to connect specified WiFi network.");
  }

  // Wait until connection completed
  Serial.print("Connecting to AP...");
  while (WiFi.status() != WL_CONNECTED) {
    delay(200);
    Serial.print(".");
  }
  Serial.print("Ok\n");
  digitalWrite(dPin[0], LOW); //indicate wifi connected

  // Initialize a NTPClient to get time
  timeClient.begin();
  // Set offset time in seconds to adjust for your timezone, eg GMT +1 = 3600
  timeClient.setTimeOffset(0);
  lastNTPUpdateTime = millis() - NTPInterval - 1;   // force initial time fetch
  getTime();
 
  pinger.OnReceive([](const PingerResponse & response)
  {
    return true;  // Return true to continue the ping sequence. If current event returns false, the ping sequence is interrupted.
  });

  pinger.OnEnd([](const PingerResponse & response)
  {
    hostList[target].tPing = int(response.AvgResponseTime + 0.5);
    hostList[target].nLost = response.TotalSentRequests - response.TotalReceivedResponses;
    isFinished = true;  //marks all pings to that target completed
    return true;
  });
}

void loop()
{
  if (WiFi.status() == WL_CONNECTED) {
    digitalWrite(dPin[0], LOW);
  } else {
    digitalWrite(dPin[0], HIGH);
  }

  bool resultOK = PerformPing();
  if ( resultOK == false ) {
    Serial.println("Bad Ping");
  }
  target++;
  if (target == numHosts ) {
    // all done, show results
    showLEDs();
    target = 0;
  }
  getTime();

}//loop

bool PerformPing()
{
  Serial.print("Pinging target ");
  Serial.print(target);
  Serial.print(": ");
//  Serial.println(hostList[target].IP);
  isFinished = false;
  hostList[target].tPing = -1;
  hostList[target].nLost = -1;
  bool pingOK = pinger.Ping((hostList[target].IP), pingNumber, pingTime);
  if ( pingOK == false ) return false;

  // wait here for isFinished to get set on by the Pinger.onEnd() function
  while ( isFinished == false ) {
    delay(50);
    }
  // one set of pings to a single target complete and results in
  //Serial.print(" target ");     Serial.print(target);     Serial.println(" values in ");
  hostList[target].tPing = pingAvg;
  hostList[target].nLost = pingsLost;
  return true;
}

void showLEDs()
{
  //flash LEDs according to number of lost (or good) pings.
  Serial.print("loss values: ");
  for (int n = 0; n < numHosts; n++) {
    //print loss values and ping averages
    Serial.print(n);
    Serial.print(": ");
    Serial.print(hostList[n].nLost);
    Serial.print(" / ");
    Serial.print(hostList[n].tPing);
    Serial.print(";    ");
    //the lower limit on analogWrite() is 100Hz, but startWaveform() doesn't have that limit:
    startWaveform(dPin[numHosts - n], (hostList[n].nLost * 50000) + 10, ((5 - hostList[n].nLost ) * 50000) + 10, 0); //using lost pings: 0=LED ON, 1-4 = flashing, 5=LED OFF
  }
  Serial.println("");
}

void getTime()
{
  if ( millis() - lastNTPUpdateTime >= NTPInterval ) {
    lastNTPUpdateTime += NTPInterval;
    timeClient.update();
    formattedDate = timeClient.getFormattedDate();
    // Extract date
    int splitT = formattedDate.indexOf("T");
    dayStamp = formattedDate.substring(0, splitT);
    //Serial.println(dayStamp);
    // Extract time
    timeStamp = formattedDate.substring(splitT + 1, formattedDate.length() - 1);
    //Serial.println(timeStamp);
    myFormattedDate = String(dayStamp) + ", " +  String(timeStamp);
    Serial.print("my Formatted Date: ");
    Serial.println(myFormattedDate);
    Serial.println("");
  }
}

You should not have to declare pinAvg and pingsLost since your struct variables get set directly in the .onEnd() function. I've added a few more print debug statements

/*****************************************************************************
  Arduino library handling ping messages for the esp8266 platform
  MIT License  Copyright (c) 2018 Alessio Leoncini

  Rui Santos: Complete project details at https://randomnerdtutorials.com/esp32-ntp-client-date-time-arduino-ide/
  This requires the  NTP Client library forked by Taranais. https://github.com/taranais/NTPClient

****************************************************************************
*/

#include <Pinger.h>
#include <ESP8266WiFi.h>
#include <core_esp8266_waveform.h>
#include <NTPClient.h>
#include <WiFiUdp.h>

extern "C"
{
#include <lwip/icmp.h> // needed for icmp packet definitions
}

// to do the pin mapping for the Lolin NodeMCU pins D0 - D8
const int dPin[] = {16, 5, 4, 0, 2, 14, 12, 13, 15};
const int numPins = sizeof(dPin) / sizeof(dPin[0]);

const char* ssid     = "TALKTALKCC34C4";
const char* password = "MVGGX799";

//recording millis() times to update NTP
unsigned long lastNTPUpdateTime = 0;
const unsigned long NTPInterval = 5 * 60000UL;


//data for ping:
const int pingNumber = 5; //do 5 pings per set
const int pingTime = 200; //200ms timeout
//byte target = 0; //state machine control and select url to ping
//int pingAvg;
//int pingsLost;

struct host {
  byte IP[4];
  int tPing;
  int nLost;
};

//create data set of type host, &  initialise our struct for all cases
struct host hostList[] = {
  {{192, 168, 1, 1}, 0, 0 } ,  //0; router
  {{192, 168, 1, 11}, 0, 0 } , //1: RYZEN5
  {{192, 168, 1, 21}, 0, 0 } , //2: FILES
  {{192, 168, 1, 22}, 0, 0 } , //3: LP
  {{192, 168, 1, 14}, 0, 0 } , //4: GeoBRDG
  {{192, 168, 1, 24}, 0, 0 } , //5: NAS
  {{107, 162, 133, 62}, 0, 0 } //6: TalkTalk
};
const int numHosts = sizeof(hostList) / sizeof(hostList[0]);
int target = 0;  // current index into hostList[].  Needs to be global to use inside .onEnd()

// Define NTP Client to get time
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org");
String formattedDate, myFormattedDate;
String dayStamp;
String timeStamp;
const int nRounds = 43; //number of full rounds to complete before calling ntp
//1 round takes 7 sec. approx; so 1 min = 8.6 rounds; 5 min = 43 rounds
int count = 0; // number of rounds completed:  call ntp and save to SD every 5 min

volatile bool isFinished;

// Set global to avoid object removing after setup() routine
Pinger pinger;

void setup()
{
  // Begin serial connection at 74880 baud
  Serial.begin(74880);
  delay(1000); // serial comms is disturbed during a restart

  //set up LED pins as outputs & HIGH (LEDs all off)
  for (int i = 0; i < numPins; i++) {
    pinMode(dPin[i], OUTPUT);
    digitalWrite(dPin[i], HIGH);
  }

  // Connect to WiFi access point
  digitalWrite(dPin[0], HIGH); //indicate wifi not connected
  bool stationConnected = WiFi.begin(ssid, password);
  delay(200); //allow time to connect

  // Check if connection errors
  if (!stationConnected) {
    Serial.println("Error, unable to connect specified WiFi network.");
  }

  // Wait until connection completed
  Serial.print("Connecting to AP...");
  while (WiFi.status() != WL_CONNECTED) {
    delay(200);
    Serial.print(".");
  }
  Serial.print("Ok\n");
  digitalWrite(dPin[0], LOW); //indicate wifi connected

  // Initialize a NTPClient to get time
  timeClient.begin();
  // Set offset time in seconds to adjust for your timezone, eg GMT +1 = 3600
  timeClient.setTimeOffset(0);
  lastNTPUpdateTime = millis() - NTPInterval - 1;   // force initial time fetch
  getTime();

  pinger.OnReceive([](const PingerResponse & response)
  {
    if (response.ReceivedResponse)
    {
      Serial.print("  ping response time is ");
      Serial.print(response.ResponseTime);
      Serial.println(" msec");
    }
    else
    {
      Serial.printf("Request timed out.\n");
    }
    return true;  // Return true to continue the ping sequence. If current event returns false, the ping sequence is interrupted.
  });

  pinger.OnEnd([](const PingerResponse & response)
  {
    hostList[target].tPing = int(response.AvgResponseTime + 0.5);
    hostList[target].nLost = response.TotalSentRequests - response.TotalReceivedResponses;
    isFinished = true;  //marks all pings to that target completed
    Serial.print("  Ping complete. Avg Ping=" );
    Serial.print(hostList[target].tPing);
    Serial.print(", lost packets = ");
    Serial.println(hostList[target].nLost);
    return true;
  });
}

void loop()
{
  if (WiFi.status() == WL_CONNECTED) {
    digitalWrite(dPin[0], LOW);
  } else {
    digitalWrite(dPin[0], HIGH);
  }

  bool resultOK = PerformPing();
  if ( resultOK == false ) {
    Serial.println("Bad Ping");
  }
  target++;
  if (target == numHosts ) {
    // all done, show results
    showLEDs();
    target = 0;
  }
  getTime();

}//loop

bool PerformPing()
{
  Serial.print("Pinging target ");
  Serial.print(target);
  Serial.print(": ");
  //  Serial.println(hostList[target].IP);
  isFinished = false;
  hostList[target].tPing = -1;
  hostList[target].nLost = -1;
  bool pingOK = pinger.Ping((hostList[target].IP), pingNumber, pingTime);
  if ( pingOK == false ) return false;

  // wait here for isFinished to get set by the Pinger.onEnd() function
  while ( isFinished == false ) {
    delay(50);
  }
  // one set of pings to a single target complete and results in
  //Serial.print(" target ");     Serial.print(target);     Serial.println(" values in ");
  //hostList[target].tPing = pingAvg;
  //hostList[target].nLost = pingsLost;
  return true;
}

void showLEDs()
{
  //flash LEDs according to number of lost (or good) pings.
  Serial.print("loss values: ");
  for (int n = 0; n < numHosts; n++) {
    //print loss values and ping averages
    Serial.print(n);
    Serial.print(": ");
    Serial.print(hostList[n].nLost);
    Serial.print(" / ");
    Serial.print(hostList[n].tPing);
    Serial.print(";    ");
    //the lower limit on analogWrite() is 100Hz, but startWaveform() doesn't have that limit:
    startWaveform(dPin[numHosts - n], (hostList[n].nLost * 50000) + 10, ((5 - hostList[n].nLost ) * 50000) + 10, 0); //using lost pings: 0=LED ON, 1-4 = flashing, 5=LED OFF
  }
  Serial.println("");
}

void getTime()
{
  if ( millis() - lastNTPUpdateTime >= NTPInterval ) {
    lastNTPUpdateTime += NTPInterval;
    timeClient.update();
    formattedDate = timeClient.getFormattedDate();
    // Extract date
    int splitT = formattedDate.indexOf("T");
    dayStamp = formattedDate.substring(0, splitT);
    //Serial.println(dayStamp);
    // Extract time
    timeStamp = formattedDate.substring(splitT + 1, formattedDate.length() - 1);
    //Serial.println(timeStamp);
    myFormattedDate = String(dayStamp) + ", " +  String(timeStamp);
    Serial.print("my Formatted Date: ");
    Serial.println(myFormattedDate);
    Serial.println("");
  }
}

I don't understand why you can not wait inside PerformPing() for it to finish. I'm not sure what you are trying to access from the network and how you would be doing this. If you eventually want to be able to respond to other events like incoming http requests or serial input, then that waiting inside PerformPing can be moved outside that function and maybe into loop(). You would just check 'isFinished' in the loop and if true, increment target and call PerformPing again else skip it.

Maybe get this code working first?

Ran your code - it compiled and uploaded with no issues.

Pinging target 4: Request timed out.
ping response time is 45 msec
ping response time is 175 msec
ping response time is 120 msec
Request timed out.
Ping complete. Avg Ping=340, lost packets = 2

I modified the set of targets (just the URL's) as shown here so that it repeatedly pinged the "suspect" device. No other changes. I'm still seeing incorrect values for the average ping time.

//create data set of type host, &  initialise our struct for all cases
struct host hostList[] = {
  {{192, 168, 1, 14}, 0, 0 } , //4: GeoBRDG
  {{192, 168, 1, 14}, 0, 0 } , //4: GeoBRDG
   {{192, 168, 1, 14}, 0, 0 } , //4: GeoBRDG
   {{192, 168, 1, 14}, 0, 0 } , //4: GeoBRDG
  {{192, 168, 1, 14}, 0, 0 } , //4: GeoBRDG
   {{192, 168, 1, 14}, 0, 0 } , //4: GeoBRDG
 {{192, 168, 1, 14}, 0, 0 } , //4: GeoBRDG
};

Pinging target 0: ping response time is 32 msec
ping response time is 149 msec
ping response time is 112 msec
ping response time is 69 msec
ping response time is 188 msec
Ping complete. Avg Ping=110, lost packets = 0
Pinging target 1: ping response time is 151 msec
ping response time is 110 msec
ping response time is 70 msec
ping response time is 30 msec
ping response tim Lb0 msec
Ping complete. Avg Ping=102, lost packets = 0
Pinging target 2: ping response time is 109 msec
ping response time is 69 msec
ping response time is 29 msec
ping response time is 149 msec
ping response time is 109 msec
Ping complete. Avg Ping=93, lost packets = 0
Pinging target 3: ping response time is 68 msec
ping response time is 28 msec
ping response time is 148 msec
ping response time is 111 msec
ping response time is 65 msec
Ping complete. Avg Ping=84, lost packets = 0
Pinging target 4: ping response time is 27 msec
ping response time is 147 msec
ping response time i.⸮j͕⸮5
ping response time is 66 msec
ping response time is 187 msec
Ping complete. Avg Ping=106, lost packets = 0
Pinging target 5: ping response time is 145 msec
ping response time is 105 msec
ping response time is 66 msec
ping response time is 24 msec
ping response time is 149 msec
Ping complete. Avg Ping=98, lost packets = 0
Pinging target 6: ping response time is 104 msec
ping response time is 63 msec
ping response time is 23 msec
ping response time is 144 msec
Request timed out.
Ping complete. Avg Ping=334, lost packets = 1
loss values: 0: 0 / 110; 1: 0 / 102; 2: 0 / 93; 3: 0 / 84; 4: 0 / 106; 5: 0 / 98; 6: 1 / 334;
Looking at screens full of data I've noticed that the error only occurs when pings are lost; and then the "average" is the sum of the recorded valid pings (here 104,63,23,144 = 334)

I can easily adjust that in my program to give a more realistic value.

I've also noticed it when pings to this device are lost its almost always the last in the set. How the average would work out if it was a different loss - maybe the first - would be hard to spot.

It is a bug in the library. The way it is implemented, the AvgResponseTime variable is the sum of all of the pings and on the very last ping, it then divides that by the number of responses

  // Evaluate average response time
  m_pingResponse.AvgResponseTime += m_pingResponse.ResponseTime;
  if(m_requestsToSend == 0)
  {
    m_pingResponse.AvgResponseTime /= m_pingResponse.TotalReceivedResponses;
  }

Since your last ping was a timeout, this function never gets called the last time so the sum is left in AvgResponseTime rather than the average.

You can work around the bug by basically doing the same thing in your callback functions.

/*****************************************************************************
  Arduino library handling ping messages for the esp8266 platform
  MIT License  Copyright (c) 2018 Alessio Leoncini

  Rui Santos: Complete project details at https://randomnerdtutorials.com/esp32-ntp-client-date-time-arduino-ide/
  This requires the  NTP Client library forked by Taranais. https://github.com/taranais/NTPClient

****************************************************************************
*/

#include <Pinger.h>
#include <ESP8266WiFi.h>
#include <core_esp8266_waveform.h>
#include <NTPClient.h>
#include <WiFiUdp.h>

extern "C"
{
#include <lwip/icmp.h> // needed for icmp packet definitions
}

// to do the pin mapping for the Lolin NodeMCU pins D0 - D8
const int dPin[] = {16, 5, 4, 0, 2, 14, 12, 13, 15};
const int numPins = sizeof(dPin) / sizeof(dPin[0]);

const char* ssid     = "TALKTALKCC34C4";
const char* password = "MVGGX799";

//recording millis() times to update NTP
unsigned long lastNTPUpdateTime = 0;
const unsigned long NTPInterval = 5 * 60000UL;


//data for ping:
const int pingNumber = 5; //do 5 pings per set
const int pingTime = 200; //200ms timeout
//byte target = 0; //state machine control and select url to ping
//int pingAvg;
//int pingsLost;

struct host {
  byte IP[4];
  int tPing;
  int nLost;
};

//create data set of type host, &  initialise our struct for all cases
struct host hostList[] = {
  {{192, 168, 1, 1}, 0, 0 } ,  //0; router
  {{192, 168, 1, 11}, 0, 0 } , //1: RYZEN5
  {{192, 168, 1, 21}, 0, 0 } , //2: FILES
  {{192, 168, 1, 22}, 0, 0 } , //3: LP
  {{192, 168, 1, 14}, 0, 0 } , //4: GeoBRDG
  {{192, 168, 1, 24}, 0, 0 } , //5: NAS
  {{107, 162, 133, 62}, 0, 0 } //6: TalkTalk
};
const int numHosts = sizeof(hostList) / sizeof(hostList[0]);
int target = 0;  // current index into hostList[].  Needs to be global to use inside .onEnd()

// Define NTP Client to get time
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org");
String formattedDate, myFormattedDate;
String dayStamp;
String timeStamp;
const int nRounds = 43; //number of full rounds to complete before calling ntp
//1 round takes 7 sec. approx; so 1 min = 8.6 rounds; 5 min = 43 rounds
int count = 0; // number of rounds completed:  call ntp and save to SD every 5 min

volatile bool isFinished;

// Set global to avoid object removing after setup() routine
Pinger pinger;

void setup()
{
  // Begin serial connection at 74880 baud
  Serial.begin(74880);
  delay(1000); // serial comms is disturbed during a restart

  //set up LED pins as outputs & HIGH (LEDs all off)
  for (int i = 0; i < numPins; i++) {
    pinMode(dPin[i], OUTPUT);
    digitalWrite(dPin[i], HIGH);
  }

  // Connect to WiFi access point
  digitalWrite(dPin[0], HIGH); //indicate wifi not connected
  bool stationConnected = WiFi.begin(ssid, password);
  delay(200); //allow time to connect

  // Check if connection errors
  if (!stationConnected) {
    Serial.println("Error, unable to connect specified WiFi network.");
  }

  // Wait until connection completed
  Serial.print("Connecting to AP...");
  while (WiFi.status() != WL_CONNECTED) {
    delay(200);
    Serial.print(".");
  }
  Serial.print("Ok\n");
  digitalWrite(dPin[0], LOW); //indicate wifi connected

  // Initialize a NTPClient to get time
  timeClient.begin();
  // Set offset time in seconds to adjust for your timezone, eg GMT +1 = 3600
  timeClient.setTimeOffset(0);
  lastNTPUpdateTime = millis() - NTPInterval - 1;   // force initial time fetch
  getTime();

  pinger.OnReceive([](const PingerResponse & response)
  {
    if (response.ReceivedResponse)
    {
      Serial.print("  ping response time is ");
      Serial.print(response.ResponseTime);
      Serial.println(" msec");
      hostList[target].tPing += response.ResponseTime;
    }
    else
    {
      Serial.printf("Request timed out.\n");
    }
    return true;  // Return true to continue the ping sequence. If current event returns false, the ping sequence is interrupted.
  });

  pinger.OnEnd([](const PingerResponse & response)
  {
    //hostList[target].tPing = int(response.AvgResponseTime + 0.5);
    hostList[target].tPing /= response.TotalReceivedResponses;
    hostList[target].nLost = response.TotalSentRequests - response.TotalReceivedResponses;
    isFinished = true;  //marks all pings to that target completed
    Serial.print("  Ping complete. Avg Ping=" );
    Serial.print(hostList[target].tPing);
    Serial.print(", lost packets = ");
    Serial.println(hostList[target].nLost);
    return true;
  });
}

void loop()
{
  if (WiFi.status() == WL_CONNECTED) {
    digitalWrite(dPin[0], LOW);
  } else {
    digitalWrite(dPin[0], HIGH);
  }

  bool resultOK = PerformPing();
  if ( resultOK == false ) {
    Serial.println("Bad Ping");
  }
  target++;
  if (target == numHosts ) {
    // all done, show results
    showLEDs();
    target = 0;
  }
  getTime();

}//loop

bool PerformPing()
{
  Serial.print("Pinging target ");
  Serial.print(target);
  Serial.print(": ");
  //  Serial.println(hostList[target].IP);
  isFinished = false;
  hostList[target].tPing = 0;
  hostList[target].nLost = 0;
  bool pingOK = pinger.Ping((hostList[target].IP), pingNumber, pingTime);
  if ( pingOK == false ) return false;

  // wait here for isFinished to get set by the Pinger.onEnd() function
  while ( isFinished == false ) {
    delay(50);
  }
  // one set of pings to a single target complete and results in
  //Serial.print(" target ");     Serial.print(target);     Serial.println(" values in ");
  //hostList[target].tPing = pingAvg;
  //hostList[target].nLost = pingsLost;
  return true;
}

void showLEDs()
{
  //flash LEDs according to number of lost (or good) pings.
  Serial.print("loss values: ");
  for (int n = 0; n < numHosts; n++) {
    //print loss values and ping averages
    Serial.print(n);
    Serial.print(": ");
    Serial.print(hostList[n].nLost);
    Serial.print(" / ");
    Serial.print(hostList[n].tPing);
    Serial.print(";    ");
    //the lower limit on analogWrite() is 100Hz, but startWaveform() doesn't have that limit:
    startWaveform(dPin[numHosts - n], (hostList[n].nLost * 50000) + 10, ((5 - hostList[n].nLost ) * 50000) + 10, 0); //using lost pings: 0=LED ON, 1-4 = flashing, 5=LED OFF
  }
  Serial.println("");
}

void getTime()
{
  if ( millis() - lastNTPUpdateTime >= NTPInterval ) {
    lastNTPUpdateTime += NTPInterval;
    timeClient.update();
    formattedDate = timeClient.getFormattedDate();
    // Extract date
    int splitT = formattedDate.indexOf("T");
    dayStamp = formattedDate.substring(0, splitT);
    //Serial.println(dayStamp);
    // Extract time
    timeStamp = formattedDate.substring(splitT + 1, formattedDate.length() - 1);
    //Serial.println(timeStamp);
    myFormattedDate = String(dayStamp) + ", " +  String(timeStamp);
    Serial.print("my Formatted Date: ");
    Serial.println(myFormattedDate);
    Serial.println("");
  }
}

Defect filed and fix proposed. If you wish you can try this file with the original code and it should report the correct average response time

Pinger.cpp (15.4 KB)

VINDICATED! (sorry for shouting)

Thanks BLH I sweated over this and simplified things to the point where I was pretty sure it wasnt an error in my code before asking you to check the library.

I've tried your modified .cpp and for some reason it is giving unrealistically low values.

EG it returns no lost pings and pingAvg=3ms for my broadband provider (talktalk on 107.162.133.62)
however when I run a stand-alone ing test I get 15ms.

Also, I think you will find if pings are lost a value of 0 gets added to the running total, so for a set of 5 pings if one is 80ms and 4 lost the average will be reported as 80/5 = 16.

I cant see any "correct" way to report an average if pings are lost. They cant be ignored as it means for that event ping time>timeout; and certainly cant be counted as zero.

Maybe the best way is just to document what the current response.AvgResponseTime actually returns?

I'm just doing this: adding the timeout value to the total for each lost ping.

bool PerformPing()
{
  if (roundComplete)  //ready for next set of pings
  {
    //Serial.print(" target ");     Serial.print(target);     Serial.println(" sending ping ");
    isFinished = false;
    int url = target;
    bool pingOK = pinger.Ping(IPAddress(host1[url].IP), pingNumber, pingTime);
    roundComplete = false;
  }
  else if (isFinished) // one set of pings to a single target complete and results in
  { 
    isFinished = false;
    //correct data: average is only correct if no pings lost; otherwise its the sum of the valid ping times
     if(pingsLost==0){
      host1[target].tPing = pingAvg;
    }
    else{
      host1[target].tPing = int((pingAvg + pingsLost*pingTime)/pingNumber);
    }
    
    host1[target].nLost = pingsLost;
    roundComplete = true;
  }
  return roundComplete;
}

The average is divided by the total number of received responses so if a ping times out, the receivecount does not get incremented. In your example, it would be 80/1, not 80/5. I'll study the library a bit more to see if I can figure out why the average is different.