Strategies for better battery management

It would be great if there was a blog post about how to do better battery management for the Imp.

I recently made a device that connected to a server every four hours, turned a servo then went into deep sleep until the next four hour period was up. I was running it on four AA batteries and expected it would last a while but in actuality lasted three weeks. Have no idea about power management, and need to learn, but blog post about it would be super handy.

Would love to see the blog used more in this way. Yeah I know about the Wiki but I think featured posts about certain key subjects would be great.

Thanks!

We should have more tutorials, yes… things are being worked on!

I suspect the problem with the servo-based device is that the servo was being powered all the time - and servos tend not to be very low power, even when they’re not moving. Adding circuitry to cut power to the servo when the imp is asleep would likely take that out to years on 4xAA; the Hannah board has this circuit on it for this very reason :slight_smile:

We haven’t quite decided how we want to use our blog yet… but we do know that we want to keep it accessible and keep deeply technical articles off of it…

That said, we are trying to find ways of communicating this kind of information to our developer community and would love your feedback about good ways to do this…

Would a separate developer blog be useful?

  • Would anyone be interested in contributing articles to it?
    Would having this information on the wiki be enough?
    Would you be into an email every month or two with more in depth technical articles?

I love any initiative for creating whatever documentation about the imp, squirrel, programming tricks, code snippets and hardware design.
And a blog about experiences, ideas etc, yes, great!
Now you have to search so much for any relevant information and if you find it, you have to have a college degree to understand.
Current Squirrel docs have been written by aliens, in their own language…

Thanks Hugo - makes sense now though I suspected that’s what was happening!

A developer blog would be great. And yes, a 101 on Squirrel would be be appreciated by many I suspect. One of the best pages I found on Squirrel was this one: http://forum.iv-multiplayer.com/index.php?topic=898.0

So, back to the original question… Battery management. I, too, am looking for more information on how to maximize an Imp connected to, say, a LiPo battery. I have a project that has two Imps that each have ambient light sensors on them which are read via the ADC. I have a 3.7V 2,000 mAh LiPo powering each board. They each need to report the ADC value back to a Node.js server. I have imp.setpowersave( true ) and I fire the read every two seconds with imp.wakeup( 2, sendADCValue ). Is that as maximal as I can get, aside from waiting longer between reads? Thanks in advance for any input!

Depends on how urgently you need the data; if you are just collecting data, or it’s only important you send it if it changed by a certain amount, then your best bet is to turn wifi off and use imp.deepsleepfor() to sleep/wake without turning wifi on.

If the buffer is full or the “send now” condition is met, you can turn on wifi and send the accumulated data, then fall back into the shallow sleep cycle.

imp.deepsleepfor() makes more sense for what I’m doing. Thanks!

Can the April board be updated to use a lower power regulator? The imp can go to 6uA, but the regulator draws 20-25uA. Small, but many times what the imp consumes.

Was this the lowest power regulator you could find at the time or was it a cost issue? (just curious)

The DCDC used on April was a reasonable trade off on cost and input voltage range. There are many DCDCs with lower Iq, but not generally with a 16v input range.

eg, this part is 3.5uA and similar spec to the TPS62172… just 3x the cost:

http://www.linear.com/product/LTC3621

I can’t get nv to store values in deep sleep. I see the log say that the device is booting every time it wakes, which appears to mean that the nv is wiped. As described above, I’m trying to send data to a server ONLY if a threshold has been met. either 2,000 negatively or positively, on the ADC. But, in order to know the last value, I need to be able to store it between deep sleeps. I’m trying NOT to call a server and this wake up the WiFi if I don’t have to. Perhaps I’m missing something?Suggestions?

SAM, check this out. It works:
http://devwiki.electricimp.com/doku.php?id=electricimpapi:imp:deepsleepfor

…and to add to this, if you see the wakereason “new squirrel” then this generally means your code has crashed with a runtime error when disconnected from wifi. These type of problems are a real pain to debug - you should check all code paths when connected first.

The next release, if there is a runtime error when wifi is off, will connect and report the error and line number before re-loading the squirrel, which helps immensely…

Well, I’m still not getting the results I’d like to, so here’s my code (which I’m assuming at this point is flawed):

`
const LIGHT_CHANGE_THRESHOLD = 1000;
local sensorOutput = OutputPort( “JSON Sensor Output”, “string” );

function readLighting() {

local adcValue = hardware.pin9.read();

if( math.abs( nv.lastValue - adcValue ) > LIGHT_CHANGE_THRESHOLD ) {
    local json = {
        impid = hardware.getimpeeid(),
        voltage = hardware.voltage(),
        signal = imp.rssi(), 
        light = adcValue,
        time = hardware.millis()
    };
    // this will wake WiFi, in theory?
    sensorOutput.set( json );
    // stash this new value as the last one read for next time around
    nv.lastValue = adcValue;
}

// schedule next read 5 seconds from now and turn off WiFi?
imp.deepsleepfor( 5 );

}

server.log( “Light sensing started” );
hardware.pin9.configure( ANALOG_IN );
imp.configure( “iPotti Number 2 Light Sensor”, [], [sensorOutput] );
imp.setpowersave( true );

if( !( (“nv” in getroottable()) && (“lastValue” in nv) ) ) {
nv <- { lastValue = 0 };
}

imp.onidle( readLighting );
`

I’m not convinced the two Imps are deep sleeping because I’m seeing log output every 5 seconds. As I think about it (writing this), is the WiFi waking up because I’m logging (to the server)? That would be very dumb of me to miss. :stuck_out_tongue:

These forums are fantastic, BTW. Kudos to you, Hugo and your team, for a great device and support for it. Thanks, too, Impensor. I’d read that article on deepsleepfor() but for whatever reason, it wasn’t working for me in the context of my code. The example by itself works as advertised, of course.

Also, looking at the code above, even when I comment our all server.log() calls, I see this in the log every 5 seconds…

2013-09-10 13:05:36 UTC+7: [Status] Device booting 2013-09-10 13:05:36 UTC+7: [Status] Device configured to be "iPotti Number 2 Light Sensor"

…which makes be think the WiFi is turning on every time the sleep is finished.

Also, on the Imps I see a red LED blink (short), a green LED blink (short), then a long delay (seconds), and it repeats. I didn’t time it, but it could be the 5 seconds between in my sleep call. I can’t find a matching pattern in the LED table for the combination of red and green like I’m seeing.

Wifi is brought up the first time it’s required. Some things that require it include server.log and imp.configure.

When you’re doing low power stuff, you actually want to either not call imp.configure, or call it right before you actually want to turn on wifi.

The LED pattern you described sounds like what you think it is. The imp waking up, coming online, sleeping for 5 seconds, and then repeating.

Thanks, bi. Glad I’m on the right track as far as understanding… I think.

The examples for deepsleep are sparse. I haven’t seen a variety of examples on the subject, so I’m flying a bit blind. The docs aren’t always as deep as I’d prefer, but I’m slowly building on experimentation. However, you said something very interesting about imp.configure and maybe I don’t understand some of the basics as well as I thought I did: How can I do what I’m doing without calling imp.configure when imp.configure is required?

Must my Imp devices direct all of their output through the cloud or am I missing something really simple? I’m not real thrilled that I have to go through the cloud to post to a REST service somewhere other than the cloud. It looks like I’m doing two calls to do what one call could do. Imp is on WiFi, my REST service is on the web, ergo the Imp should be able to open an HTTP connection directly to the REST service, no? Ideally, I’d like the Imps in my project to connect via http directly to my Node.js web service without any intermediate calls. Perhaps I’m missing a vital step in here somewhere. This is all very exciting and confusing at the same time.

Revised code. Is this legit? Will this work? I’m reluctant to hit Save. :slight_smile:

`
const LIGHT_CHANGE_THRESHOLD = 1000;
local sensorOutput = OutputPort( “JSON Sensor Output”, “string” );

function readLighting() {

local adcValue = hardware.pin9.read();

if( math.abs( nv.lastValue - adcValue ) > LIGHT_CHANGE_THRESHOLD ) {
    local json = {
        impid = hardware.getimpeeid(),
        voltage = hardware.voltage(),
        signal = imp.rssi(), 
        light = adcValue,
        time = hardware.millis()
    };
    // this will wake WiFi, in theory?
    sensorOutput.set( json );
    // stash this new value as the last one read for next time around?
    nv.lastValue = adcValue;
}

imp.configure( "iPotti Number 2 Light Sensor", [], [sensorOutput] );
imp.setpowersave( true );

if( !( ("nv" in getroottable()) && ("lastValue" in nv) ) ) {
    nv <- { lastValue = 0 };
}

// schedule next read 5 seconds from now and turn off WiFi
imp.deepsleepfor( 5 );

}

hardware.pin9.configure( ANALOG_IN );

imp.onidle( readLighting );
`

Yes that should work.

Although, ideally you should move away from Output ports, and start using agents (agents may even remove the need for your node.js server). Agents make passing information back and forth (between the imp and the cloud, as well as the cloud and external web services) a lot simpler.

Using agents, you don’t need to configure your imp to have an output port, as you would use agent.send() instead. It would look something like this:

Device Code
`const LIGHT_CHANGE_THRESHOLD = 1000;

function readLighting() {
local adcValue = hardware.pin9.read();
if( math.abs( nv.lastValue - adcValue ) > LIGHT_CHANGE_THRESHOLD ) {
local json = {
impid = hardware.getimpeeid(),
voltage = hardware.voltage(),
signal = imp.rssi(),
light = adcValue,
time = hardware.millis()
};
agent.send(“lightChanged”, json);
nv.lastValue = adcValue;
}
// schedule next read 5 seconds from now and turn off WiFi?
imp.deepsleepfor( 5 );
}

hardware.pin9.configure( ANALOG_IN );
imp.setpowersave( true );

if( !( (“nv” in getroottable()) && (“lastValue” in nv) ) ) {
nv <- { lastValue = 0 };
}

imp.onidle( readLighting );`

Agent Code
device.on("lightChanged", function(json) { url = "http://example.com"; // URL you're sending data to headers = {}; // add key value pairs of any headers you need local request = http.post(url, headers, http.jsonencode(json); request.sendasync(function(response) { server.log(response.statuscode + ": " + response.message); }); });