espressif / arduino-esp32

Arduino core for the ESP32
GNU Lesser General Public License v2.1
12.99k stars 7.29k forks source link

SimpleTime example extended to deep Sleep --> TimeZone lost #1291

Closed rin67630 closed 6 years ago

rin67630 commented 6 years ago

Hardware:

Board: ESP32 LoLin32 Core Installation/update date: Jun 8 2016 00:22:57 IDE name: Arduino IDE Flash Frequency: 40Mhz Upload Speed: 115200

Description:

The SimpleTime example is the only one that uses the RTC of the ESP32 and provides time beyond deep sleep. However after a deep sleep the time zone settings are lost.

Generally, the SimpleTime example lacks imho compatibilty with the other Arduino time libraries. now(); does not work, I could not find a workaround. second(); to year(); do not work, I found out that _timeinfo.tmsec to _timeinfo.tmyear contains the info as well, but having it the usual way would be nice.

Sketch:

//***Libraries***

#include <WiFi.h>
#include "time.h"
#include "SSD1306.h"
#include "SPIFFS.h"
#include <WiFiUdp.h>

#define uS_TO_S_FACTOR 1000000  /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP  1       /* ESP32 will go to sleep for (x seconds) */

const char* ssid       = "SSID";
const char* password   = "PASS";
const char* ntpServer = "de.pool.ntp.org";
const long  gmtOffset_sec = 3600;
const int   daylightOffset_sec = 3600;
int second;
int minute;
int hour;
int day;
int month;
int year;
int weekday;
struct tm timeinfo;
//Parameters see: http://www.cplusplus.com/reference/ctime/tm/

//***Hardware Definitions***
#define SCL 5  // GPIO for I2C (Wire) System Clock
#define SDA 4  // GPIO for I2C (Wire) System Data
#define MOSI  13 // GPIO for SPI Master Out
#define MISO  12 // GPIO for SPI Master In
#define SCLK  14 // GPIO for SPI System Clock
#define OLED_RESET 0  // GPIO0
char buffer[16];

byte mac[6];   // the mac address of your Wifi shield
IPAddress ip;

RTC_DATA_ATTR int bootCount = 0; //Boot count should be stored in the non volatile RTC Memory

void setup()
{
  Serial.begin(115200);
  analogSetWidth(10);                           // 10Bit resolution for better linearity
  analogSetAttenuation((adc_attenuation_t)0);   // 0=0db (0..1V) 1= 2,5dB; 2=-6dB (0..1V); 3=-11dB

  esp_sleep_wakeup_cause_t wakeup_reason;
  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch (wakeup_reason)
  {
    case 1  : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case 2  : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case 3  : Serial.println("Wakeup caused by timer");
      WiFi.disconnect(true);
      WiFi.mode(WIFI_OFF);
      break;
    case 4  : Serial.println("Wakeup caused by touchpad"); break;
    case 5  : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.println("Wakeup was not caused by deep sleep");
      if (!getLocalTime(&timeinfo))
      {
        //connect to WiFi
        Serial.print("Connecting to %s "); Serial.println(ssid);

        WiFi.begin(ssid, password);
        while (WiFi.status() != WL_CONNECTED) {
          delay(500);
          Serial.print(".");
        }
        ip = WiFi.localIP();
        Serial.print("IP number assigned by DHCP is "); Serial.println(ip);

        //init and get the time
        configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
        Serial.print("SNTP fetched time is: "); printLocalTime();

        //disconnect WiFi as it's no longer needed
        WiFi.disconnect(true); WiFi.mode(WIFI_OFF);
      }
      break;
  }
  bootCount++;
  Serial.print("Boot count: ");
  Serial.print(bootCount);
  Serial.print(" | RTC time is: ");
  printLocalTime();
  ip = WiFi.localIP();
  Serial.print("IP number is currently ");
  Serial.print(ip);
  Serial.println();
}

void loop()
{
  getTimeValues();
  Serial.print("Setup ESP32 to sleep for ");
  Serial.print(TIME_TO_SLEEP);
  Serial.println(" Seconds");
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  Serial.println("Going to sleep now");
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}

void print_wakeup_reason()
{
  esp_sleep_wakeup_cause_t wakeup_reason;
  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch (wakeup_reason)
  {
    case 1  : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case 2  : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case 3  : Serial.println("Wakeup caused by timer"); break;
    case 4  : Serial.println("Wakeup caused by touchpad"); break;
    case 5  : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.println("Wakeup was not caused by deep sleep"); break;
  }
}

void getTimeValues()
{
  getLocalTime(&timeinfo);
  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 + 1;
}

void printLocalTime()
{

  if (!getLocalTime(&timeinfo)) {
    Serial.println("Failed to obtain time");
    return;
  }
  Serial.println(&timeinfo, "%A, %d %B %Y %H:%M:%S");
  //Parameters see: http://www.cplusplus.com/reference/ctime/strftime/
}

Debug Messages, Serial Output:


ets Jun  8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:812
load:0x40078000,len:0
load:0x40078000,len:11404
entry 0x40078a28
Wakeup was not caused by deep sleep
Connecting to GW-FM-MA ....IP number assigned by DHCP is 192.168.178.26
SNTP fetched time is: Wednesday, 04 April 2018 23:22:11
Boot count: 1 | RTC time is: Wednesday, 04 April 2018 **23:22:11**
IP number is currently 0.0.0.0
Setup ESP32 to sleep for 1 Seconds
Going to sleep now
ets Jun  8 2016 00:22:57

rst:0x5 (DEEPSLEEP_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:812
load:0x40078000,len:0
load:0x40078000,len:11404
entry 0x40078a28
Wakeup caused by timer
Boot count: 2 | RTC time is: Wednesday, 04 April 2018 **21:22:13**
IP number is currently 0.0.0.0
Setup ESP32 to sleep for 1 Seconds
Going to sleep now
ets Jun  8 2016 00:22:57
lbernstone commented 6 years ago

Word on the street is that the internal RTC runs slow, but this seems to handle what you are looking for:

#include <WiFi.h>

#define NTP_SERVER "us.pool.ntp.org"
#define TZ_INFO "MST7MDT6,M3.2.0/02:00:00,M11.1.0/02:00:00" // Americas/Denver
#define SLEEPTIME 1E7 //microseconds

void initFirst() {
#ifdef MYSSID
  WiFi.begin(MYSSID,PASSWD);
#else    
  WiFi.begin();
#endif  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  delay(200);
  Serial.println(WiFi.localIP());
  struct tm local;
  getLocalTime(&local, 10000); // wait up to 10sec to sync
}

void setup() {
  Serial.begin(115200);
  configTzTime(TZ_INFO, NTP_SERVER);
  esp_sleep_wakeup_cause_t wakeup_cause;
  wakeup_cause = esp_sleep_get_wakeup_cause();
  Serial.println(wakeup_cause);
  if (wakeup_cause != 3) initFirst();
}

void loop() {
  tm local;
  getLocalTime(&local);
  Serial.println(&local, "Time set: %B %d %Y %H:%M:%S (%A)");
  Serial.println("Entering sleep");
  esp_sleep_enable_timer_wakeup(SLEEPTIME);
  esp_deep_sleep_start();
}
rin67630 commented 6 years ago

Thank you for your example. it however prints the time only once after sync, not after deep-sleep

ets Jun  8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:812
load:0x40078000,len:0
load:0x40078000,len:11404
entry 0x40078a28
0
.........192.168.178.26
Time set: April 05 2018 02:34:56 (Thursday)
Entering sleep
ets Jun  8 2016 00:22:57

rst:0x5 (DEEPSLEEP_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:812
load:0x40078000,len:0
load:0x40078000,len:11404
entry 0x40078a28
3
ets Jun  8 2016 00:22:57

rst:0x5 (DEEPSLEEP_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:812
load:0x40078000,len:0
load:0x40078000,len:11404
entry 0x40078a28
3
ets Jun  8 2016 00:22:57
lbernstone commented 6 years ago

Maybe you need a short delay b/w the printlns and the sleep command, but you should at least get the first couple characters into the buffer before it passes out. It works perfectly on my Heltec wifi kit based board.

stickbreaker commented 6 years ago

@rin67630 What RTC?

The deepsleep function just adds the specified sleep time to the milliseconds counter?

Chuck

rin67630 commented 6 years ago

@stickbreaker

The deepsleep function just adds the specified sleep time to the milliseconds counter? I don't know the details, the ESP32 Specs do mention a built in RTC. The time is kept current and the ESP returns with the correct time set after a deep sleep, that's what matters.

rin67630 commented 6 years ago

With the correct coding the time-zone can be reactivated after a deep sleep. So it was just a matter of documentation. Sorry for the inconvenience.

pbrandst commented 5 years ago

@rin67630 - I saw you closed with the comment using the correct coding it worked, but I am facing exactly the same problem you described. In my setup function I am when starting first time after reset getting the current time with: configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); both offsets are 3600 I am then using getLocalTime(&timeinfo); to read the time and dispaly the time. Everything works fine and then go to deep sleep touchAttachInterrupt(T0, callback, Threshold);

//Configure Touchpad as wakeup source esp_sleep_enable_touchpad_wakeup();

after wake up with touching T0 I come again in my setup there I run the following code if (bootCount++ > 0) { if(!getLocalTime(&timeinfo)){ DPRINTLN("Failed to obtain time"); } else { DPRINT(timeinfo.tm_hour); DPRINT(":"); DPRINTLN(timeinfo.tm_min); ShowTime(timeinfo.tm_hour,timeinfo.tm_min); } }

bootCount is an RTC variable, so this part of the code is only executed after wakeup from deep sleep, meaning the time has been already set by NTP.

However, after deepsleep I am getting an hour earlier (currently no DST and I am in Austria). So seems that the tiomezone settings got lost. My question to @rin67630 - what did you change in your code that timezone corrections did work after deep sleep ?

pfeerick commented 4 years ago

Just to document this for anyone else looking in the future (as was I when trying to get NTP time working in conjunction with the RTC and deepsleep)... it's possible the change in code was in relation to how the timezone was set.... instead of

configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);

I use

configTime(0, 0, ntpServer);
// TZ string information: https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
setenv("TZ", "AEST-10", 1);
tzset(); // save the TZ variable

and it works just fine now. Don't forget to repeat the last two lines in the section of your code that DOESN'T enable the wifi & do the NTP lookup, or at least make sure it always runs, else you'll retrieve the un-timezone-corrected time/date ;) Not that I know from experience! 😂😂

I have been able to use configTzTime(TZ_INFO, NTP_SERVER); instead of the above three statements, but I find it only works for the initial lookup - if the wifi has not connected, the ESP32 resets.

RodGat100 commented 4 years ago

@pfeerick, thank you for "just documenting", solved my problem.

larsinka commented 3 years ago

@pfeerick do you have a link to documentation about setenv ? Does the parameter "TZ" only specify the format that is used for the timezone configuration? What does the "1" do?

lbernstone commented 3 years ago

https://man7.org/linux/man-pages/man3/setenv.3.html https://raw.githubusercontent.com/nayarsystems/posix_tz_db/master/zones.csv

Bredahl commented 1 year ago

I don't know if this could be of help to anyone. Setting the time using mktime and settimeofday.

  configTime(0, 0, "pool.ntp.org");
//configTime(3600, 0, "pool.ntp.org");

  struct tm tm;
  getLocalTime(&tm);
  //tm.tm_hour = tm.tm_hour + 1;
  time_t t = mktime(&tm);
  //Serial.printf("Setting time: %s", asctime(&tm));
  struct timeval now = { .tv_sec = t + 3600};
  settimeofday(&now, NULL);