Sleep mode questions

Thank you that is an good alternative. But i am trying not to add any further hardware.

Hello particle community

I need a little bit help. I am using the System.sleep(uint16_t wakeUpPin, uint16_t edgeTriggerMode, long seconds) in order to cycle my photon in and out of stop mode. Now i understand that the photon’s processing will stop for the specified “long seconds”, if an external signal does not disturb it before hand, and then wake and continue running code from the point it stopped. Do timers still run in the back ground even when the photon is ‘stopped’ (during the period of long seconds)? The reason i am asking is because, for example, i would like to increment a counter periodically every 3 seconds, which is the frequency that i have set the counter’s function to run at using blynk’s timer function timer1.setInterval(3000L, CounterFunction). Now this is the general idea that i have applied to specific application. My specific application requires that i saved data to an SD card, with a time stamp. Since the medium of communication between the photon is bluetooth (with builtin photon wifi switched off), i request the current date and time through the use of my project’s Blynk interface app. So basically my hardware receives unix time from blynk over bluetooth communication and than, using particle’s pre-built time and date converter functions, i am able to produce a time stamp of the current time and date. However, since my app will not constantly be connected to the hardware (it will only definitely be connected to the hardware for the initial setup) i am required to find a way to increment the time stamp and maintain the time]ings when the hardware is disconnected from the app (e.g. if i move away from the hardware so that bluetooth comms in not possible). Now i used a counter and some elementary code to detect when the hardware app and hardware are disconnected and when this happens the time stamp manually incremented by 3 in order to maintain the time stamp. I have tested this and found a perfect correlation between the timestamp produced by this method and matched it to the timestamp produced through unix conversion. I was able to verify this by allowing my project to run for a few hours and then connecting to the app, allowing the app to immediately take over the value of the timestamp and saw that the difference between the artificially incremented time stamps as well and those that followed it lined up and measured 3 seconds apart. The problem however arises when i introduce the stop mode. Logically, witha 1 second stop mode i should simply add the additional second to my increments and the timestamp correlation should be upheld. However this is not the case, my timestamp is always a few minutes ahead of real time. I cannot understand why, other then to assume that maybe the timer controlling the execution of the counter every 3 seconds is not be stopped? Here is the code i am using:

void setup() {
    
    Serial.begin(9600);
    Serial1.begin(115200);                                  //Initialise serial communication on the TX and RX pins 
    Blynk.begin(Serial1,auth);                              //Connect the Blynk application to the photon via bluetooth
    pinMode(WindspeedPin,INPUT_PULLUP);                     //Specifies the Digital pin as an input 
    pinMode(DetectPin1, INPUT_PULLDOWN);                    //Set analog pin A7 as input with internal pull down resistor
    pinMode(DetectPin2, INPUT_PULLUP);                      //Set analog pin A6 as input with internal pull up resistor
    pinMode(RainSensorPin,INPUT_PULLDOWN);                  //Set analog pin D5 as input with internal pull down resistor
    pinMode(RainDetectorPin,INPUT_PULLDOWN);                //Set analog pin D6 as input with internal pull down resistor
 
    Blynk.notify("Weather Station: Online"); 
    Serial.println("Weather Station: Online");
    delay(1000);
    
    
    timer1.setInterval(3000L, AllFunctions);                //Set timer1 to periodically send data to Blynk every 3 seconds 
      
}

void loop() {
    
    Blynk.run();                                            //Maintain connection to Blynk 
    timer1.run();                                           //Keep timer1 running
     
}


void AllFunctions(){
     
    Windsensor();
    GetVEML7700SensorData();
    RainSensor();
    GetBME280SensorData();                                  //Moved it to give it enough time to intialise
    BlynkComms();                                           //Called last to allow sensors to make measurements before they are transmitted to the mobile app
    DisplayOnSerialMonitor();                          //Displays variables on the serial monitor
    
    SaveToSDCard();                                       //Checks to see if the data logging to SD card is activated
                                 
    TimeStampCounter=3; // Time increments by 3 when power save is not invoked
        
        if(PowerSave1==1 & PowerSave2==1){                  //Power saving mode activated when both the rain sensor and the windsensor are disconnected from the station
            
            Blynk.syncVirtual(V14);                 
            System.sleep(DetectPin1,RISING,1);     
            TimeStampCounter=3.739;          // Instead of 4 i am trying to workout by trail and error what value i should use
            
          
            
        }
            
        
        Counter=0;
        
    }
   
}
// The data logging to SD card code
void SaveToSDCard(){
      	    
	    if (digitalRead(DetectPin2)==HIGH){  //Checks if the SD card is connected                     
            
              
            requestTime();  //Request unix time from Blynk
    
            
            
	        if(CheckSDCard==1){// Check if the SD is present
	        
	            printToCard.println("\nNew batch of weather data,Date,Time,Temperature(C),Humidity(%),Pressure(hPa),Windspeed(km/h),Wind direction,Light intensity(klx),Rain fall(mm/hr)");             //This will run once only when the SD is first activated
	            Serial.println("\nNew batch of weather data");
	            
	            if(!printToCard.getLastBeginResult()){ //To verify is data is being stored onto the SD card
	                
	               Blynk.notify("SD card initializing, please wait...");
	               Serial.println("SD card initializing, please wait...");
	               CheckSDCard=1;
	                
	            }
	            else{
	                
	                Blynk.notify("Save data to SD card: Enabled");             
	                Serial.println("Save data to SD card: Enabled");
	                CheckSDCard=0;
	            
	            }
	        }

	        else if(CheckSDCard==0){
                
                Serial.printlnf("The value of t0=%f before", t0);
                Serial.printlnf("The value of t=%f before", t);
                if(t==t0){
                    
                    t=t+TimeStampCounter;
                    t0=t;
                    Serial.printlnf("Since no connection to blynk the t=t+TimeStampCounter executed. TimeStampCounter=%f", TimeStampCounter);
                        
                }
                else{ 
                    
                    t0=t;
                    Serial.println("The t0=t executed");
                
                }
                
                Serial.printlnf("The value of t0=%f after", t0);
                Serial.printlnf("The value of t=%f after", t);
                Seconds=Time.second(t);
                Minutes=Time.minute(t);
                Hours=Time.hour(t);
                Day=Time.day(t);
                //WeekdayNumber=Time.weekday(t);
                Month=Time.month(t);
                Year=Time.year(t);
                Serial.printlnf("%i/%i/%i  %i:%i:%i", Day, Month, Year, Hours, Minutes, Seconds);
    
    
                //Serial.printlnf("Date:  %i-%i-%i \nTime: %i:%i:%i ", Day, Month, Year, Hours, Minutes, Seconds);
                //Serial.print("Weekday: ");
                //Serial.print(Weekday);
                //Serial.println("");
            	            
	            printToCard.printlnf(" ,%i/%i/%i,%i:%i:%i,%0.2f,%0.2f,%0.2f,%0.2f,%s,%0.2f,%0.2f,%d", Day, Month, Year, Hours, Minutes, Seconds,Temperature, Humidity, Pressure, Speed, Direction, LightIntensity, RainFall);
                //Serial.printlnf("%i/%i/%i  %i:%i:%i  Temperature: %0.2f C, Humidity: %0.2f %, Pressure: %0.2f hPa, Windspeed: %0.2f km/h, Wind direction: %s, Light intensity: %0.2f klx, Rain fall: %0.2f mm, counter2: %d", Day, Month, Year, Hours, Minutes, Seconds,Temperature, Humidity, Pressure, Speed, Direction, LightIntensity, RainFall);

}
 

the variables i have used: TimeStampCounter, t and t0 have been declared as doubles since the integer value 4 is too large an increment and integer 3 is too small when stop mode is activated. Please advise.

No

However the Photon features a RTC which will keep updating the time and when the device gets woken (by said RTC) you will find that the time returned by the Time object will be pretty close to what it is supposed to be.

Another word of caution, since the RTC has only a 1 second resolution your System.sleep(DetectPin1,RISING,1) will usually not sleep for 1 second exact but only for the rest of the running second in which you are sending the device to sleep.

BTW, this is probably the wrong "AND" operator

This should probably not be the binary AND but the logical

if(PowerSave1==1 && PowerSave2==1){

While in this particular case the result will be the same, for other checks you'd probably get confusing results :wink:

2 Likes

Hello ScruffR. Thank you for your reply.

However the Photon features a RTC which will keep updating the time and when the device gets woken (by said RTC) you will find that the time returned by the Time object will be pretty close to what it is supposed to be.

What do you mean by this? Are you talking about the accuracy in terms of switching the Photon "on" and "off" stop mode ? If not what 'time returned by RTC' do you mean?

... will usually not sleep for 1 second exact but only for the rest of the running second in which you are sending the device to sleep.

What do you mean by this? If my stop mode is set for 1 second of sleep are you saying my device will sleep for less than 1 second? Is there a way to determine how long it will be in stop mode for? I am trying by trail and error: I started reducing the value of 4 to 3.9 3.8 etc to see which value comes close but what i am noticing is that as the battery powering my project depreciates the results of my values achieve different results i.e. when i use 3.737 as the TimeStampCounter and the voltage is 3.9V i get a deviation of 80 seconds after an hour of manual incrementation, however when i test the same TimeStampCounter value and the voltage is 3.7V the deviation becomes less. This problem is only prevalent when i introduce the sleep mode. When the sleep mode is not invoked and i manually increment the time by 3, regardless of the voltage level, there is no observable deviation after an hour. This method is not proving effective when the stop mode is invoked though. Is there a better and more reliable method i can use to improve accuracy of the time obtained when stop mode is invoked?

I could set the RTC time using the unix time obtained from blynk using setTime() but is there a way to then request the time incremented by the RTC and use this incremented unix timestamp to convert to real time?

While in this particular case the result will be the same, for other checks you’d probably get confusing results :wink:

Thanks!:face_with_hand_over_mouth:

The STM32 features a Real Time Clock which will be updating the time as long it is powered - even in deep sleep. And that same RTC is also used for the timing of the wake. When you set the device to wake in 10 seconds the system calculates what real time that would be and sets a wake schedule for that time.
So when the time of the RTC (e.g. set via the cloud or via Time.setTime() is correct before going to sleep it will still be correct after wake (maybe with ~1sec drift over a day).
e.g. when you send your device to sleep for 10 minutes at 7/5/2019 8:00:00pm immediately after (timed) wake check Time.local() you will get 7/5/2019 8:10:00 pm (ignoring the reconnect latency for illustrational purposes - e.g. with SYSTEM_THREAD(ENABLED)).

Yes, that's what I'd suspect for above reason.

With external timing device (e.g. an oscilloscope)

Depends on the kind of precision you are aiming for.

Are you not using the Particle cloud? The time provided by that is at least of the same quality and it's the "native" time base for the Time object which will be automatically set on with each new cloud connect.

Of course

  int timeBeforeSleep = Time.now();
  System.sleep(DetectPin1, RISING, 100, SLEEP_NETWORK_STANDBY);
  int timeAfterSleep = Time.now();
  Serial.printlnf("Slept for %d seconds", timeAfterSleep - timeBeforeSleep);

You keep mentioning UNIX timestamp as if it was something special. The Time object uses just that, so we can just call it time :wink:

I also don't see the benefit of using Blynk Timers instead of Particle's Software Timers.
However, with either timer I'd not rely on the 3000ms of the timer callbacks to be precise. If precision was important I'd take a snapshot of the last call (e.g. millis()) and calculate the difference between the current and the last call to account for any timer latency.

1 Like

The STM32 features a Real Time Clock which will be updating the time as long it is powered - even in deep sleep. And that same RTC is also used for the timing of the wake. When you set the device to wake in 10 seconds the system calculates what real time that would be and sets a wake schedule for that time.
So when the time of the RTC (e.g. set via the cloud or via Time.setTime() is correct before going to sleep it will still be correct after wake (maybe with ~1sec drift over a day).
e.g. when you send your device to sleep for 10 minutes at 7/5/2019 8:00:00pm immediately after (timed) wake check Time.local() you will get 7/5/2019 8:10:00 pm (ignoring the reconnect latency for illustrational purposes - e.g. with SYSTEM_THREAD(ENABLED) ).

Okay thanks i will play around with this.

A 1 second drift after a day is more than adequate precision for my application.

No i am not using the cloud, as i mentioned in the previous message, my particular project requires bluetooth communication only and i have my switched off my photon's Wi-Fi.

Thank you! this is most helpful.

I am trying to be as specific as possible to avoid any confusing.

Okay thanks, i used a similar method to determine how long my code took to run before the it restarted the cycle.
Thanks alot ScruffR, i think this might solve my problem

Hi there, I see in the Docs for the OS API there is a new way of sleeping from version 1.5.0. Has anyone got any examples of using this method, I cannot get it to work. The documentation is here:
https://docs.particle.io/reference/device-os/firmware/photon/#sleep-sleep-

I’m assuming the top three lines I enter at the top of my code

SystemSleepConfiguration config;
config.mode(SystemSleepMode::STOP)
      .gpio(D2, RISING);

and when I want to sleep I run

SystemSleepResult result = System.sleep(config);

However when I try compiling this I get the following error:

toothbrush_timer.ino:2:1: 'config' does not name a type

Can anyone give me some guidance on how to move forward.
Thanks.

@keithellis,

Sure, there are just a few steps:

  1. Initialize the API - In the program’s header
SystemSleepConfiguration config;                    // Initialize the Sleep 2.0 API 
  1. Set the configuration for Sleep - In your sketch - setup or loop
    config.mode(SystemSleepMode::STOP)                                          // Could use HIBERNATE here but then would only be awoken by interrupt as the RTC is not connected to a GPIO pin
      .gpio(userSwitch,CHANGE)
      .duration(testDurationSeconds * 1000)
      .network(NETWORK_INTERFACE_CELLULAR)
      .flag(SystemSleepFlag::WAIT_CLOUD);
  1. Call the Sleep API:
System.sleep(config);
  1. Optional - Figure out what woke the device from sleep
SystemSleepResult result = System.sleep(config);

Hope that helps.

Chip

4 Likes

That’s brilliant, all working now. Thank you.