Convert Epoch to variables with ESP32

Hi all,

I have built a LED clock with an embedded ATMEGA328 and MAX7219 drivers. I want to display time and date, day number (1-366), week number (01-53), temp and humidity (DHT sensor). Originally, I was using an RTC DS3231 module for timekeeping. Then I discovered the ESP32 and I thought it would be cool to use the I2C interface on my board to get the time off the Internet.

Since I’m a rookie with C, I found the piece of code below and I started fiddling with it to extract the time, date, day number and week number.

void printLocalTime()
{
  time_t rawtime;
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo))
  {
    Serial.println("Failed to obtain time");
   return;
  }
  char timeStringBuff[50];
  strftime(timeStringBuff, sizeof(timeStringBuff), "%A, %B %d %Y %H:%M:%S", &timeinfo);
  //print like "const char*"
  Serial.println(timeStringBuff);

  //Optional: Construct String object 
  String asString(timeStringBuff);
}

The Wi-Fi & NTP part is working and I have been able to display time, date, day number and the DHT readings using Nick Gammon’s “I2Canything” library (ESP32 acting as master, embedded ATMEGA 328 as slave).

As long as I use a call to printLocalTime() in my loop, followed by a direct assignment to variables from the so called “specifiers” like timeinfo.tm_sec, it seems to be working (see master code below). I can use the bytes on the slave side to display the variables with ledcontrol.

Trouble is, I cannot fathom how to extract the week number using the printLocalTime function. If I try using the standard strftime() function with the sole “%W” specifier, date and time won’t work.

Do you guys have any idea?

Here is my sandbox code, still sloppy for the time being.

Master code on the ESP32

#include <WiFi.h>
#include "time.h"
#include <I2C_Anything.h>
#include "DHT.h"

const byte SLAVE_ADDRESS = 8;

#define DHTPIN 14
#define DHTTYPE DHT11

DHT dht(DHTPIN, DHTTYPE);

const char* ssid       = "mySSID";
const char* password   = "myKey";

const char* ntpServer = "pool.ntp.org";
const long  gmtOffset_sec = 3600;
const int   daylightOffset_sec = 3600;

byte connectionStatus;
byte second;
byte lastSecond;
byte minute;
byte hour;
byte day;
long year;
long yday;
byte month;
byte weekday;
byte isDST;
byte* current;
float hum;
float temp;
struct tm timeinfo;

void printLocalTime()
{
  if(!getLocalTime(&timeinfo)){
    Serial.println("Failed to obtain time");
    return;
  }
  //Serial.println(&timeinfo, "%H:%M:%S %d-%m-%y %W %w");

}

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

  dht.begin();

  Wire.begin();
   
  //connect to WiFi
  Serial.printf("Connecting to %s ", ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
  }
  Serial.println(" CONNECTED");
  connectionStatus=1;
  Wire.beginTransmission(SLAVE_ADDRESS);
  I2C_writeAnything (connectionStatus);              
  Wire.endTransmission();

  
  //init and get the time
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  printLocalTime();

  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);

  if (WiFi.status() == WL_DISCONNECTED) {
    connectionStatus=0;
    Wire.beginTransmission(SLAVE_ADDRESS);
    I2C_writeAnything (connectionStatus);              
    Wire.endTransmission();
  }

  hum = dht.readHumidity();
  temp = dht.readTemperature();

  delay(300);

  Wire.beginTransmission(SLAVE_ADDRESS);
  I2C_writeAnything (hum);              
  I2C_writeAnything (temp);
  Wire.endTransmission();

}

void loop()
{

  printLocalTime();
  second = timeinfo.tm_sec;
  minute = timeinfo.tm_min;
  hour = timeinfo.tm_hour;
  day = timeinfo.tm_mday;
  month = timeinfo.tm_mon + 1;
  year = timeinfo.tm_year + 1900;
  weekday = timeinfo.tm_wday;
  yday = timeinfo.tm_yday;

  if (lastSecond!=second) {

    Wire.beginTransmission(SLAVE_ADDRESS);
    I2C_writeAnything (hour);
    I2C_writeAnything (minute);
    I2C_writeAnything (second);
    I2C_writeAnything (day);
    I2C_writeAnything (month);
    I2C_writeAnything (year);
    I2C_writeAnything (weekday);
    I2C_writeAnything (yday);  
    I2C_writeAnything (hum);              
    I2C_writeAnything (temp);
    Wire.endTransmission();

    lastSecond=second;

    Serial.println(hum);
    Serial.println(temp);

  }

  if (second==30) {

    hum = dht.readHumidity();
    temp = dht.readTemperature();

    Serial.println(hum);
    Serial.println(temp);
    if (isnan(hum) || isnan(temp)) {
    Serial.println("Failed to read from DHT sensor!");
      return;
    }

  }

}

Slave code on the ATMEGA328

#include <I2C_Anything.h>
#include <LedControl.h>

const byte MY_ADDRESS = 8;

boolean haveData = false;
boolean haveDataWiFi = false;
boolean haveDataDHT = false;

byte connectionStatus;
float h;
float t;
int temp;
int humi;

byte testByte;
byte second;
byte minute;
byte hour;
byte day;
byte month;
long year;
long yday;
byte weekday;
byte lastSecond;

int secOnes=0;  
int secTens=0;  
int minOnes=0;
int minTens=0;
int hourOnes=0;
int hourTens=0;
int dayOnes=0;
int dayTens=0;
int monthOnes=0;
int monthTens=0;
int yearOnes=0;
int yearTens=0;
int ydayOnes=0;
int ydayTens=0;
int ydayHundreds=0;
int tempDecimal=0;
int tempOnes=0;
int tempTens=0;
int humiHundreds=0;
int humiTens=0;
int humiOnes=0;
int wiFiLed=11;

LedControl lc1=LedControl(6,5,7,1);
LedControl lc2=LedControl(3,2,4,1);
LedControl lc3=LedControl(9,8,10,1);

void setup() {
  Serial.println("Start");
  Wire.begin(MY_ADDRESS; 
  Wire.onReceive(receiveEvent);
  Serial.begin(115200);

  pinMode(5,OUTPUT);
  pinMode(6,OUTPUT);
  pinMode(7,OUTPUT);
  pinMode(wiFiLed,OUTPUT);

  lc1.shutdown(0,false); 
  lc2.shutdown(0,false);
  lc3.shutdown(0,false);
  delay(50);
  lc1.setIntensity(0,8);   
  lc2.setIntensity(0,8);
  lc3.setIntensity(0,8);
  delay(50);
  lc1.clearDisplay(0);
  lc2.clearDisplay(0);
  lc3.clearDisplay(0);
  delay(50);

}

void loop()
{

  if (haveDataWiFi)
    {

    if (connectionStatus == 1) {
      digitalWrite (wiFiLed, HIGH);
    }

    else {
      digitalWrite (wiFiLed, LOW);
    }
  
    haveDataWiFi=false;

  }

  if (haveData)
    {
    

    if (second != lastSecond) {

      secOnes=second%10;  
      secTens=(second/10)%6;  
      minOnes=minute%10;  
      minTens=(minute/10)%6;

      hourOnes=hour%10;
      hourTens=(hour/10)%10;

      lc1.setDigit(0,7,hourTens,false);
      lc1.setDigit(0,6,hourOnes,false);
      lc1.setChar(0,5,'-',false);
      lc1.setDigit(0,4,minTens,false);
      lc1.setDigit(0,3,minOnes,false);
      lc1.setChar(0,2,'-',false);
      lc1.setDigit(0,1,secTens,false);
      lc1.setDigit(0,0,secOnes,false);

      lastSecond=second;

    }

    dayOnes=day%10;
    dayTens=(day/10)%10;
    monthOnes=month%10;
    monthTens=(month/10)%10;
    yearOnes=(year-2000)%10;
    yearTens=(year%2000)/10;

    lc2.setDigit(0,1,yearTens,false);
    lc2.setDigit(0,0,yearOnes,false);
    lc2.setChar(0,2,'-',false);
    lc2.setDigit(0,4,monthTens,false);
    lc2.setDigit(0,3,monthOnes,false);
    lc2.setChar(0,5,'-',false);
    lc2.setDigit(0,7,dayTens,false);
    lc2.setDigit(0,6,dayOnes,false);
   
    ydayOnes=yday%10;
    ydayTens=(yday/10)%10;
    ydayHundreds=(yday/100)%4;

    lc3.setDigit(0,0,ydayHundreds,false);
    lc3.setDigit(0,1,ydayTens,false);
    lc3.setDigit(0,2,ydayOnes,false);

    haveData = false;

  }

  if (haveDataDHT) {

    humi = h;
    temp = (int) t;
    haveDataDHT=false;

  }


  humiOnes=humi%10;
  humiTens=(humi/10)%10;

  tempOnes=temp%10;
  tempTens=(temp/10)%10;

  lc3.setDigit(0,4,humiTens,false);
  lc3.setDigit(0,5,humiOnes,false);
  lc3.setDigit(0,6,tempTens,false);
  lc3.setDigit(0,7,tempOnes,false);


}

void receiveEvent (int howMany)
 {
 
if (howMany >= (sizeof second) + (sizeof minute) + (sizeof hour) + (sizeof day) + (sizeof month) + (sizeof year) + (sizeof weekday) + (sizeof yday))
 
  {

   I2C_readAnything (hour);
   I2C_readAnything (minute);
   I2C_readAnything (second);
   I2C_readAnything (day);
   I2C_readAnything (month);
   I2C_readAnything (year);
   I2C_readAnything (weekday);
   I2C_readAnything (yday);
   haveData = true;
   }

 if (howMany == (sizeof connectionStatus))
 
  {
   I2C_readAnything (connectionStatus);
   haveDataWiFi = true;
   }
 
 if (howMany >= (sizeof h) + (sizeof t))
 
  {
   I2C_readAnything (h);
   I2C_readAnything (t);
   haveDataDHT = true;
   }

 }

Cheers,

Fred

  //Serial.println(&timeinfo, "%H:%M:%S %d-%m-%y %W %w");

Look at the various overloads of the print() method, in the Print class, that HardwareSerial derives from. Which overload is this calling, when not commented out? Is that second argument valid?

Hi Paul,

It seems to be valid, yes. If I uncomment the command below it will return the string "15:40:35 09-12-18 49 0"

Serial.println(&timeinfo, "%H:%M:%S %d-%m-%y %W %w");

When I try

Serial.println(&timeinfo, "%W");

the printLocalTime() function will return "49", but I cannot transform this value to a usable String, byte, char or int to send over to the slave.

More specifically, I used the code I found to create a String and I tried extracting the values with charAt() to no avail.

I get a compiling error: request for member 'charAt' in 'timeStringBuff', which is of non-class type 'char [50]'

Thanks,

Fred

the printLocalTime() function will return "49", but I cannot transform this value to a usable String, byte, char or int to send over to the slave.

So, the timeinfo struct must contain a value that is the week of the year. Look at the struct, and see what that member is called.

Hi,

This was my first thought and I've tried to find where the timeinfo struct was defined, but couldn't.

The ESP32 uses standard C time library functions, but I cannot make sense of these despite my research.

The link below suggests the week is not that simple to get, however it must be defined somewhere...

http://www.cplusplus.com/reference/ctime/tm/

Has anybody encountered the same issue?

Thanks,

Fred

The link below suggests the week is not that simple to get, however it must be defined somewhere...

Actually, it isn't. The day of the year is, but you need to calculate the week number yourself. Some interesting info here: What's the Current Week Number?

The javascript example looks the most useful. Instead of all the function calls, you can directly access the values from the timeinfo variable (of type struct tm, which IS well documented).