Nano RP2040 Connect get time from Network Time Protocol (NTP) time server display on ST7789 SPI IPS

The Network Time Protocol (NTP) is a networking protocol for clock synchronization between computer systems over packet-switched, variable-latency data networks.
~ ref: wikipedia.org>Network_Time_Protocol


To get time from Network Time Protocol (NTP) time server using Arduino Nano RP2040 Connect

With WiFiNINA library installed in Arduino IDE's Library Manager, it a sample WiFiUdpNtpClient show how to get the time from a Network Time Protocol (NTP) time server, demonstrates use of UDP sendPacket and ReceivePacket.

Display on 1.14" 135x240 ST7789 SPI IPS

Read here for Nano RP2040 Connect to display on 1.14" 135x240 IPS ST7789 SPI in Arduino Framework.

Exercise code to get time from Network Time Protocol (NTP) time server display on ST7789 SPI IPS

NRP_WiFiUdpNtpClient.ino

/*
 * Arduino Nano RP2040 Connect query NTP TIme Service (base on WiFiNINA example WiFiUdpNtpClient),
 * display on 1.14" 135x240 ST7789 SPI IPS.
 * 
 * Just a exercise, not a complete clock.
 * - No error handling
 * - Display update only after readNTP success.
 */

#include <WiFiNINA.h>
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7789.h> // Hardware-specific library for ST7789
#include <SPI.h>

/*
 * Prepare for ST7789 SPI IPS using Software SPI
 * because the WiFiNINA use SPI, so drive ST7789 via Software SPI.
 * 
 *   Connection:
 *   GND GND
 *   VCC 3V3
 *   SCL D10
 *   SDA D9
 *   RES D8
 *   DC  D7
 *   CS  D6
 *   BLK 3V3
 */
#define TFT_SCLK  10
#define TFT_MOSI  9
#define TFT_RST   8
#define TFT_DC    7
#define TFT_CS    6

// For ST7789 using software SPI:
Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);

/*
 * prepare for WiFiNINA
 */
char ssid[] = "ssid";        // your network SSID (name)
char pass[] = "password";    // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0;            // your network key index number (needed only for WEP)

/*
 * Prepare for NTP
 */
unsigned int localPort = 2390;      // local port to listen for UDP packets

IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server

const int NTP_PACKET_SIZE = 48; // NTP timestamp is in the first 48 bytes of the message

byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets

// A UDP instance to let us send and receive packets over UDP
WiFiUDP Udp;

unsigned long previousMillis;
const long interval = 1000;       //interval for 1 second

unsigned long nxRqsNTP;
const long intervalRqsNTP = 5000; //read NTP every 5 seconds

void setup() {
  delay(500);
  Serial.begin(9600);
  delay(500);

  // init 1.14" 240x135 TFT:
  tft.init(135, 240);           // Init ST7789 240x135
  tft.setRotation(3);
  tft.fillScreen(ST77XX_BLACK);

  promptMsg("Waiting Serial...", ST77XX_WHITE, 10, 10, 2);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
    
  }
  Serial.println("\n--- Start ---");

  // check for the WiFi module:
  if (WiFi.status() == WL_NO_MODULE) {
    Serial.println("Communication with WiFi module failed!");
    promptMsg("WiFi Module Failed", ST77XX_WHITE, 10, 10, 2);
    // don't continu
    while (true);
  }

  Serial.println("WiFi firmware ver: " + (String)WiFi.firmwareVersion());
  promptMsg("WiFi firmware ver:", ST77XX_WHITE, 10, 10, 2);
  drawText((char *)WiFi.firmwareVersion(), ST77XX_WHITE, 10, 30, 2);
  delay(1000);

  previousMillis = millis();
  nxRqsNTP = millis() + intervalRqsNTP;
  
  pinMode(LED_BUILTIN, OUTPUT);
  //Flash 3 times to indicate program start
  digitalWrite(LED_BUILTIN, LOW);  //LED OFF
  delay(500);
  digitalWrite(LED_BUILTIN, HIGH);  //LED ON
  delay(200);
  digitalWrite(LED_BUILTIN, LOW);  //LED OFF
  delay(200);
  digitalWrite(LED_BUILTIN, HIGH);  //LED ON
  delay(200);
  digitalWrite(LED_BUILTIN, LOW);  //LED OFF
  delay(200);
  digitalWrite(LED_BUILTIN, HIGH);  //LED ON
  delay(200);
  digitalWrite(LED_BUILTIN, LOW);  //LED OFF
  delay(200);

  promptMsg("XX:XX:XX", ST77XX_RED, 10, 50, 3);
}

void loop() {

  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;

    if(WiFi.status() != WL_CONNECTED){

      tft.fillRect(9, 49, 170, 26, ST77XX_BLACK);
      drawText("OFF Line", ST77XX_YELLOW, 10, 50, 3);
      
      Serial.println("WiFi.status(): " + deCode_WiFiStatus(WiFi.status()));
      digitalWrite(LED_BUILTIN, LOW);  //LED OFF

      //re-connect if dis-connected
      if(WiFi.begin(ssid, pass) == WL_CONNECTED){
        digitalWrite(LED_BUILTIN, HIGH);  //LED ON
        Serial.println("\n--- WiFi connected ---");
        printWifiStatus();
      }else{
        Serial.println("WiFi.status(): " + deCode_WiFiStatus(WiFi.status()));
      }
    }else{
      digitalWrite(LED_BUILTIN, HIGH);  //LED ON
    }
  }

  if (currentMillis >= nxRqsNTP) {
    if(WiFi.status() == WL_CONNECTED){
      nxRqsNTP = millis() + intervalRqsNTP;
      readNTP();
    }
  }
}

void readNTP(){

  Serial.println("\nStarting connection to server...");
  Udp.begin(localPort);
  
  sendNTPpacket(timeServer); // send an NTP packet to a time server
  // wait to see if a reply is available
  delay(1000);
  if (Udp.parsePacket()) {
    Serial.println("packet received");
    // We've received a packet, read the data from it
    Udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer

    //the timestamp starts at byte 40 of the received packet and is four bytes,
    // or two words, long. First, extract the two words:

    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long 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 = ");
    // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
    const unsigned long seventyYears = 2208988800UL;
    // subtract seventy years:
    unsigned long epoch = secsSince1900 - seventyYears;
    // print Unix time:
    Serial.println(epoch);
  
    char bufUTC[9];

    unsigned long UTChr = (epoch  % 86400L) / 3600;
    unsigned long UTCmin = (epoch  % 3600) / 60;
    unsigned long UTCsec = epoch % 60;
    
    sprintf(bufUTC,"%02u",UTChr);
    bufUTC[2] = ':';
    sprintf(bufUTC+3,"%02u",UTCmin);
    bufUTC[5] = ':';
    sprintf(bufUTC+6,"%02u",UTCsec);

    tft.fillRect(9, 49, 170, 26, ST77XX_BLACK);
    drawText(bufUTC, ST77XX_YELLOW, 10, 50, 3);
    

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

  Udp.stop();
}

// send an NTP request to the time server at the given address
unsigned long sendNTPpacket(IPAddress& address) {
  //Serial.println("1");
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  //Serial.println("2");
  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;

  //Serial.println("3");

  // 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
  //Serial.println("4");
  Udp.write(packetBuffer, NTP_PACKET_SIZE);
  //Serial.println("5");
  Udp.endPacket();
  //Serial.println("6");
}

void printWifiStatus() {
  Serial.println("WiFi.status(): " + deCode_WiFiStatus(WiFi.status()));
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your board's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

String deCode_WiFiStatus(uint8_t status){
  switch (status){
    case WL_CONNECTED: return "WL_CONNECTED";
    case WL_AP_CONNECTED: return "WL_AP_CONNECTED";
    case WL_AP_LISTENING: return "WL_AP_LISTENING";
    case WL_NO_SHIELD: return "WL_NO_SHIELD";
    //case WL_NO_MODULE: return "WL_NO_MODULE";
    case WL_IDLE_STATUS: return "WL_IDLE_STATUS";
    case WL_NO_SSID_AVAIL: return "WL_NO_SSID_AVAIL";
    case WL_SCAN_COMPLETED: return "WL_SCAN_COMPLETED";
    case WL_CONNECT_FAILED: return "WL_CONNECT_FAILED";
    case WL_CONNECTION_LOST: return "WL_CONNECTION_LOST";
    case WL_DISCONNECTED: return "WL_DISCONNECTED";
    default: return("unknown!!!");
    
  }
}

void promptMsg(char *text, uint16_t color, int16_t x, int16_t y, uint8_t textsize){
  tft.fillScreen(ST77XX_BLACK);
  tft.drawRect(0, 0, tft.width(), tft.height(), ST77XX_WHITE);
  drawText(text, color, x, y, textsize);
}

void drawText(char *text, uint16_t color, int16_t x, int16_t y, uint8_t textsize) {
  tft.setCursor(x, y);
  tft.setTextSize(textsize);
  tft.setTextColor(color);
  tft.setTextWrap(true);
  tft.print(text);
}

Comments

Popular posts from this blog

MicroPython/ESP32-C3 + 1.8" 128x160 TFT ST7735 SPI, using boochow/MicroPython-ST7735 library.

CameraWebServe: ESP32-S3 (arduino-esp32) + OV5640 camera module