Putting a Host to Sleep Between Sensor Readings
Introduction
This sample app demonstrates how to build projects that periodically take sensor readings, and use the Notecard to put a host MCU to sleep for a set period between readings. This approach is useful in low-power applications, where minimizing energy consumption is essential for prolonging battery life.
Wireless Connectivity with Blues
This sample app is built around the Blues Notecard and Blues Notehub.
The Blues Notecard is the easiest way for developers to add secure, robust, and affordable pre-paid wireless connectivity to their microcontroller or single-board computer of choice. Notecard is a System-on-Module (SoM) that combines pre-paid data, low-power hardware (~8μA-12μA when idle), and secure communications. It acts as a device-to-cloud data pump to communicate with the Blues cloud service Notehub.
Notehub is the Blues cloud service for routing Notecard-provided data to third-party cloud applications, deploying OTA firmware updates, and securely managing fleets of Notecards. Notehub allows for secure communications between edge devices and the cloud without certificate management or manual provisioning of devices.
General Information
System Hardware
This article’s pattern can be implemented with any Notecard, any host microcontroller, any sensor, and any battery. For demonstration purposes, this article uses the following hardware.
Component | Purpose |
---|---|
Blues Notecard Cellular WBGLW | Wireless connectivity module enabling device-to-cloud data syncing. |
Blues Notecarrier F | Carrier board for connecting Notecard to an MCU. |
Blues Swan | Example host MCU. |
Adafruit SCD-40 | Example sensor. |
LiPo Battery | Power source. |
List of Acronyms
Acronym | Definition |
---|---|
MCU | Microcontroller |
SoM | System-on-Module |
Summary
The Notecard greatly simplifies the process of building low-power, sensor-based applications. In addition to being a SoM that's low power by nature (idling at ~8μA-12μA), the Notecard additionally has the ability to manage the power of a host microcontroller and its connected sensors.
As MCUs and sensors are often the biggest sources of power consumption in embedded projects, using the Notecard to intelligently manage these components can drastically reduce the power consumption of your devices.
Requirements
-
A host MCU that exposes an enable
EN
pin. -
One or more sensors that are powered by the same host MCU.
-
Host firmware that takes readings from your sensor(s), and uses the Notecard API to put the MCU to sleep or into a low-power mode.
Technical Implementation
Hardware Wiring
This example makes use of the Notecard's ATTN
pin to manage the
power of a connected host MCU. To make that connection possible, the
Notecard's ATTN
pin must be wired to the host's EN
pin.
Notecard | Host MCU |
---|---|
ATTN | EN |
Additionally, before continuing ensure your host is connected to battery power and any sensor you intend to use.
The demonstration hardware for this example (Cellular Notecard, Notecarrier F, Blues Swan, SCD40 sensor, 2000mAh LiPo battery), is shown connected below.
If you're using a Notecarrier F, you can optionally set the
FEATHER_EN
DIP switch
to N_ATTN
instead of manually wiring the Notecard's ATTN
pin to your host's
enable pin.
Notecard Configuration
Every Notecard must be associated with a cloud-based Notehub project. This is accomplished using the hub.set API.
The request below shows a typical configuration for a low-power application that uses periodic synchronization mode, and uses voltage-variable values for the outbound and inbound intervals. You can take this configuration verbatim, or switch up the intervals based on your project's needs.
{
"req":"hub.set",
"product": "<your-product-uid>",
"mode":"periodic",
"voutbound":"usb:10;high:60;normal:120;low:360;dead:0",
"vinbound":"usb:10;high:1440;normal:1440;low:1440;dead:0"
}
J *req = NoteNewRequest("hub.set");
JAddStringToObject(req, "product", "<your-product-uid>");
JAddStringToObject(req, "mode", "periodic");
JAddStringToObject(req, "voutbound", "usb:10;high:60;normal:120;low:360;dead:0");
JAddStringToObject(req, "vinbound", "usb:10;high:1440;normal:1440;low:1440;dead:0");
NoteRequest(req);
req = {"req": "hub.set"}
req["product"] = "your-productuid"
req["mode"] = "periodic"
req["voutbound"] = "usb:10;high:60;normal:120;low:360;dead:0"
req["vinbound"] = "usb:10;high:1440;normal:1440;low:1440;dead:0"
card.Transaction(req)
For the voltage-variable values to work, the Notecard must know what power source you plan to use (so it knows whether a voltage reading is "usb", "high", "normal", "low", or "dead").
You can provide this information with the card.voltage
API. The request below
shows how to tell the Notecard you're using a LiPo battery, and you can refer to
the request's API documentation
for a list of the other available values.
{
"req":"card.voltage",
"mode":"lipo"
}
J *req = NoteNewRequest("card.voltage");
JAddStringToObject(req, "mode", "lipo");
NoteRequest(req);
req = {"req": "card.voltage"}
req["mode"] = "lipo"
rsp = card.Transaction(req)
Host Firmware
The full sample host firmware is available on GitHub. You may wish to refer to the full source code as you read through this section.
The firmware running on the host MCU is responsible for taking sensor
readings, queuing a Note on the Notecard with the sensor values, and
then using the Notecard's card.attn
command to request that the host
be put to sleep.
The firmware in this section uses the Notecard's Arduino library, but you can implement this pattern with any of the Notecard's SDKs.
Here's the first part of the firmware that takes a sensor reading (in this case from a SCD40), and queues a Note with its values on the Notecard.
void setup()
{
...
// Turn on the Swan's onboard LED when it's powered on. This is a handy
// trick during development as you'll have a visual signal when your host
// is powered on.
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
uint16_t error;
char errorMessage[256];
// Start Measurement
error = scd4x.startPeriodicMeasurement();
if (error) {
Serial.print("Error trying to execute startPeriodicMeasurement(): ");
errorToString(error, errorMessage, 256);
Serial.println(errorMessage);
}
Serial.println("Waiting for first measurement... (5 sec)");
delay(5000);
// Read Measurement
uint16_t co2;
float temp;
float humidity;
error = scd4x.readMeasurement(co2, temp, humidity);
if (error) {
Serial.print("Error trying to execute readMeasurement(): ");
errorToString(error, errorMessage, 256);
Serial.println(errorMessage);
} else if (co2 == 0) {
Serial.println("Invalid sample detected, skipping.");
} else {
Serial.print("Co2:");
Serial.print(co2);
Serial.print("\t");
Serial.print("Temperature:");
Serial.print(temp);
Serial.print("\t");
Serial.print("Humidity:");
Serial.println(humidity);
}
// Queue a Note on the Notecard
J *req = notecard.newRequest("note.add");
if (req != NULL)
{
JAddStringToObject(req, "file", "data.qo");
J *body = JAddObjectToObject(req, "body");
if (body)
{
JAddNumberToObject(body, "co2", co2);
JAddNumberToObject(body, "temp", temp);
JAddNumberToObject(body, "humidity", humidity);
}
notecard.sendRequest(req);
}
error = scd4x.stopPeriodicMeasurement();
if (error) {
Serial.print("Error trying to execute stopPeriodicMeasurement(): ");
errorToString(error, errorMessage, 256);
Serial.println(errorMessage);
}
}
Note that all of the code above is in the Arduino setup()
function,
which is normally intended to only run once when the MCU is powered on.
However, when using this article's pattern the setup()
function runs every
time the host is powered back on by the Notecard. Because of this, the
code in the Arduino loop()
function is minimal.
void loop()
{
// Request that the Notecard place the host to sleep. Use a "command"
// instead of a "request" because the host is going to power down and
// cannot receive a response.
J *req = notecard.newCommand("card.attn");
JAddStringToObject(req, "mode", "sleep");
JAddNumberToObject(req, "seconds", 3600);
notecard.sendRequest(req);
// Delay 1 second in case the host fails to sleep and try again
delay(1000);
}
This code invokes the Notecard's
card.attn
request
to instruct the Notecard to power down the host.
By using the seconds
argument, you tell the Notecard the interval
at which the Notecard should power the host back on, in this case
3600
seconds, or 1 hour.
With this pattern in place, you allow the Notecard to idle in a low-power mode, with the host and sensor(s) completely powered off. Then, every hour (or whatever interval you configure), you turn on the host to take a new reading before returning to a low-power state.
The card.attn
offers several different triggers you can use to wake up
a host (not just seconds
). For example, you can wake a host when the
Notecard receives an inbound Note, when the Notecard moves (as detected
by its onboard accelerometer), or when environment variables change.
For a full list of the options available, check out the
card.attn
request's API documentation.
During development, you cannot flash firmware if your host is disabled via its
EN
pin.
The easiest way to re-enable your host is by removing the connection between
the Notecard's ATTN
pin and your host's EN
pin.
If you're using a Notecarrier F, you can also set the FEATHER_EN
DIP switch
to ON
to enable your host, and then flip the switch back to N_ATTN
after you finish flashing firmware.