How to construct a low power firmware that can be updated?

I have a working Particle (Photon) application which is running fine.

Everything is in the setup() function and there is no need of loop().

It wakes up every 15 seconds, queries a sensor, posts the data to a website and then goes back to sleep.

This is very efficient from a power consumption perspective (actually, would be better if I could wake up less frequently (like every5 minutes), but I find that the wifi takes two-or-three wake cycles to actually connect when it first powers up, and 15 seconds is about as long as I can safely wait without recreating that problem.

However, even with these frequent updates, I can’t refresh the device via the cloud (which is semi-desirable in my application).

What are the minimum requirements to be able to flash a device that is asleep most of the time via the cloud?

I’ve included my current code since it is short for completeness.

#include "Adafruit_DHT.h"

#include "application.h"
#include "HttpClient.h"

#define SERVER "www.delong.com"
#define PORT 80
#define CGI_PATH "/cgi-bin/post_temp.cgi"
#define MY_ID "Photon_Test1"

// DHT22 is installed next to Photon on a breadboard such that Photon 567G = DHT 1234. A 10kΩ resistor is also
// placed across 56/12. Hence, to power the DHT, we need to hold 5 high.
#define DHTPOWER 5
#define DHTPIN 6
#define DHTTYPE DHT22

#define SLEEP_DURATION 15 // Sleep for 15 seconds between polling intervals For debugging

http_header_t headers[] = {
    { "Accept", "*/*" },
    { NULL, NULL },
};

DHT probe(DHTPIN, DHTTYPE);

HttpClient http;
uint32_t next_time;

http_request_t request;
http_response_t response;


void setup() {
    Serial.begin(115200);
    float tC;
    float hum;
    char Query[1024];
    char tbuf[10];
    char hbuf[10];

    Serial.println();
    Serial.println("Application>\tGathering Data");
    // Gather the data
    pinMode(DHTPOWER, OUTPUT);
    digitalWrite(DHTPOWER, HIGH);
    probe.begin();
    delay(1000); // Let probe stabilize after powerup.
    hum = probe.getHumidity();
    tC = probe.getTempCelcius();
    Serial.print("Application>\t\tHumidity: ");
    Serial.println(hum);
    Serial.print("Application>\t\tTemperature: ");
    Serial.println(tC);


    // Report the data
    Serial.println("Application>\tPerparing Query");
    request.hostname=SERVER;
    request.port=PORT;
    String(tC).toCharArray(tbuf, 6);        // Ugly, but apparently only workable way on Particle
    String(hum).toCharArray(hbuf, 6);    // Ugly, but apparently only workable way on Particle
    sprintf(Query, "%s?my_id=%s&sensor_unit_1=dht_2&temp_1=%s&hum_1=%s", CGI_PATH, MY_ID, tbuf, hbuf);
    Serial.print("Applicatin>\t\tQuery String: ");
    Serial.println(Query);
    request.path = Query;

    // Send the request
    Serial.println("Application>\tSending Query");
    http.get(request, response, headers);
    Serial.print("Application>\tResponse status: ");
    Serial.println(response.status);

    Serial.print("Application>\tHTTP Response Body: ");
    Serial.println(response.body);

    // Sleep until next report period
    Serial.println("Sleeping");
    delay(500); // Let the Serial buffer drain before power down.
    System.sleep(SLEEP_MODE_DEEP, SLEEP_DURATION);
    Serial.println("This shouldn't happen");
}

void loop() {
}
1 Like

I use a control pin to regulate if the Photon goes to sleep or just applies a 'delay' between queries. If the pin is HIGH, the Photon goes to sleep, if it is LOW, no sleep. This way I can jumper the pin to ground to do development, and then just jumper the pin to high and trigger sleep. Basically a 'program / run' switch.

BTW, there is a much better library for DHT available than the one that you are using. Please see

2 Likes

@owendelong, @Awake is right in pointing out the problems with the idDHT22 library which I have now posted disclaimers on and consider deprecated. One key feature being developed by the Particle team is Cloud queuing including firmware pushes. For example, when you push new code to your Photon but it is asleep, the update will be pushed. When the Photon wakes, it will automatically check the Cloud queue and pull in the update. :smile:

2 Likes

Sorry to be smarmy, but as far as new ā€˜features’, I’ll believe it when I see it. There are far too many fundamental holes in the basic functionality that still need addressing… I would rather get compatibility with the basic Arduino functioning before they add more ā€˜neato’ stuff. The Particle team needs to regroup and get the basics working.

2 Likes

@Awake, which ā€œbasic arduino functionalityā€ are you missing?

1 Like

Ping @christine

Not to drift too far off topic, the jumper idea is useless. I can go smack the setup button as easily as I can install a jumper, but eventually this thing is supposed to go to a very remote location.

Firmware queuing would solve my problem, but in the meantime, I’m looking for ideas on how to deal with what we have today. So, does anyone know what is actually necessary and/or have any examples of code for extremely low power operation? (It’s possible that the site where this will eventually be running will have to survive for many days on battery powering not only this device, but also a couple of relatively high wattage radios (think amateur repeater, 10W), the WAP, router, and local network terminating equipment). Sure, when the site has power, things are fine and I suppose I could build a more elaborate solution that holds a pin HIGH as long as there’s AC power available, but making this thing low-power feels like the better solution. A trip up the mountain (1.5 hour drive minimum if the road is passable) to update the firmware is less than desirable. (I accept that a trip up the mountain to replace borked firmware updates may be required, as I’ll carefully locally test the update process before sending to the mountain).

(I used Adafruit_DHT, so not sure how idDHT22 came into the mix). Bottom line, I’m not going to go through the hassle of changing libraries in the local copy and the WebIDE is broken at the moment (Particle apparently broke it just before leaving for the weekend, which really annoys me since the weekend is when most of my time to play with such things occurs)

For what I’m doing, the Adafruit library isn’t without its issues, but it’s working well enough.

I don’t know what Awake’s issues are, I haven’t encountered them yet (since sprintf with %f doesn’t work there, either), though at least they have working dtostrf() with documentation and examples), but I will say Arduino never broke my IDE for the weekend.

im not a low power expert so i will refrain from tackling that question…but i am currently using the WebIDE in another tab. what’s ā€œbrokenā€ for you on the webIDE?

1 Like

You could put code on the device that

  1. Subscribes to a cloud event foo
  2. Once every X seconds, temporarily suspends the sleep cycle, waits for Spark.connected() to become true, then waits a few seconds to see if it receives event foo, and if so, publishes cloud event bar.
  3. Waits a few seconds before resuming its sleep cycle

On your end, when you are ready to flash the device, publish foo (using command line tools), then wait until the device publishes bar (to tell you that it’s ready to be flashed), then flash the device.

If the sleep delay on the device is greater than 60 seconds, you’ll have to keep publishing foo every 60 seconds (which is currently the only TTL you can have on a cloud event) until you get a bar back.

2 Likes

Just to give a heads-up on timelines for the cloud queueing feature @peekay123 mentioned above — because we expect sleepy devices to be an extremely common use case for the Electron, this feature is required by the time we ship it in October. :clock10:

2 Likes

Until this morning, All my attempts to compile anything since Friday evening had resulted in an Error 404.

I was able to compile the same code in the local IDE without an issue.

Now that it’s back, I’m still seeing a different problem. Now I’m getting errors claiming that inside of HttpClient, delay() and millis() are not defined. Strangely, with the same code, compiled in the local IDE, I still do not have this problem.

The same code (modulo some changes to #include statements to deal with differences in the directory environment for local libraries vs. cloud development) compiles just fine in the local environment. (ā€œParticle DEVā€)

Hi @owendelong,

Good questions! If you want to use a queued flash to flash your photon, keeping your photon online for around ~15 seconds is a good window. Right now the cloud waits about 5 seconds after the handshake before starting to re-play queued commands (like a firmware update).

As soon as we release the newer photon firmware, the cloud will automatically deliver system updates as needed when you’re working with the IDE. Because this means up to 3 files are being flashed instead of just one, queued commands become necessary very quickly. You can actually test this now with the ā€˜signal’ command, if you add a ā€œttlā€ property to the request. the TTL (or time to live), will instruct the server to let the command stick around for that many seconds before expiring. If your device connects in that timeframe, and is online for more than ~5 seconds, the cloud will send that command to your device.

Auto-updates and the signal command are the first paths to use this new feature, but we’ll soon extend it to any OTA, or function calls, and down the road will probably extend it to events and anything that needs it.

I hope that helps!

Thanks,
David

2 Likes

This sounds like exactly what I need. So far, I've been delivering my updates by clicking the lightning bolt in the IDE (web or local). I wasn't aware of an alternative. Can you point me to documentation of how to set a TTL on a "scheduled update" instead?

Thanks!

Owen

OK… Since you recommended the PietteTech DHT library, I’m going to start by asking here.

After converting to that library, I’m running into a problem where calls to:

result = DHT.acquireAndWait();

Never return. Unfortunately, whatever is going wrong seems to still pet the watchdog timer, so the system doesn’t reset automatically. I haven’t looked at the library source yet, but I figured I’d ask if this is a known issue and if you had any suggestions.

I’ve created the following code to test some power modes.
http://pastebin.com/cwwEbvWu
(Note: I’ve only had my Photon a few days and only played with it for a few hours)
My Photon uses about 360mW in normal operation, 220mW with WiFi.off() (the same for System.sleep(seconds) which
is more cumbersome since I can’t get it to wake up the WiFi on it’s own) and below the measuring threshold in deep sleep.

For a low power firmware I would currently go with wake up -> measure/do your thing potentially do as much as you can without WiFi -> deep sleep that brings us back to the beginning. As for updating, either one keeps the connected time long enough and we wait for queuing or use a different server to check for a ā€œupdate incomingā€ flag.

Thanks… Yeah, I’m kind of looking for the ā€œHow long does it need to be on line in order to be reasonably capable of updating the firmware?ā€ answer.

In other words, where you say ā€œeither one keeps the connected time long enoughā€¦ā€, the question is ā€œhow long is ``long enoughā€™ā€™ā€.

HAve you tried the code in the thread that I first referred you to?