Using NTP pool instead of particular server

So my code was working fine but lost its time synch presumably because the NTP server it was ‘hard-wired’ to was not responding any more. (Pinging that server unsuccessfully proved this.)

My question is how can I change it to be more robust and get the time synch from an NTP pool of servers?

(Arduino Uno WiFi Rev 2.)

lights.ino (10.6 KB)

You will have to declare multiple TimeServers and if the first one fails, move on to the next, etc. If you get to the end and all have failed, you lose.

You could implement that as an array if IPAddresses and a pointer to which is current

// fake addresses
IPAddress timeServer1(143, 210, 16, 201);
IPAddress timeServer2(143, 210, 16, 202);
IPAddress timeServer3(143, 210, 16, 203);
IPAddress servers[] = { timerServer1, timerServer2, timeServer3 };
const int nServers = sizeof(servers) / sizeof(servers[0]);
int currentServer = 0;
//...

I am not sure how to initialize the array directly but other might know how...
maybe like this

// fake addresses
IPAddress servers[] = { IPAddress(143, 210, 16, 201), IPAddress(143, 210, 16, 202), IPAddress(143, 210, 16, 203) };
const int nServers = sizeof(servers) / sizeof(servers[0]);
int currentServer = 0;
//...

blh64:
You will have to declare multiple TimeServers and if the first one fails, move on to the next, etc. If you get to the end and all have failed, you lose.

Not really. You can start at the beginning again. Perhaps one of the servers in your array has come back online.

I am not sure how to initialize the array directly but other might know how…

Same way as an array of structs:

IPAddress servers[] = { {143, 210, 16, 201}, {143, 210, 16, 202}, {143, 210, 16, 203} };

Maybe if you use a domain name instead of an IP address, you might get better results. I might allow the time server setup to load balance request among a large number of servers. Maybe something like below.

mail.perturb.org

Yes, that was the idea. The question was how. The original code was adapted from the examples in the WiFiNINA library and I don't have much of an idea about how to realise the change. I know there are pools of NPT servers but how does one point the code to a pool instead of a hard-wired particular URL?

“I know there are pools of NPT servers but how does one point the code to a pool instead of a hard-wired particular URL?”

Below is some code somebody else wrote that might be of use. It worked when I tried it with my WeMOS esp board. You might study the code to see how it works using a domain name instead of a static IP address.

/*
  NTP-TZ-DST_simplified (v0)
  NetWork Time Protocol - Time Zone - Daylight Saving Time

  This is a greatly simplified version of NTP-TZ-DST (v2) intended to be easier to understand with just the basic functions

  This example shows:
  - how to read time
  - how to set timezone per country/city
  - how to use callbacks when time is updated

  This example code is in the public domain.
*/


#ifndef STASSID
#define STASSID "xxxxxxxx"
#define STAPSK  "xxxxxxxx"
#endif

// This database is autogenerated from IANA timezone database
//    https://www.iana.org/time-zones
// and can be updated on demand in this repository
#include <TZ.h>

// "TZ_" macros follow DST change across seasons without source code change
// check for your nearest city in TZ.h
#define MYTZ TZ_Pacific_Auckland

////////////////////////////////////////////////////////

#include <ESP8266WiFi.h>
#include <coredecls.h>                  // settimeofday_cb()
#include <PolledTimeout.h>

#include <time.h>                       // time() ctime()
#include <sys/time.h>                   // struct timeval

// this line is necessary, not sure what it does
extern "C" int clock_gettime(clockid_t unused, struct timespec *tp);

// An object which can store a time
static time_t now;

// this uses the PolledTimeout library to allow an action to be performed every 20 seconds
static esp8266::polledTimeout::periodicMs showTimeNow(20000);

/* This is a shortcut to print a bunch of stuff to the serial port.  It's very confusing, but shows what values are available
#define PTM(w) \
  Serial.print(" " #w "="); \
  Serial.print(tm->tm_##w);

void printTm(const char* what, const tm* tm) {
  Serial.print(what);
  PTM(isdst); PTM(yday); PTM(wday);
  PTM(year);  PTM(mon);  PTM(mday);
  PTM(hour);  PTM(min);  PTM(sec);
}
*/

void showTime() {   // This function is used to print stuff to the serial port, it's not mandatory
  now = time(nullptr);      // Updates the 'now' variable to the current time value

  // human readable
  Serial.print("ctime:     ");
  Serial.print(ctime(&now));
  // Here is one example showing how you can get the current month
  Serial.print("current month: ");
  Serial.println(localtime(&now)->tm_mon);
  // Here is another example showing how you can get the current year
  Serial.print("current year: ");
  Serial.println(localtime(&now)->tm_year);
  // Look in the printTM method to see other data that is available
  Serial.println();
}

void time_is_set_scheduled() {    // This function is set as the callback when time data is retrieved
  // In this case we will print the new time to serial port, so the user can see it change (from 1970)
  showTime();
}

void setup() {
  Serial.begin(115200);
  Serial.println("\nStarting...\n");

  // install callback - called when settimeofday is called (by SNTP or us)
  // once enabled (by DHCP), SNTP is updated every hour
  settimeofday_cb(time_is_set_scheduled);

  // This is where your time zone is set
  configTime(MYTZ, "pool.ntp.org");

  // start network
  WiFi.persistent(false);
  WiFi.mode(WIFI_STA);
  WiFi.begin(STASSID, STAPSK);

  // On boot up the time value will be 0 UTC, which is 1970. 
  // This is just showing you that, so you can see it change when the current data is received
  Serial.printf("Time is currently set by a constant:\n");
  showTime();
}

void loop() {
  if (showTimeNow) {
    showTime();
  }
}

Use WiFi.hostByName

char const * const ntpServerName = "uk.pool.ntp.org";
IPAddress ntpServerIP;
...
WiFi.hostByName(ntpServerName, ntpServerIP);

guix:
Use WiFi.hostByName

char const * ntpServerName = "uk.pool.ntp.org";

IPAddress ntpServerIP;
...
WiFi.hostByName(ntpServerName, ntpServerIP);

Yup. You can keep the pool of multiple URLs in a 2-dimensional const char array and select the one you want to try and convert it to an IPAddress. Then use that IPAddress in the Udp.beginPacket() function.