Help extend my battery life

I’m using the Photon to drive a web application I have. Basically I want to push a button and have the code on the Photon call a URL on my server which does something.

In my first test, I left the WiFi on and found that the battery died after a few hours (less than a day not sure exactly). So, I figured out how to use System.sleep and use the button press to wake it up. That’s getting me 3 days of power. Better, but not where I want to be. I’d like to get it to over a week if not longer.

What if I connect my button to the WKP pin? Is there a circuit diagram for how to wire the button there (do I need a resister and if so, how)?

Here is the current code that I use:

#include "application.h"
#include "HttpClient.h"
// Our button
#define button D2

// Dont be connecting to the cloud
SYSTEM_MODE(MANUAL);
// HTTP Request objects
HttpClient http;
http_header_t headers[] = {
    { "Accept", "*/*" },
    { NULL, NULL }
};
http_request_t request;
http_response_t response;
// Our mode. Start in startup mode
int startup = 1;
// Nothing to setup
void setup() {
}
void loop() {
    // Don't let our loop get called during startup.
    // Only after button pressed
    if ( !startup ) {
    // Start wifi up and connect to the network
        WiFi.on();
        WiFi.connect();
        while (!WiFi.ready()) {
            delay( 100 );
        }
        // Steal LED and let user know we're making the http call
        RGB.control( true );
        RGB.color( 0,0,255 ); // blue - mark that
        // Make http call
        request.hostname = "myhost.example.com";
        request.port = 80;
        request.path = "/myurl";
        http.get( request, response, headers );
        // Let user know its done
        RGB.color( 0,255,0 );
        // Force a delay to ensure we don't execute the action constantly
        delay(2000);
        // Get ready for the next loop to do it over again
        RGB.control( false );
    }
    // Make sure we're not in startup mode for the next loop iteration
    startup = 0;
    // Kill wifi again
    WiFi.off();
    // move the device into low power mode until button pressed
    System.sleep( button, FALLING );
}

How large is the battery your using?

If you use deep sleep the system should stay running off the battery for weeks to months if all you want it to do is sleep until the button is pressed. I’m not sure how to code that correctly but I do know deep sleep drops the current consumption down to micro amps.

What about deepsleep instead of just sleep.
Sleep will leave the photon running and just switch off the wifi off , which if I remember right the docs say 80 milli amps, with deepsleep it’s down to microamps .

It’s 2000mAh

@peter_a ,

Looking at the reference guide, I don’t see a way to specify Deep sleep & be able to bring it back by pushing the button. I do like the idea of using Deep Sleep… Just need to solve 2 problems with it…

First, how do I connect to the WKP pin without frying it…

Second, If I power up the device for the first time (or after power fails) it should not call my API. Only when I press the button (to wake it from sleep) should it call the API. Since deep sleep doesn’t save state of variables (like my state variable) and treats it the same as powering on I don’t know how to differentiate the two

I think you just pull the WKP pin high 5v or less to wake up the Photon from deep sleep.

So if you put the Photon into deep sleep and use the button to trigger the WKP pin every time its pushed you could just have your code run every time the button is pushed only assuming that all you want to do is send a notification over the web every time the button is pushed.

Even in Sleep mode the Photon consumes 30-38mA with a 2000mAh battery you should be seeing 2000 / 38 = 52 hours of run time. In Deep Sleep you should be seeing months of run time if all you need is for the Photon to wake up when the button has been pressed.

@RWB - How do I use a pull up in this case? I thought pull ups did the opposite. When a button is pressed the state goes from high to low (https://learn.sparkfun.com/tutorials/pull-up-resistors). So for this, do I just connect the button to the 3v3 pin and the other end to the WKP pin?

So, it will be like the system is booting up whenever I press the button. Is there any way to have the photon not call my API during the initial loop (i.e. when setup and loop are run the first time the device sees power before it goes to sleep the first time)?

I would just run power from the + of your battery to one side of the button and run the other pin on the button to the WKP pin which will pull the pin high up to the 3-3.7v battery voltage at least which should be enough.

When you push the button the Photon will wake and run what ever code you give it. Then at the end of your task put it back into Deep Sleep.

30 - 38ma , the docs says :-

Typical current consumption is 80mA with a 5V input. Deep sleep quiescent current is 160uA. When powering the Photon from the USB connector,

Correct a pullup resistor "holds" the state high untill something with less resistance pulls it low, for example a button tied to ground.
A similar pulldown resistor is used here instead to keep the pin low untill the button is activated.

So you would have a 10K ohm resistor from Dx to GND, and a button from Dx to HIGH (3.3v or 5v since photon is 5v tolerant on digital pins).

And your program would look something like

Particle.publish("myButtonEvent", NULL, 60, PRIVATE);
//May need some delay here to make sure the event has been sent
System.sleep(D3,CHANGE); 

But there is a issue at the moment with wakeup on pin change being unreliable.

So, I think I solved the problems I was having…

@RWB seemed to be right… I can simply connect the VIN pin to the button to the WKP pin. According to the docs, VIN is as close to the power source as I can get (I’m using the Sparkfun battery shield so I don’t have direct access to the + terminal of the battery).

The next issue I had was around identifying when I’m hitting the loop during initialization (before I hit the deep sleep for the first time) and when I hit the loop after I wake the photon on by pressing the button. To solve that I am using both sides of the battery. The left side goes from VIN - button - WKP. The right side goes from GRD - button - D6. When I supply power to the Photon, D6 is in the LOW state and I have a digitalRead checking the state and skipping my loop. When I press (and hold) the button D6 goes HIGH. Once I hit the loop it’ll see the high state and let my code run… So, pulling out all the Wifi and API stuff and just using the LED, here is what it looks like:

#include "application.h"

// Dont be connecting to the cloud
SYSTEM_MODE(MANUAL);

// Sleep only until button press, so set a timeout so long as to not be
// relevent
#define forever 3153600000

void setup() {
    pinMode( D7, OUTPUT );
    pinMode( D6, INPUT_PULLDOWN );
}

void loop() {
    if ( digitalRead( D6 ) == HIGH ) {
      digitalWrite( D7, HIGH );
      delay( 5000 );
    }
    System.sleep( SLEEP_MODE_DEEP, forever );
}

Actually… I found this diagram on the internet: http://elinux.org/images/4/4b/Mpushbuttonworking.jpg . I believe that is the button I have from Sparkfun. I assumed that the button is a two pole button meaning that the left side is independent of the right side. Can someone validate that I’m doing the right thing using the VIN and GRD pins the way I am?

Quick update: it looks like I am not using GRD at all… So it looks like the net result is that I’m going from VIN -> button -> D6 and VIN-> button -> WKP.

Yea that button is not a dual pole switch so if your connecting the Battery + to one side and the Battery - to the other side then your shorting out the battery when you push the button or your instantly shorting out the battery if the 2 leads your connecting the battery to are on connected legs.

The deep sleep is just like a ON / OFF switch for the system. From my understanding when the Photon wakes from a Deep Sleep it’s basically the same as if you just turned it on. Your starting fresh when waking out of deep sleep.

So if the button is pressed the WKP pin is triggered, the Photon wakes up and your code calls a URL on your server which does something. Then you put the Photon back into Deep Sleep forever.

Is there any reason that wouldn’t work?

The API call starts my car remotely. I need to ensure that when I plug the Photon in to charge I don’t inadvertently start my car at the same time.

I’m not a electrical expert by any means… I understand the reason for a Pulldown or Pullup, but don’t understand high and low states and what that means. According to: https://learn.sparkfun.com/tutorials/pull-up-resistors I think its fine but my fear is that by using the button to connect the VIN pin to D6 instead of GRD while using INPUT_PULLDOWN I’m going to fry something.

@skibumatbu

Pulling the pin High just means that its above 2-2.5v when the pin state is read. At least that's how I understand it.

Pulling a Pin High or Low keeps the voltage on that pin held to 0 or 5 volts instead of having the pin not connected to anything AKA a Floating Pin. It's best to pull the pin high or low so you don't get any floating voltage above that 2-2.5v which could be considered High.

So your only issue is that you don't want the code to call your URL when you first plug in the Photon for the first time. If that's the case then here is one simple solution.

Use one more button and connected it to Digital pin 2 and in your code read its state on startup. If Digital Pin 2 if High on startup then don't call your URL which starts your car but only go into deep sleep. Connect this button to Vin also so it pulls Digital Pin 2 up to battery voltage when the button is pressed.

So just use a use a "If" statement like this:

void loop() {
if ( digitalRead( D2 ) == HIGH ) {
System.sleep( SLEEP_MODE_DEEP, forever ) ;
}

Place Code here to call your URL that starts your car ;
System.sleep( SLEEP_MODE_DEEP, forever );
}

I'm no expert but I think that should work.

Thanks @RWB. I think that’s pretty much what I have in the code I posted a bit further back (though I’m using a PULLDOWN even though the button isn’t connected to GRD). But, its actually working… If I push the button but don’t hold it then it powers up and goes back to sleep. If I push the button and hold it, it powers up and runs my API call.

Sweet.

So the battery should work for months now since the deep sleep is running all the time except when you push the button.

Are you triggering a remote starter that’s already installed in your car now?