Convert NTP time to integer

I had a Neopixel clock using a Nano with a RTC DS3231 and a OLED display. After about 6 months the time was off by a few minutes. I decided to change to a ESP32 Dev Module and read the time from a NTP server.

I am able to read the NTP server and display the date and time on the OLED display, I am having troubles with getting the Neopixel ring to work. The problem is I am not sure what format the NTP time variables are and I need to convert them to an integer for the pixels.

This is the line that reads the time for the OLED, “Serial.println(&timeinfo, "%A, %B %d %Y %I:%M:%S");”

In this block of code in the “void printLocalTime()” function

 unsigned char hourPos = ((now.hour() % 12) * 5 + (now.minute() + 6) / 12);

   Ring.setPixelColor((hourPos + 59) % 60, Ring.Color(255, 0, 0));
   Ring.setPixelColor(((hourPos) % 60), Ring.Color(255, 0, 0));
   Ring.setPixelColor(((hourPos + 1) % 60), Ring.Color(255, 0, 0));
   Ring.setPixelColor(((now.minute()) % 60) % 60, Ring.Color(0, 255, 0));
   Ring.setPixelColor(((now.second()) % 60) % 60, Ring.Color(0, 0, 255));
   

I need to replace now.hours with %I, now.minute with %M and now.second with %S. the now tags were what I used from the RTC, it doesn’t matter what tags I use here Hrs, Min and Sec will be fine.

I’ve tried a couple of ways to convert it but obviously none are working for me.

Thanks for your help, here is the full sketch.

/* New Neo-pixal clock wuth ESP32
  using NTP server time
*/


#include <WiFi.h>
#include "time.h"
#include "esp_sntp.h"
#include <Wire.h> 
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_NeoPixel.h>

// Reset pin not used but needed for library
#define OLED_RESET -1
//Adafruit_SSD1306 display(OLED_RESET);
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define LEDStripPin 4 // Pin used for the data to the LED strip
#define menuPin 0 // Pin used for the menu button (green stripe)
#define numLEDs 60 // Number of LEDs in strip
Adafruit_NeoPixel Ring = Adafruit_NeoPixel(numLEDs, LEDStripPin, NEO_GRB + NEO_KHZ800);

const char *ssid = "My_SSID";
const char *password = "My_Password";

const char *ntpServer1 = "pool.ntp.org";
const char *ntpServer2 = "time.nist.gov";
const long gmtOffset_sec = 18000; // 5 hours
const int daylightOffset_sec = 3600;

const char *time_zone = "CET-1CEST,M3.5.0,M10.5.0/3";  // TimeZone rule for Europe/Rome including daylight adjustment rules (optional)

void printLocalTime() {
  struct tm timeinfo;
  if (!getLocalTime(&timeinfo)) {
    Serial.println("No time available (yet)");
    return;
  }
  Serial.println(&timeinfo, "%A, %B %d %Y %I:%M:%S");

  // clear LED array
  Ring.clear(); // Set all pixel colors to 'off'

   unsigned char hourPos = ((now.hour() % 12) * 5 + (now.minute() + 6) / 12);

   Ring.setPixelColor((hourPos + 59) % 60, Ring.Color(255, 0, 0));
   Ring.setPixelColor(((hourPos) % 60), Ring.Color(255, 0, 0));
   Ring.setPixelColor(((hourPos + 1) % 60), Ring.Color(255, 0, 0));
   Ring.setPixelColor(((now.minute()) % 60) % 60, Ring.Color(0, 255, 0));
   Ring.setPixelColor(((now.second()) % 60) % 60, Ring.Color(0, 0, 255));
   

   Ring.show();   // Send the updated pixel colors to the hardware.

  
 // Clear the display
  display.clearDisplay();
  //Set the color - always use white despite actual display color
  display.setTextColor(WHITE);
  //Set the font size
  display.setTextSize(2);
  //Set the cursor coordinates
  display.setCursor(0, 10);

  // display.print("Time");
  display.setCursor(20, 15);
  display.print(&timeinfo, "%I:%M:%S");

  // display date
  display.setCursor(7, 45);
  display.print(&timeinfo, "%b/%d/%y");

  display.display(); // Update screen

}

// Callback function (gets called when time adjusts via NTP)
void timeavailable(struct timeval *t) {
  Serial.println("Got time adjustment from NTP!");
  printLocalTime();
}

void setup() {
  Serial.begin(115200);

  // First step is to configure WiFi STA and connect in order to get the current time and date.
  Serial.printf("Connecting to %s ", ssid);
  WiFi.begin(ssid, password);
  Wire.begin(); // Starts the Wire library allows I2C communication

    esp_sntp_servermode_dhcp(1);  // (optional)

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println(" CONNECTED");

  // set notification call-back function
  sntp_set_time_sync_notification_cb(timeavailable);

  /**
   * This will set configured ntp servers and constant TimeZone/daylightOffset
   * should be OK if your time zone does not need to adjust daylightOffset twice a year,
   * in such a case time adjustment won't be handled automagically.
   */
  configTime(-gmtOffset_sec, daylightOffset_sec, ntpServer1, ntpServer2);

  
  // initialize OLED with I2C addr 0x3C
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);

  // Start LEDs
  Ring.begin();
  Ring.setBrightness(15);
  Ring.show(); // Initialize all pixels to 'off'

} //end setup

void loop() {
  delay(1000);

  printLocalTime();  // it will take some time to sync time :)

  

} //end loop


You don't need to "convert" anything. Calling time(nullptr) on an ESP32 will return the epoch time as a 64-bit signed integer:

   time_t now = time(nullptr);
1 Like

The time library should have functions to return the hour, minute, second, etc. I’m not where I can look up the C library at the moment.

Just for giggles, where is that documented?

Per the Espressif Documentation, ESP32 supports the standard C time library.

The variable type would be time_t, the base type is going to be dependent on the processor you are compiling for.

The time can be converted from a time_t to a tm struct using the gmtime() or localtime() functions, which breaks it out into hours, minutes, seconds, day, month, year, etc.

See the documentation for the standard C time.h

1 Like

Here's your function using a tm struct.

I did not test it, but all your original code needed was hh, mm and ss.

void printLocalTime() {
 struct tm timeinfo;
 if (!getLocalTime(&timeinfo)) {
   Serial.println("Failed to obtain time");
   return;
 }

 int hh = timeinfo.tm_hour;   // 24-hour format
 int mm = timeinfo.tm_min;
 int ss = timeinfo.tm_sec;

 // Convert hour to 12-hour format and map to pixel ring
 unsigned char hourPos = ((hh % 12) * 5 + (mm + 6) / 12);

 Ring.setPixelColor((hourPos + 59) % 60, Ring.Color(255, 0, 0)); // red blur left
 Ring.setPixelColor((hourPos) % 60, Ring.Color(255, 0, 0));      // red center
 Ring.setPixelColor((hourPos + 1) % 60, Ring.Color(255, 0, 0));  // red blur right

 Ring.setPixelColor(mm % 60, Ring.Color(0, 255, 0));  // green minute
 Ring.setPixelColor(ss % 60, Ring.Color(0, 0, 255));  // blue second

 Ring.show();
}

HTH

a7

Excellent. @alto777 I loaded your changes in and it’s working fine.

Thanks to all for the clarification and the help.

1 Like