Blynk +rtc +"time compensation" to wake up from deep sleep on exact second

I need blynk to trigger a blink at a specific time (interval) based on the RTC widget.

I’m new to coding so … please be gentle :slight_smile:

Here is my code ( help needed at "/ /help " line )

/*-----------------------------------------------
///

/*
 * I need this esp8266 code to wake up on exact time (as much as possible :) )
  * some kind of inner time compensation 
 * then re-sync time (for next exact wake up
 * then go back to sleep
 */

#define BLYNK_PRINT Serial
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <TimeLib.h>
#include <WidgetRTC.h>



char auth[] = "auth";
char ssid[] = "ssid";
char pass[] = "pass";

BlynkTimer timer;
WidgetRTC rtc;
WidgetTerminal terminal(V1);




const int sleepSeconds = 10;
//const int wakeUpAt = ?????  12:00:00 ??????;    //// < Help needed



digitalWrite(BUILTIN_LED, HIGH);

void clockDisplay()
{
  String currentTime = String(hour()) + ":" + minute() + " " + second()+ "'";
  String currentDate = String(day()) + "/" + month() + "/" + year();
  Serial.print("T: ");
  Serial.print(currentTime);
  Serial.print("   ");
  Serial.print(currentDate);
  Serial.println();

   terminal.print("");
   terminal.print(currentTime);
   terminal.print("  ");
   terminal.print(currentDate);
   terminal.println();
   terminal.println("");
   terminal.println(" ");
   terminal.flush();

  Blynk.virtualWrite(V2, currentTime);
  Blynk.virtualWrite(V3, currentDate);
}

BLYNK_CONNECTED() {
  // Synchronize time on connection
  rtc.begin();
}



void setup()
{
  Serial.begin(9600);
  Blynk.begin(auth, ssid, pass);


  pinMode(BUILTIN_LED, OUTPUT);
  pinMode(D0, WAKEUP_PULLUP);

  setSyncInterval(1*60); // Sync interval in minutes
  timer.setInterval(10*1000L, clockDisplay);

    for (int i = 0; i < 20; i++)
  {
    digitalWrite(BUILTIN_LED, LOW);
    delay(100);
    digitalWrite(BUILTIN_LED, HIGH);
    delay(100);

  Serial.printf("I'm going to Sleep for %d seconds\n\n", sleepSeconds);
  ESP.deepSleep(sleepSeconds * 1000000);
  }
 }



void loop()
{
  Blynk.run();
  timer.run();
}


*/

TNX

This cannot be done this way. The ESP will wake up after x-seconds, but you can never time that because in deepsleep it has no knowledge of the time.

E.g if you put it to deepsleep at 10:00am for 60s it will wake up at 10:01.

Also the loop in your setup contains delay for 20x100ms which is not good.

Can you explain more about your project? That might give us a better hint on what you need to achieve your goals :slight_smile:

To my understanding it is possible and the ESP8266 internal clock is fairly precise … and I only need it to wake up at around the exact time (give or take 3 seconds) then re-calibrate it’s interval clock to compensate to the real world time … and back to sleep - just to wake up later at a given time or at exact pre-configured time.

Eventually it will trigger a simple sensor at a specific minute on every hour of the day .

I’m not sure if you can achieve this because I don’t think you can time the wake-up/sleep proces with this much accuracy. You’ll also need to be doing the measurements and so on.

I’m thinking you can set the ESP to wake up, sync time, do measurements and than wait for a specific time to put it in deepsleep.

E.g.

  • Wakeup at 10.00
  • (do stuff here, sync time and so on)
  • DeepSleep at 10.05 (give it some time to handle things)
  • Deepsleep for 55 minutes.

That way you can be fairly sure it will trigger at the right times. 5 minutes or more to do stuff will probably be overkill for reading a couple sensors, but the time trigger will be accurate I think.

I think you over thinking this.

this is simple:

  1. lets say interval is 60 seconds and time to wake up is at 12:00
    1.wakeup
    2.get rtc
    3.realize it is 11:58 change 60 to 180 (minus all other delays (can be pre calculated).
    4.do your thing ( sensor / blinking )
  2. go back to sleep

1.wake up at 12:00
repeat …

I just dont know the coding syntax to achieve this …

No, it’s not possible to wake an ESP from itself. You have to put in a signal to the ESP to wake up from deepsleep. You cannot set a timer to wake up from itself because it’s not active.

@Lichtsignaal but the duration of required sleep time can be calculated from trigger time less current time.

@dandan yes this can be done but the ESP’s clock is quite poor and loses up to 10 minutes per day. Probably not a problem in your case.

Until recently maximum deepSleep was defined as 2 to the power 32 which is 4,294,496,296 micro seconds or 4295 seconds or approx 71.6 minutes.

Create a long variable based on (X * hours() * 3600) + (Y * minutes() * 60) + (Z * seconds() ) for your trigger time. So if you want the trigger at 10:15:45 X is 10, Y is 15 and Z is 45.

Establish current time as a long from RTC in the same way. Compare the 2 longs and set the deepSleep duration. Keep using the maximum deepSleep duration until trigger time is less than 4295 seconds.

I saw a GitHub post recently about a change to deepSleep but struggling to find it. Will post if I find it.

This may not be in depth enough, but I found this and have been reading it a bit in preparation :wink:

Chapter 4 talks about using Deep Sleep and how the RTC does stay active to allow periodic wakeups.

@dandan ok latest details on deepSleep duration.

In May Espressif’s released 2.1.0 SDK as per https://github.com/espressif/ESP8266_NONOS_SDK/releases/tag/v2.1.0 and under System changes it has:

11. Support long periods of deep sleep;

The change is covered in section 3.3.9 of their pdf at http://www.espressif.com/sites/default/files/documentation/2c-esp8266_non_os_sdk_api_reference_en.pdf

Namely:

uint64	time_in_us: the duration of time (ÎĽs) when the device is in Deep-sleep.
The theoretical maximum value of time_in_us can be calculated by formula:
(time_in_us	/	cali)	<<	12	=	2^31	-	1

• cali	=	system_rtc_clock_cali_proc(), the cali is the RTC clock period (in
us); bit11 ~ bit0 are decimal. For more details about the cali, please see the
API: system_rtc_clock_cali_proc. 

The following post http://www.esp8266.com/viewtopic.php?p=67729#p67729 calculates that from the change above that the new maximum deepSleep duration is possibly around 192 minutes.

The increased deepSleep durations are not yet in the master branch of the ESP8266 Arduino core.

1 Like

Thank you so much for the info .

So… as I understand : maximum period of a deep sleep can be up to 192 minutes… (3.2 h)…

What about light sleep ? will it be 24H or more ?

But even so - can you direct me to a code (or edit my initial code) showing a calibration of the wake up interval - based on input from Blynk RTC widget ?

I’m sure someone already have done that . .but I cant seem to find an example code…

Why would you want light sleep?

Take a look at some of the logic in this stripped down version of your sketch

// MaxSleep.ino per https://community.blynk.cc/t/blynk-rtc-time-compensation-to-wake-up-from-deep-sleep-on-exact-second/16216

#define BLYNK_PRINT Serial
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <TimeLib.h>
#include <WidgetRTC.h>

char auth[] = "auth";
char ssid[] = "ssid";
char pass[] = "pass";

BlynkTimer timer;
WidgetRTC rtc;

// seconds in a day 86400 but rolls over to 0 after 86399
unsigned int sleepSeconds;      // calculate from timeNow and wakeUpAt
unsigned int wakeUpAt  = 43200; // 12 noon X 3600s 
unsigned int timeNow;           // time now from RTC in seconds
unsigned int maxSleep  =  3600; // say 60 minutes = 3600 seconds 


// digitalWrite(BUILTIN_LED, HIGH);  // NOT HERE

void clockDisplay()
{
  if(year() != 1970){
    String currentTime = String(hour()) + ":" + minute() + " " + second()+ "'";
    //String currentDate = String(day()) + "/" + month() + "/" + year();
    timeNow = ((hour() * 3600) + (minute() * 60) + second()) * 100000;

    if(timeNow > wakeUpAt){               // trigger time has already passed for today
      Serial.println("Trigger time has already passed for today");
      if(86399 - timeNow >= maxSleep){     // more than 60 minutes to midnight
        Serial.println("Sleeping for maximum time");
        sleepSeconds = maxSleep;  
      }
      else{                               // less than 60 minutes to midnight
        sleepSeconds = (86399 - timeNow);
        Serial.println("Sleeping until midnight");  
      }
    }
    else{                                 // trigger time has not passed for today
      Serial.println("Trigger time has not passed for today");
      if(wakeUpAt - timeNow >= maxSleep){  // more than 60 minutes to trigger time
        Serial.println("Sleeping for maximum time");
        sleepSeconds = maxSleep;  
      }
      else{                               // less than 60 minutes to trigger time
        sleepSeconds = (wakeUpAt - timeNow);
        Serial.println("Sleeping until trigger time");  
      }        
    }
        
    Serial.printf("I'm going to Sleep for %d seconds\n\n", sleepSeconds);
    ESP.deepSleep(sleepSeconds * 1000000);
    delay(100);
  }
}

BLYNK_CONNECTED() { 
  rtc.begin(); // Synchronize time on connection
}

void setup()
{
  Serial.begin(9600);
  Blynk.begin(auth, ssid, pass);
  pinMode(BUILTIN_LED, OUTPUT);
  pinMode(D0, WAKEUP_PULLUP);
  setSyncInterval(1*60); // Sync interval in minutes
  timer.setInterval(10*1000L, clockDisplay);

    for (int i = 0; i < 20; i++)
  {
    digitalWrite(BUILTIN_LED, LOW);
    delay(100);
    digitalWrite(BUILTIN_LED, HIGH);
    delay(100);
  }
  // moved deepSleep to the clockDisplay function
 }

void loop()
{
  Blynk.run();
  timer.run();
}
1 Like

With the following revised lines in setup() and maxSleep set to 40s for testing purposes it shows a cycle time, including connection to the server of 43 to 44 seconds.

  setSyncInterval(1); // Sync interval in seconds
  timer.setInterval(1000L, clockDisplay);

  for (int i = 0; i < 10; i++)
  {
    digitalWrite(BUILTIN_LED, LOW);
    delay(20);
    digitalWrite(BUILTIN_LED, HIGH);
    delay(20);
  }
1 Like

With an average “cali” around 24900 on my WeMos and mods to the libraries to include Espressif changes to deepSleep I am going to try for a 12000 second sleep (3h20m).

[3188] Connected to WiFi
[3188] IP: 192.168.10.172
[3188] 
    ___  __          __
   / _ )/ /_ _____  / /__
  / _  / / // / _ \/  '_/
 /____/_/\_, /_//_/_/\_\
        /___/ v0.4.8 on Arduino

[3194] Connecting to blynk-cloud.com:8442
[3384] Ready (ping: 98ms).
[3786] Time sync: OK
Current time: 19:22:48
Trigger time has already passed for today
Sleeping for maximum time
I'm going to Sleep for 12000 seconds

I’ll report back later to see if it manages to sleep for 3h40m

1 Like

:trophy:

Ran it twice and the 200m sleep was just 55m on both occasions.

The problem with the deepSleep function is that it doesn’t give any warning of invalid parameters and doesn’t even give the original 72m maximum when you request longer than whatever the new limit is.

Dropped it down to 180m to see what that comes up with.

@dandan with the version of deepSleep() that most people use it doesn’t handle the overflow of 32 bit numbers to 64 bit numbers. So in simple terms it works on a modulus 4295 seconds basis when you convert the microseconds back to seconds. So if it’s set at 4300 seconds the sleep after modulus (rollover) is just 5 seconds.

Espressif introduced 64 bit numbers for deepSleep back in May and it’s available by using their SDK 2.1.0.

After a lot of messing about I can now sleep for 12600s (3h 30m) rather than the old 1h 12m.

I also modified my version of the sketch to better handle the midnight rollover for extended sleep periods. It now sleeps the full 12600s if time to midnight plus midnight to trigger time is > 12600s. And maximum seconds from now until midnight plus time until trigger time after midnight if this is less than 12600s.

The new deepSleep() has the same inaccuracy as before so it will wake a little under 3% early. So you don’t get 12600s the actual clock time is around 12250s.

With trigger time set for 00:20:00 Serial Monitor now shows:

    [3365] Ready (ping: 80ms).
    [3767] Time sync: OK
    Current time: 21:01:06
    Trigger time has already passed for today
    Sleeping until after midnight
    RTC speed: 25090
    I'm going to Sleep for 11933 seconds
    I'm going to Sleep for 11933000 milliseconds (or X 1000 microseconds)

Note you can’t show the deepSleep microseconds directly in Serial Monitor because Serial.Print() doesn’t handle 64 bit numbers.

1 Like

Thank you for the hard work .
Can you post your last edited code … ? ( with “better midnight rollover” handling ) .
( or maybe you’ve already edited your post… :slight_smile:

Thanks again.

p.s.
Does the ESP32 handles deep sleep differently then esp8266 ?

The code I have will only work if your are using Espressif 2.1.0 SDK, which most Blynkers will not be.

If you want to stick to the maximum 72m deepSleep() I can probably mod my 3h30m sketch.

Dunno.

Hmmm
Well , since I plan on using my simple wemos d1 mini - I guess the default version of the SDK is the right one for me.

From what I understand, it can sleep much longer (years?), has a low power RTC and multiple wakeup options (internal and external)

1 Like