Go Down

Topic: Sleep mode for MKR1000 using RTCZero (Read 3648 times) previous topic - next topic

Uncle82

I am working on a project with MKR1000, that should acquire dht22 data every 15minutes and send message to thingspeak. Everything works fine, but the battery life doesn't go longer than 8 hours. So I tried to implement some sleep logic, starting from the example of RTCZero library (https://www.arduino.cc/en/Tutorial/SleepRTCAlarm). However it is not clear to me how the library can be used to wake up the board every 15 minutes. If I understood correctly, the alarm can wake the board when the rtc.setAlarmTime matches with the time of the RTC. So if I use rtc.MATCH_MMSS, where MM is 15 and SS is 00, the alarm will wake the board every first quarter of a hour and not on 30, 45 and 00 minutes. Is it correct?

Maybe this is very easy, but I am not expert of this topic.

thanks

a_guadalupi

Hi, you are on the right way, but with a trick. :)
You have to use the MATCH_MMSS but in the callback attached to the alarm you have to shift the alarm.

When the alarm is matched you have to use the setAlarmTime function in such a way:

Code: [Select]


void setup(){
  ....
  ....
  setAlarmTime(xx, 0, xx); //your starting time
  ...
  ...
}

void alarmMatch(){
  int alarmMinutes = rtc.getMinutes();
  alarmMinutes += 15;
  if (alarmMinutes >= 60){
    alarmMinutes -= 60;
  }

  setAlarmTime(rtc.getHours(), alarmMinutes, rtc.getSeconds());
}


Uncle82

Hi, you are on the right way, but with a trick. :)
You have to use the MATCH_MMSS but in the callback attached to the alarm you have to shift the alarm.

When the alarm is matched you have to use the setAlarmTime function in such a way:

Code: [Select]


void setup(){
  ....
  ....
  setAlarmTime(xx, 0, xx); //your starting time
  ...
  ...
}

void alarmMatch(){
  int alarmMinutes = rtc.getMinutes();
  alarmMinutes += 15;
  if (alarmMinutes >= 60){
    alarmMinutes -= 60;
  }

  setAlarmTime(rtc.getHours(), alarmMinutes, rtc.getSeconds());
}


Thanks for the trick. But there is something strange, it seems not executing more than one line in the alarmMatch void. For example I tried led blinking every minute and it does not switch it off. The board put led HIGH at first alarm and doesn not put it LOW after delay(500). Here is the example:

#include <RTCZero.h>

/* Create an rtc object */
RTCZero rtc;

/* Change these values to set the current initial time */
const byte seconds = 0;
const byte minutes = 05;
const byte hours = 12;

/* Change these values to set the current initial date */
const byte day = 12;
const byte month = 01;
const byte year = 17;

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  rtc.begin();

  rtc.setTime(hours, minutes, seconds);
  rtc.setDate(day, month, year);

  rtc.setAlarmTime(12, 06, 00);
  rtc.enableAlarm(rtc.MATCH_MMSS);

  rtc.attachInterrupt(alarmMatch);

  rtc.standbyMode();
}

void loop()
{
  rtc.standbyMode();    // Sleep until next alarm match
}

void alarmMatch()
{
  digitalWrite(LED_BUILTIN, HIGH);
  delay(500);
  digitalWrite(LED_BUILTIN, LOW);
  delay(500);
   int alarmMinutes = rtc.getMinutes();
  alarmMinutes += 1;
  if (alarmMinutes >= 60){
    alarmMinutes -= 60;
  }

  rtc.setAlarmTime(rtc.getHours(), alarmMinutes, rtc.getSeconds());
}

a_guadalupi

Hi, actually is a good practice to have an interrupt routine shorter as possible (with no delay!!!). So you should do something like this:

Code: [Select]

#include <RTCZero.h>

/* Create an rtc object */
RTCZero rtc;

/* Change these values to set the current initial time */
const byte seconds = 0;
const byte minutes = 5;
const byte hours = 12;

/* Change these values to set the current initial date */
const byte day = 12;
const byte month = 1;
const byte year = 17;

bool matched = false;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  rtc.begin();

  rtc.setTime(hours, minutes, seconds);
  rtc.setDate(day, month, year);

  rtc.setAlarmTime(12, 06, 00);
  rtc.enableAlarm(rtc.MATCH_MMSS);

  rtc.attachInterrupt(alarmMatch);

  rtc.standbyMode();
}

void loop() {
  if (matched) {
    matched = false;
    digitalWrite(LED_BUILTIN, HIGH);
    delay(500);
    digitalWrite(LED_BUILTIN, LOW);
    delay(500);

    digitalWrite(LED_BUILTIN, HIGH);
    delay(500);
    digitalWrite(LED_BUILTIN, LOW);
    delay(500);
    int alarmMinutes = rtc.getMinutes();
    alarmMinutes += 1;
    if (alarmMinutes >= 60) {
      alarmMinutes -= 60;
    }

    rtc.setAlarmTime(rtc.getHours(), alarmMinutes, rtc.getSeconds());
    rtc.standbyMode();    // Sleep until next alarm match
  }
}

void alarmMatch() {
  matched = true;
}



Uncle82

Great!!

Actually the delay was a problem in the alarmMatch. I tried your solution and it works fine. I have also included a call to a data log function (connect to the wifi and send T/RH to thingspeak) between the two led blink and it works perfectly.
Next step is to test the battery life with this upgrade. I will post results asap.

Thanks!

karliwalti

Hi

Would be interesting to hear about your findings.
I work on a very similar project (with a different temperature sensor) and found the battery life also not very useful.

I solved the wakeup very similar to what  @a_guadalup suggested;

Code: [Select]

int alarmminute = 15 ;  //start time for alarm
const int alarminterval = 15 ;  //period to take temp in minutes  


in loop:
    alarmminute= (alarmminute+alarminterval) % 60;
    rtc.setAlarmMinutes(alarmminute);
    rtc.standbyMode();


only setting AlarmMinutes will make sure you wake up at fixes intervals and not after a fixed interval.

For sending data to thingspeak you will need the wifi board. This uses much more power than the MKR1000 itself. make sure to to use WiFi.disconnect() before entering into standby mode.
Power consuption is still not perfect (I read one could go down to 2 mA), but I have not figured out how.


danistrigaro

Great!!

Actually the delay was a problem in the alarmMatch. I tried your solution and it works fine. I have also included a call to a data log function (connect to the wifi and send T/RH to thingspeak) between the two led blink and it works perfectly.
Next step is to test the battery life with this upgrade. I will post results asap.

Thanks!
Hi uncle82,
do you have any news about the test of the battery life with this solution?

Thanks
Daniele

CowboySkippy

Hello All,

I am measuring about 97mA after executing rtc.standbyMode() and I am measuring about 105mA during WiFi active.  I am using USB power (and not a battery).  Therefore, the POWER ON LED is illuminating continuously, and this is contributing to the current cosumption either case. According to the schematic, I believe this is DL3 and is likely adding about 10mA.

I tried to measure the current when using a battery (and not USB power).  I don't have the right jump wires to do so.  My two jump wires are two big for the female receptacle. 

I have run an experiment in which the system is in rtc.standbyMode() for 15min, then wakes for about 10s to read a value and push it to my Google sheet. My battery's rating is 1200mAh @ 3.7V. I was able to run the system for about 12.5 hours.  Using the battery rating and system specs, I expected a duration (1200mAh/(97mA - ~10mA)) = 13.79h.  So my observation closely matches the math and it gives me high confidence.

Nevertheless, I do not 'feel' that 97mA after executing rtc.standbyMode(), even with the POWER ON LED illuminated, is a sufficiently low power consumption. 
I was hoping for MUCH LOWER power consumption, maybe in the <10mA range...   >:(

I would love to hear from others. 
Are others also seeing similar power consumption?
Has anyone figured out a way to lower power consumption?

CowboySkippy

ballscrewbob

IIRC the firmware upgrade was supposed to fix some power issues.
You all did that right ?

It may not be the answer you were looking for but its the one I am giving based on either experience, educated guess, google or the fact that you gave nothing to go with in the first place so I used my wonky crystal ball.

CowboySkippy

Hello All,

On 20170818, one month ago, I measured 97mA after executing rtcStandbyMode() and 105mA during WiFi active.
I have made changes to my Arduino sketch and I now measure 1.25mA after executing rtcStandbyMode().  This is two orders of magnitude better that 97mA!
Below is pseudocode showing my changes:

Code: [Select]
void loop(){

  // if (myRTCAlarmExpired)
  {
    WiFi.noLowPowerMode();
    WiFi.begin(ssid,pass);
    delay(9000);
    // do stuff, such as read a sensor, post to PushingBox, etc....
    // set the rtc Alarm for the next interval...
    WiFi.disconnent(); // This is the line of code that dropped my current draw from 97mA to 1.25mA !!!
    WiFi.end();

  }

  rtc.standbyMode();
}


I am using the following library versions:
  • WiFi Built-In by Arduino Version 1.2.7 Installed
  • WiFi101 by Arduino Version 0.14.3 Installed


I confirm my MKR1000 ran 16 days, 19 hours and 8 minutes with a fully charged 1200mAh battery.
The average current draw, remember, is > 1.25mA because the circuit is drawing ~100mA when WiFi is active and transmitting data. I am very pleased that I am only drawing 1.25mA (vs ~100mA). 

I am very pleased with my current performance.
But, I can optimize further:
  • Collect several sensor samples throughout the hour or day and enable Wifi once an hour or day and post them to my Google Sheet.
  • Minimize the about of time that WiFi is enabled.  I am current looping several seconds with a generous safety margin and can probably lower that number.  The current draw is maximal while WiFi is enabled.


Thanks for the feedback!
CowboySkippy

Go Up