Friday, January 29, 2021

Time is of the essence

For an index to all my stories click this text

I am building a project together with my son in law (he does the mechanics) in which we need to know the time to set some lamps on or off. The project uses an ESP32 as we need a lot of IO ports.

How do we get the time. Of course there is a timer that starts everytime the ESP boots. But that does not give you the actual time. And that is what we need. Lamps should go on when it gets dark and not in bright sunlight.

Luckily there is a library for the ESP micro controllers that will get a fair accuarte time from an official NTP server. Fair accurate ?? Well yes it takes some time to get the information from the server (somewhere on the world) to the ESP and that can set the time one or two seconds off. Nothing we need worry about as our project is not THAT critical.

Libraries.

To get the time the ESP program needs several libraries. First it needs to make contact over the internet with the Wifi library which is included in the ESP setup in the Arduino IDE.

Then we need the NTP library to make contact over the web with an NTP server. These are very accurate servers that have only one purpose: serve the actual time. The library will get the time from the server.
This library is suitable for the ESP8266 (all versions) and the ESP32.

Next we need the UDP library as the NTP server sends the information in UDP protocol. This is also included in the Arduino IDE.

So we only need to install the NTP library to get things working. The others are already present.



To get the library just open the library manager in the Arduino IDE



Search for NTP and choose the NTP Client by Fabrice Weinberg.

The time program

The source code is for the ESP8266 and you will need to change just 1 line to get this working on an ESP32. I'll show you how to do that at the end of the explanation of the program.


#include <NTPClient.h>
#include <ESP8266WiFi.h>
#include <WiFiUDP.h>
 
// WiFi credentials for your router
const char* ssid = "XXXXXXXXXXXXXXXXX"; 
const char* password = "YYYYYYYYYYYYYYY"; 

#define NTP_OFFSET   60 * 60      // In seconds
#define NTP_ADDRESS  "europe.pool.ntp.org"

WiFiUDP ntpUDP;

NTPClient timeClient(ntpUDP, NTP_ADDRESS, NTP_OFFSET);

void setup(void) 
{  
  Serial.begin(115200);
  Serial.print("Starting the connection");
  WiFi.begin(ssid, password); // Connect to WiFi
  
  timeClient.begin();
  
  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(500);
    Serial.print(".");
  }
  // Print local IP address and start web server
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}
 
void loop() {
  timeClient.update();
  String newtime = timeClient.getFormattedTime();
  Serial.print("the time is : ");
  Serial.println(newtime);
  Serial.print("Hour    : ");
  Serial.println(newtime.substring(0,2));
  Serial.print("Minute  : ");
  Serial.println(newtime.substring(3,5));
  Serial.print("Seconds : ");
  Serial.println(newtime.substring(6,8));
  delay(1000*10);
}

I will go over the program step by step. Thats the best way to comprehend and alter it for your own purposes.


#include <NTPClient.h>
#include <ESP8266WiFi.h>
#include <WiFiUDP.h>
The program starts with loading the libraries it needs.


// WiFi credentials for your router
const char* ssid = "XXXXXXXXXXXXXXXXX"; 
const char* password = "YYYYYYYYYYYYYY"; 
This is all familiar stuff. Replace the XXXXXX with the name of your router and the YYYY with it's password.


#define NTP_OFFSET   60 * 60      // In seconds
#define NTP_ADDRESS  "europe.pool.ntp.org"
The NTP_OFFSET defines in which time-zone you are. I am in the Netherlands at 1 hour after the Greenwhich time. So the offset for me is 60 seconds x 60 minutes.
The NTP_ADDRESS is the name of the NTP server. I am using the European version.


WiFiUDP ntpUDP;

This line starts the UDP library.


WiFiUDP ntpUDP;

And here the NTP library is started with UDP, the servers adress and the time-zone offset.

The setup() will bring nothing new. The serial monitor is started. It starts the Wifi connection and as long as there is no connection it prints dots. And when a connection is established it prints the IP adress in the Serial monitor.

The loop is where we extract the actual time.


  timeClient.update();
  String newtime = timeClient.getFormattedTime();

The first line gets the new time from the server and the second line puts that time in the  String variable newtime. We can analyse that variable to extract hours, minutes and seconds.



As you can see the time is printed in the serial monitor in the format HH:MM:SS.


  Serial.print("the time is : ");
  Serial.println(newtime);

These lines print the time in the Serial Monitor.

  Serial.print("Hour    : ");
  Serial.println(newtime.substring(0,2));
  Serial.print("Minute  : ");
  Serial.println(newtime.substring(3,5));
  Serial.print("Seconds : ");
  Serial.println(newtime.substring(6,8));

This is where the hours, minutes and seconds are extracted. A string starts at index 0 so substring(0,2) gets the first two letters in the string which are the hours. substring (3,5) Gets the characters at the 4th and 5th position which are the minutes.

The program then waits 10 seconds and gets the new time from the server.

The ESP32 version

Well actually the program is exactly the same except for the call to the wifi library. The only thing you have to do is to alter:

#include <ESP8266WiFi.h>

into:

#include <WiFi.h>

The NTP server

As I am located in the Netherlands I use the european NTP server located at: europe.pool.ntp.org

There are many more servers and at least one for each continent. You can find them all on the following link: https://www.ntppool.org/zone/@
Please use a NTP server closest to your location for more accuracy.

Time zones

The NTP servers send UTC time. You might be in a different timezone. To get the right time on your screen use the following formula:

UTC -5.00 : -5 * 60 * 60 : -18000
UTC +1.00 : 1 * 60 * 60 : 3600
UTC +0.00 : 0 * 60 * 60 : 0

#define NTP_OFFSET   60 * 60

This is my adaption as I am located at UTC +1 hour.

Now we can accurately set our lights on and off depending on the hour of the day.


BAD PRACTICE

The program demonstrated here is actually bad practice. You are overloading the NTP server with your requests. What you should do is to request the time once a day or every 6 hours or so. This way we can keep the NTP servers free of charge. 

To keep the time you should use the time library and have that updated every once in a while with the accurate time from the NTP server. That is for another story.


Till next time
Have fun

Luc Volders