Quick question on Wifi.on()/WiFi.off() vs System.sleep(); in power-saving application

Hello,

I have a device that is battery powered and through testing it has became obvious I don’t have the battery life I desired. I have now decided to start turning off the WiFi module to see where that gets me. I have also considered System.sleep();. The code does need to continue running as it is an event counter. Once the desired interval has elapsed (in my case 3600000 millis), I would like it to go ahead and post the results. Here is the part of the code that does that part of the work.

if(currentMillis - previousMillis >= sendDelay)
    {
    Wifi.on();
    WiFi.connect();
    request.port = 80;
    request.hostname = "things.ubidots.com";
    request.path = "/api/v1.6/variables/"VARIABLE_ID"/values";
    request.body = "{\"value\":" + String(count) + "}";
    http.post(request, response, headers);
    request.path = "/api/v1.6/variables/"VARIABLE_ID2"/values";
    request.body = "{\"value\":" + String(soc) + "}";
    http.post(request, response, headers);
    previousMillis = currentMillis;
    count = 0;
    digitalWrite(Led, HIGH);
    delay(20);
    digitalWrite(Led, LOW);
    WiFi.off();
    }

I have already turned off the WiFi module prior to this being ran. Notice I have WiFi.on(); and then WiFi.connect();. This seems redundant and I’m not sure its necessary. Can you just use WiFi.connect();? Will this command wait until connection is established before it goes to the next line of code or do I need to put a delay(); there? I know I could probably use the WiFi.ready(); for that but wasn’t sure if that was necessary either.

Thanks in advance!

@brybrew, which SYSTEM_MODE are you running?

Using System.sleep(time) is the same as using WiFi.off() but with a timer. Using WiFi.connect() won't turn on the WiFi i believe so you still need WiFi.on(). As per the docs, WiFi.connect():

When this function returns, the device may not have an IP address on the LAN; use WiFi.ready() to determine the connection status.

You can use the waitUntil() command with WiFi.ready() after callng WiFi.connect(). :wink:

@peekay123 Thanks.

I am in AUTOMATIC mode.

I really don’t want to mess with a timer for the sleep so I will just use the WiFi.on/off commands.

So…

    WiFi.on();
    WiFi.connect();
    waitUntil(WiFi.ready);
    request.port = 80;
    request.hostname = "things.ubidots.com";
    request.path = "/api/v1.6/variables/"VARIABLE_ID"/values";
    request.body = "{\"value\":" + String(count) + "}";
    http.post(request, response, headers);
    request.path = "/api/v1.6/variables/"VARIABLE_ID2"/values";
    request.body = "{\"value\":" + String(soc) + "}";
    http.post(request, response, headers);
    previousMillis = currentMillis;
    count = 0;
    digitalWrite(Led, HIGH);
    delay(20);
    digitalWrite(Led, LOW);
    WiFi.off();

?

Looks good to me. I’ll try this here in a bit.

@brybrew, if you will not be using the Particle Cloud then you may want to consider using SEMI_AUTOMATIC or MANUAL modes. :grinning:

Thanks @peekay123. I have moved to MANUAL mode and made the changes mentioned above (and it works). I’ll charge up and see what kind of life we get now. It would appear it only takes about 15 seconds to turn the wifi module on and get through the posting of data so that should make a big difference.

@brybrew, sounds good! Please share your results with us when you can!

@brybrew @peekay123 I just used DeepSleep for 5 mins to wake up and send temp and humidity to a Mongo Database. That has extended battery times to months vs days.

But there is one condition that will still drain the battery in 1 day and that’s if the WiFi connection is down which causes the Photon to stay ON and constantly look for a WiFi connection before running the code and going back to sleep again.

@peekay123 What would you suggest for creating a sleep function that attempts to connect to WiFi but will go back to sleep after 30 or 60 seconds of not getting a successful WiFi connection? This way the battery would not be drained the whole time the WiFi connection is unavailable? This will be especially important in the low power solar harvesting setup.

@RWB, @brybrew can’t go to deep sleep but in your case, I would say use SYSTEM_MODE MANUAL and control the WiFi/Cloud directly. You can use the waitFor(WiFi.ready, time)) or waitFor(Particle.connected, time)) (ScruffR: Corrected typo) command to wait for a fixed amount of time for wifi to connect. Based on what the call returns, you can go back to sleep or proceed with the cloud connection (if required). Going back to sleep for 30 to 60 seconds may not be enough and you may want to increase that knowing you are in a wifi timeout condition.

1 Like

Hey @peekay123,

An update: My first code, the one that stayed connected full time, was getting me about 11hrs with the battery. It is a 1000mAh Li battery. After the changes to MANUAL mode and the WiFi.on, WiFi.connect, etc., I am now getting 25hrs. Much better but not to the 3 days I was needing. I am now planning to look into the loop itself and see if there is anything that could help. I’m thinking if I put an interrupt command in there, looking for the leading edge of my bubble (it’s a bubble counter if I hadn’t said so already) and counting those instead of just constantly cycling through that might help. If I could get to 36hrs, I could then just move up to the 2000mAh battery. If not, I’ll just get a long wire for it.

Thanks for your help so far.

Here is the code just in case you see something that could be killing the battery. I have a couple very small LEDs hooked up that blink every so often and then the photointerrupter. I know the photo gate is the biggest drain on power since the IR led is constantly on. Guess I might need a different way to count these bubbles!

SYSTEM_MODE(MANUAL);

#include "HttpClient/HttpClient.h"
#include "SparkFunMAX17043/SparkFunMAX17043.h"
#define VARIABLE_ID "variable_id"
#define VARIABLE_ID2 "variable_id2"
#define TOKEN "my_token"


int Gate = D5;
int Led = D4;
int Led2 = D2;
int gateState = 0;
int sendDelay = 3600000;
int count = 0;
double voltage = 0;
double soc = 0;
unsigned long previousMillis = 0;
HttpClient http;

http_header_t headers[] = {
      { "Content-Type", "application/json" },
      { "X-Auth-Token" , TOKEN },
    { NULL, NULL } 
};

http_request_t request;
http_response_t response;

void setup() {

  pinMode(Gate, INPUT);
  pinMode(Led, OUTPUT);
  pinMode(Led2, OUTPUT);
  Time.zone(-6);
  lipo.begin(); 
  lipo.quickStart();
  digitalWrite(Led, HIGH);
  delay(500);
  digitalWrite(Led, LOW);
  delay(200);
  digitalWrite(Led, HIGH);
  delay(500);
  digitalWrite(Led, LOW);
  delay(200);
  digitalWrite(Led, HIGH);
  delay(1000);
  digitalWrite(Led, LOW);
  delay(200);
 
}

void loop() {
 
  unsigned long currentMillis = millis();
  static byte prevState = 1;
  gateState = digitalRead(Gate);
  
  if(gateState != prevState) 
  {
    if(gateState == HIGH)
    {
    count ++;
    digitalWrite(Led2, HIGH);
    delay(20);
    digitalWrite(Led2, LOW);
    }
    prevState = gateState; 
  } 
  if(currentMillis - previousMillis >= sendDelay)
    {
    WiFi.on();
    WiFi.connect();
    soc = lipo.getSOC();
    waitUntil(WiFi.ready);
    request.port = 80;
    request.hostname = "things.ubidots.com";
    request.path = "/api/v1.6/variables/"VARIABLE_ID"/values";
    request.body = "{\"value\":" + String(count) + "}";
    http.post(request, response, headers);
    request.path = "/api/v1.6/variables/"VARIABLE_ID2"/values";
    request.body = "{\"value\":" + String(soc) + "}";
    http.post(request, response, headers);
    previousMillis = currentMillis;
    count = 0;
    digitalWrite(Led, HIGH);
    delay(20);
    digitalWrite(Led, LOW);
    WiFi.off();
    }
  delay(100);
}
1 Like

I thought the interrupt path was already a suggestion rather early in the other thread :wink:

Once the wake-on-pin-sleep gets fixed (hopefully with 0.4.8) you’ll definetly get more than just a few days out of your battery, given the bubble rate you suggested in the other thread.

Hey @ScruffR! You found me sneaking around over here, huh?? Yes, I’m working on that as well. I just got excited when I had this thing all put together and working and wanted to test it as-is. I was using the Google script thing but it was just so unreliable at gathering data. Sometimes it would just reset the counter and not pull the count. Had to move back to Ubidots and have the photon post. I like this method I think. Just need to work on the interrupt thing :smile:

2 Likes

@ScruffR if you don’t mind what is the current working status of the Wake-On-Sleep function on the Photon at the moment? Is it the exact same on the P1 modules also?

I do plan on using these feature in the near future.

This is still the current state for Photin/P0/P1

It’s milstoned for 0.4.8 to be fixed.
If you like you can have a look at the 0.4.8-rc1 tag for local building

@scruffR Thank you for the info and not telling me to search the forum for the answer :smile:

Currently I’m not doing any local building so I’ll try to wait for 0.4.8 to get this fixed, its a valuable feature. Certainly going to be needed on the Electron.

@peekay123 Hey I had to change some code in Node Red that I use to send Particle Publish events to my Mongo DB database so I figured now was a good time to add the code that will keep the Photon from running all day if there is no WiFi present.

Now I see you recommend to do the following but I need some more help getting this setup right.

1st your recommend I start the program off in SYSTEM_MODE MANUAL which is simple.

Then I will need to turn the WiFi on manually by using:

WiFi.on,
WiFi.connect, 

Again easy enough, but I need help with the next part where we can put the Photon back to sleep for 5 mins if there is no WiFi available. You recommend to use the waitFor() function to accomplish this.

waitFor(WiFi.connected(time)

How exactly does this function work though?

Like if I wanted to wait 60 seconds for the WiFi to connect I think I would just do this:

waitFor(WiFi.connected(60000);

I know how to use a If Statement but how does the above waitFor function dictate which code runs based on if it times out or not?

I either want to Particle.Publish or go to sleep depending on if the WiFi times out or not.

Any guidance is greatly appreciated :smiley:

@RWB, waitFor() is really a macro that essentially waits for a timed delay on a specified function. In your case (DISCLAIMER: I have not tried this personally yet), the syntax would be:

if (!waitFor(WiFi.connected, 60000)) {
... timeout...
}

I believe the function returns TRUE if the function returns TRUE or FALSE if a timeout occurs. :wink:

1 Like

@peekay123 Thanks for the info.

The calls for Wifi.connected caused compile errors since I think Particle.connected is what you wanted to use on the Photon.

Here is what ended up working for me running the Photon in SYSTEM_MODE(MANUAL);:

In the main loop I run this code to put the Photon into deep sleep for 5 mins if the Wifi does not connect to the Particle Cloud within 60 seconds. If WiFi does connect the code runs normally.

Particle.connect();

  if (!waitFor(Particle.connected, 60000)) {
      
    System.sleep(SLEEP_MODE_DEEP, 300);
} 

So now the Photon will not drain the battery anytime the Wifi / Cloud is not available and this drastically increases the run time when running off a battery pack / solar powered system :smiley:

1 Like

Sorry @RWB, but about this waitFor() issue it would actually be good to pull your socks up and investigate first.
There are docs for looking up most of the syntax, and if you get a compile error they usually do also tell what's wrong there. (Just look at the code line and notice there are more opening parentheses than closing!)
https://docs.particle.io/reference/firmware/photon/#-code-waituntil-code-

Granted, in the post suggesting waitFor() originally there was a typo - parentheses ) where it should have been a comma , - but this would have cleared up in no time, if you just went to the docs and researched what this acutally does before just copying into your own code.

@ScruffR I did pull up and look at the different functions in the Document section and it along with Paul’s help is what allowed me to figure out how to get it work.

The compile error was referring to Paul’s suggestion of trying out WiFi.connected which is not a Photon function I guess. So I looked over the Documents and saw that there is a Particle.connected that did the same thing as Wifi.connected did so I changed it and all was good.

I agree with you though. There is lots of good info and example code in the Documents and there would be a lot less questions asked if everybody looked for a answer to their question in there before reaching out for help on the forum :grinning:

1 Like

@RWB, @ScruffR, OMG!!! I can’t believe I wrote WiFi.connected()!!! Shows how long I’ve been around this firmware :smirk:

3 Likes