Getting Started for Arduino users - Retrieving the time from a time server using ESP8266

Getting Started for Arduino users - Retrieving the time from a time server using ESP8266

Here is the fourth in our blog series for Arduino IDE users - this time showing you how to retrieve the correct time from a time server, after connecting the ESP8266 to WiFi. Our previous blogs covered:

  1. Getting Started with xChip Core CW01 (ESP8266) and IP01 programmer
  2. Programming CW01 (ESP8266) to drive Red, Green and Blue LEDs
  3. Connecting the ESP8266 to a WiFi access point

Please see our Getting Started page for a full list of resources supporting Arduino IDE users.

Contents

  1. What you need
  2. Installations
  3. To do
  4. When things don't work as expected
  5. What to do next
  6. References 

 

1. What you need

  • the IP01 and CW01, set up as per the first blog in the series

                     

          IP01 - switches                 IP01 - solder pads

  • details for, and access to, a WiFi accesspoint
  • the Arduino Sketch file at the bottom of this blog 

 

2. Installations
  • see our first blog in the series - on IP01 and CW01 Setup

 

3. To do
  • set the switches on the IP01 so that the CW01 can be programmed (flashed)
    • the first version of the IP01 has 2 small switches - make sure SW1 is set to position B, and SW2 is set to the DCE position

 

                    

          top view                  side view

    • the second version of the IP01 does not have switches
  • set the programmer to "Arduino as ISP" in the Tools->Programmer menu

 

  • open the code file (at the bottom of this blog) in the Arduino IDE
  • find the line of code which reads as follows;
    • const char* WIFI_SSID = "<YOUR_SSID>";
    • replace <YOUR_SSID> with the name of your WiFi SSID, for example, if your WiFi accesspoint SSID is "Joe", the above line of code should read as follows
    • const char* WIFI_SSID = "Joe";
    • the same applies to <YOUR_SECRET_PASSWORD> in the line of code which reads as follows
    • const char* WIFI_PASS = "<YOUR_SECRET_PASSWORD>";
    • if your password is "my_secret", the above line of code should read as follows
    • const char* WIFI_PASS = "my_secret";
  • click the 'Verify' button or select Sketch->Verify/Compile or type CTRL+R, make sure no errors are reported, and that 'Done compiling' is reported

                   

  • save the file using File->Save or CTRL+S if you have made any modifications to the code

  • once the compile is successful, click the 'Upload' button or select Sketch->Upload or type CTRL+U, and make sure 'Done compiling' is reported

                    

  • observe the LEDs on the CW01, these should display Red while attempting to connect, and Green once the CW01 has connected with the WiFi access point

                     

  • select Tools->Serial Monitor to observe to messages output by the Serial.print("...") statements
  • when the Sketch starts, it will attempt connection with the WiFi access point, and will print "Connecting to : <YOUR_SSID >"
  • once the CW01 connects to the WiFi access point, 'Connection established!' and 'IP address: bb.cc.dd' should be reported
    • the CW01 then reports 'Starting UDP' and 'Local port: 2390' , and then continuously reports when an NTP request is sent and received, and the seconds, Unix time, and UTC time it receives from the time server

          

 

4. When things don't work as expected
  • follow the same 'when things don't work as expected' procedure as indicated in the our second blog

 

5. What to do next
  • read and understand the code in this example
  • read more about time servers and their significance in IOT

 

6. References
  • more info - search for "time server request arduino ESP8266" on the internet

7. Code file


/*****************************************************************************
This Sketch is an example for the XinaBox CW01 ESP8266 Board
It demonstrates how to connect to a WiFi access point and 
access a time server (NTP).
Time servers are used by many internet-connected systems which depend 
on the presence of an accurate time stamp.
    You can buy these devices on our store!
     -----> https://xinabox.cc/CW01/
    Currently Supported on the following ☒CHIPs:
    - CW01
*****************************************************************************/

/************************** Library Includes ********************************/
#include 
#include 

/************************* WiFi Access Point *********************************/
// Replace the contents between inverted commas with your WiFi details.
// YOUR_SSID is the name of your WiFi access point.
// YOUR_SECRET_PASSWORD is your WiFi access point password.
const char* WIFI_SSID = "";
const char* WIFI_PASS = "";

/**************************** For Time Server Code ***************************/
// the local port to listen to for UDP data packets
unsigned int localPort = 2390;

// the time server IP address
IPAddress timeServerIP;

// time server name 
// - try and ping this name, without the inverted commas,
//   from your workstation command line
const char* ntpServerName = "time.nist.gov";

// the NTP time stamp is within the first 48 characters of the response
const int NTP_PACKET_SIZE = 48;

// buffer of NTP_PACKET_SIZE characters for outgoing requests and incoming responses
byte packetBuffer[NTP_PACKET_SIZE];

// an instance variable which allows sending and receiving of data
// using the User DataGram Protocol (UDP)
WiFiUDP udp;

// UDP packet indicator
int cb;

// timestamp high and low words, timestamp is 2 words or 4 bytes long
unsigned long highWord;
unsigned long lowWord;

// these are combined into seconds since 1900
unsigned long secsSince1900;

// Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
const unsigned long seventyYears = 2208988800UL;

// subtract seventy years
unsigned long epoch;

/**************************** SYSTEM DEFINES *********************************/
#define RED 12
#define GREEN 13
#define BLUE 5

/***************************** General Purpose *******************************/
// loop counter
unsigned int loop_count;

/***************************** Sketch Code ***********************************/
void setup() {
  // Start the Serial Monitor
  Serial.begin(115200);
  
  // set ports as digital (on/off) OUTPUTs, the digitalWrite(...) statement is used to set digital ports on or off
  pinMode(RED, OUTPUT);
  pinMode(GREEN, OUTPUT);
  pinMode(BLUE, OUTPUT);

  // Connect to WIFI
  WIFI_connect();
  
  // Start UDP
  UDP_start();  
}

void loop() {

  // contact the time server and fetch the time
  getTime();  

  // wait for 9 more seconds
  loop_count = 0;
  // wait for 9 seconds, keep flashing
  while (loop_count < 9) {
      loop_count++;
      red_led_flash(); // takes about 1 second
  }
}

void getTime() {
  
  //get a random server from the pool
  WiFi.hostByName(ntpServerName, timeServerIP);
  
  // send an NTP packet to a time server
  sendNTPpacket(timeServerIP);

  // wait 1 seond for possible reply
  red_led_flash();

  cb = udp.parsePacket();
  if (!cb) {
    Serial.println("no packet yet");
  }
  else {
    Serial.print("packet received, length = ");
    Serial.println(cb);
    
    // We've received a packet, read the packet into the buffer
    udp.read(packetBuffer, NTP_PACKET_SIZE);

    // the timestamp starts at byte 40 of the received packet and is 
    // four bytes, or two words, long. First, extract the two words:
    highWord = word(packetBuffer[40], packetBuffer[41]);
    lowWord = word(packetBuffer[42], packetBuffer[43]);
    
    // combine the four bytes (two words) into a long integer
    // this is NTP time (seconds since Jan 1 1900):
    unsigned long secsSince1900 = highWord << 16 | lowWord;
    
    Serial.print("Seconds since Jan 1 1900 = ");
    Serial.println(secsSince1900);

    // now convert NTP time into everyday time:
    Serial.print("Unix time = ");
    
    // subtract seventy years:
    epoch = secsSince1900 - seventyYears;
    
    // print Unix time:
    Serial.println(epoch);

    // print the hour, minute and second:
    // UTC is the time at Greenwich Meridian (GMT)
    Serial.print("The UTC time is ");
    // print the hour (86400 equals secs per day)
    Serial.print((epoch  % 86400L) / 3600); 
    Serial.print(':');
    // In the first 10 minutes of each hour, we'll want a leading '0'    
    if ( ((epoch % 3600) / 60) < 10 ) {
      Serial.print('0');
    }
    // print the minute (3600 equals secs per minute)
    Serial.print((epoch  % 3600) / 60); 
    Serial.print(':');
    // In the first 10 seconds of each minute, we'll want a leading '0'
    if ( (epoch % 60) < 10 ) {
      Serial.print('0');
    }
    // print the second
    Serial.println(epoch % 60);
  }
}

// flash the red LED, 50ms on and 950ms off , thus also acts as a 1 second delay 
void red_led_flash() {
  
  // turn the RED LED on by writing a logic HIGH to the port
  digitalWrite(RED, HIGH);
  delay(50);
  // turn the RED LED off by writing a logic LOW to the port
  digitalWrite(RED, LOW);
  delay(950);
}

// connect to WiFi network
void WIFI_connect() {
  
  if (WiFi.status() != WL_CONNECTED) {
    digitalWrite(GREEN, LOW);
    
    // Connect to WiFi access point.
    Serial.println(); Serial.println();
    Serial.print("Connecting to : ");
    Serial.print(WIFI_SSID);
    Serial.println(" ...");

    // Start ESP8266 STA mode
    WiFi.begin(WIFI_SSID, WIFI_PASS);

    // check connection status
    while (WiFi.status() != WL_CONNECTED) {
      digitalWrite(RED, HIGH);
      delay(250);
      digitalWrite(RED, LOW);
      delay(250);
      Serial.print(".");
    }

    // if connected, show the IP address of the ESP8266
    if (WiFi.status() == WL_CONNECTED) {
      digitalWrite(GREEN, HIGH);
      Serial.println();
      Serial.println("Connection established!");
      Serial.print("IP address:\t");
      Serial.println(WiFi.localIP());
    }
    
  }
}

// start the UDP
void UDP_start() {
  
  Serial.println();
  Serial.println("Starting UDP");
  udp.begin(localPort);
  Serial.print("Local port: ");
  Serial.println(udp.localPort());
}

// send an NTP request to the time server at the given address
unsigned long sendNTPpacket(IPAddress& address) {
  
  Serial.println("sending NTP packet...");
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // Initialize values needed to form NTP request
  // for details on the NTP packet, visit the cisco site link in references 
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]  = 49;
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;

  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp:
  udp.beginPacket(address, 123); //NTP requests are to port 123
  udp.write(packetBuffer, NTP_PACKET_SIZE);
  udp.endPacket();
}
 
----- 
Please see our getting started page for a full list of resources supporting Arduino IDE users, and the XK51 Arduino Zero Compatible Kit to build devices in minutes.
 
XinaBox is a rapid electronics development solution for developing, making products and learning. Without soldering, wiring, breadboarding, or hardware knowledge, the developer can assemble a circuit in a matter of minutes, and get straight to coding in their choice of language.
Previous article Arduino IDE users: Which XinaBox Core is best for you?
Next article Getting Started for Arduino users - Connecting CW01 (ESP8266) to WiFi

Leave a comment

Comments must be approved before appearing

* Required fields