No matter your use case or end application, IoT solutions often need to manage state and configuration across multiple devices (and usually long after they've been deployed). Instead of building your own state management system, Notecard and Notehub combine to provide two built-in mechanisms for shared state: database (.db) Notefiles and environment variables.
.db
Notefiles are great for direct state sharing between Notehub and a single
Notecard on a one-to-one basis. On the other hand, environment variables offer
hierarchical state and settings management. They scale from individual
devices to entire fleets or projects, giving multiple levels of control. At
their core, environment variables are simple key-value pairs that can be defined
in the Notehub UI or via the
Notehub API, and they
automatically propagate to devices when Notecards sync with Notehub.
The hierarchical application of environment variables:
Reserved Environment Variables
What may be one of the more overlooked features in the Blues ecosystem, environment variables provide for remote administration of virtually any user-defined feature in firmware. However, what I'd like to focus on today are the reserved environment variables. These are Blues-defined environment variables that directly map to specific Notecard APIs, meaning you can change certain Notecard behaviors without pre-configuring anything ahead of time in your firmware!
For example, let's say you deployed your fleet with the following hub.set
request using a relatively aggressive
voltage-variable
outbound syncing pattern:
{
"req": "hub.set",
"mode": "periodic",
"voutbound": "usb:5;high:15;normal:30;low:60;dead:0"
}
...but have now found it to be overkill and draining on your battery. Instead of recalling this fleet from the field for reprogramming (or performing remote DFU), this setting can be managed with a reserved environment variable:
_sync_outbound_mins = usb:5;high:30;normal:120;low:480;dead:0
New to using environment variables? Be sure to consult our complete guide on Understanding Environment Variables.
Setting Environment Variables
env APIs
Environment variables can be set on and retrieved from a Notecard using the env.* APIs. These APIs are outside the scope of this article though, as reserved environment variables are almost always managed through the Notehub UI and/or Notehub APIs.
Notehub UI
Notehub provides a robust UI for managing environment variables at the device, fleet, and project level. This is useful for managing the potentially complicated relationship between environment variables and the hierarchical level at which they are applied. See our short guide on Setting a Notehub Device Variable for more information.
Notehub API
The Notehub API provides ways to
remotely get, set, and delete environment variables on a device, fleet, or
project basis. For example, this is how you would set an arbitrary
"status":"on"
environment variable on a specific device:
curl -X PUT
-L 'https://api.notefile.net/v1/projects/<projectOrProductUID>/devices/<deviceUID>/environment_variables'
-H 'X-SESSION-TOKEN: <token>'
-d '{"environment_variables":{"status":"on"}}'
It's important to remember that environment variables override any local defaults until you delete/override them. If a reserved environment variable is used and then removed, the device will revert to its previous behavior.
Throughout the rest of this article, we're going to look at a variety of scenarios that can be handled purely via reserved environment variables. Let's dig in!
Managing Your OTA DFU Pipeline
Notecard and Notehub combine to provide a resilient OTA pipeline for both host AND Notecard firmware updates. With Notecard Outboard Firmware Update for host updates, you unlock a virtually "unbrickable" path for ESP32/STM32/nRF hosts - and you can combine it with some reserved environment variables to gate firmware rollouts via specified voltage and time parameters.
Environment Variables to Use
_fw
(string) is the name of the host firmware binary file (it must match a binary already uploaded to your Notehub project)._fwc
(string) is the name of an existing Notecard firmware binary in Notehub (used for Notecard firmware updates only)._dfu_enabled
(string) is a voltage-variable string that lets you enable/disable DFU actions depending on the voltage readings from your power source._dfu_period
(string) lets you specify a local time window for when DFU can be active._fw_download_always_enabled
(1/0) is a boolean override that forces hosts to enable DFU regardless of their current settings.
Example
Let's imagine you want to force a host DFU action to override any potential blockers on the host, but only when the voltage reading is safe (e.g. >= "normal") and the device is not in use (e.g. Sunday morning local time from 2:00AM to 5:00AM). Here are the key-value environment variable pairs you could use at a device, fleet, or project level:
_fw = your-uploaded-host-firmware.bin
_fw_download_always_enabled = 1
_dfu_enabled = usb:1;high:1;normal:1;low:0;dead:0
_dfu_period = 1000000,2,3
To decode _dfu_period
, please note that the format is ddddddd,HH,hrs
:
- The
d
values map to enabling individual days of the week, with a1
to enable and0
to disable. - The
HH
value maps to the starting time on a 24-hour clock. - The
hrs
value maps to the length of time (in hours) DFU is then enabled.
Read more about the host OTA DFU capabilities of Notecard and Notehub in our Host DFU Overview guide.
Fallback from GPS to Triangulation for Location
Each cellular-enabled Notecard includes an integrated GPS module. While GPS is a very accurate means of ascertaining location data, it's also very power-hungry, impossible to use indoors or without a clear view of the sky, and can't be activated while the cellular radio is transmitting. Luckily, any cellular- or Wi-Fi-based Notecard can fallback to Wi-Fi Triangulation (i.e. pinpointing a location based on known coordinates of visible Wi-Fi access points) and/or Cell Tower Triangulation (i.e. triangulating device location based on pings from nearby cell towers), so you can still get timely locations when GPS can't establish a fix on GPS/GNSS satellites.
Environment Variables to Use
_tri_gps_failure
(1/0) enable this so when GPS can't get a lock, the device will fallback to triangulation._tri_always
(1/0) enable if you want to ignore Notecard accelerometer readings and triangulate location even if no motion is detected._tri
(string) set towifi
,cell
, orwifi,cell
to use Wi-Fi Triangulation, Cell Tower Triangulation, or a combination of the two._stale_gps_mins
,_stale_tri_mins
,_stale_tower_mins
(int) let you decide how Notehub chooses what is the "best" location data to use, based on the number of minutes after which each type of reading is considered "stale".
Example
The following is just one example of using reserved environment variables that
bias to GPS when that data is relatively fresh. However, if GPS is stale for >=
180 minutes and a recent Wi-Fi triangulation has happened (< 90 minutes),
Notehub's best_
fields in relevant events will favor triangulation data.
_tri = wifi
_tri_gps_failure = 1
_stale_gps_mins = 180
_stale_tri_mins = 90
See our guide on Using Cell Tower & Wi-Fi Triangulation for more information.
Starting and Stopping Device Tracking
Has a Notecard gone rogue and you need to ascertain its location? You can always initiate GPS tracking and add regular "heartbeats" without touching firmware (and without requiring the device to have moved).
Environment Variables to Use
_gps_track
(1/0) enables tracking via regular_track.qo
Notes._gps_track_heartbeat_hours
(int) adds periodic heartbeats (useful if no motion is detected, yet you still want regular tracking/location events in Notehub)._gps_secs
(int) specifies the cadence at which GPS location is sampled.
Example
The following environment variables enable GPS tracking, pull in location samples every 30 minutes when motion is detected, and add in a heartbeat every 6 hours.
_gps_track = 1
_gps_secs = 1800
_gps_track_heartbeat_hours = 6
Read more about about tracking device location in our comprehensive guide on Asset Tracking with GPS.
Voltage-Aware Syncing Behaviors
Instead of using hard-coded outbound
and inbound
arguments in your hub.set
requests, a best practice is to use
voltage-variable sync behaviors.
These allow you to set syncing patterns based on the voltage levels of your
power source (e.g. sync more frequently when voltages are "normal/high" and less
frequently when "low").
Environment Variables to Use
_sync_inbound_mins
(int or string) use an integer if you want to provide a static value (in minutes), or a string to provide a voltage-variable value to set the cadence of receiving inbound Notes._sync_outbound_mins
(int or string) use an integer if you want to provide a static value (in minutes), or a string to provide a voltage-variable value to set the cadence of sending outbound Notes.
NOTE: These environment variables do require a one-time card.voltage request on the device in order to define what the "high", "normal", "low", etc voltage levels mean based on your power source. For example, if using a lipo battery you might use:
{
"req": "card.voltage",
"mode": "lipo"
}
Example
The following reserved environment variables allow a Notecard to be relatively aggressive in syncing when voltage is higher, yet far more conservative when low on battery.
_sync_outbound_mins = usb:5;high:15;normal:60;low:480;dead:0
_sync_inbound_mins = usb:5;high:30;normal:120;low:720;dead:0
Remotely Update Wi-Fi Access Point Credentials
When using any Wi-Fi-enabled Notecard, it's likely you'll pre-program your fleet
with known Wi-Fi access points and associated credentials via a card.wifi
request.
However, access points and credentials can and do change. Luckily you can still update this data by using a reserved environment variable. Simply send an array of key-value strings in the order in which you'd like your Notecards to try them.
Environment Variable to Use
_wifi
(string) is an array of SSIDs and passwords for known 2.4 GHz Wi-Fi access points.
Example
Imagine your company has rolled out updated access points and credentials. By updating a single environment variable, you can add/update/remove this information on each deployed device.
_wifi = ["StoreWiFi","s3cr3t!"],["CorpGuest","guest123"],["Fallback","password"]
Auto-Recover Unreachable Devices
Are you ever finding a deployed device is seemingly "stuck" and not reporting data to Notehub at the cadence you expect? Granted, if you have no network connectivity whatsoever, setting environment variables after the device is unresponsive will have no effect (remember Notecard has to be able to sync with Notehub in order for environment variables to be enabled!).
Environment Variables to Use
_restart
(string) lets you arbirarily restart a Notecard._restart_every_hours
(int) lets you specify a cadence for rebooting a Notecard (not recommended for production deployments due to increased data usage during reboots)._restart_no_activity_hours
(int) lets you reboot a Notecard if it hasn't connected to Notehub in the specified number of hours.
Example
Let's say you've programmed your firmware in such a way that you know your Notecard should be communicating with Notehub at least once per day. You can use this reserved environment variable to restart Notecard (and hopefully reestablish connectivity in a pinch) after 24 hours of no activity.
_restart_no_activity_hours = 24
Enable Diagnostic Logging
Having trouble with a specific device or an entire fleet? You can remotely
enable diagnostic logging with reserved environment variables that save data to
the _log.qo
Notefile on Notehub.
When you save and sync logging data with Notehub, this does use data from your cellular data allocation. Therefore, it's important to only enable this feature when needed, and disable it immediately afterwards.
Environment Variable to Use
_log
(string) specifies the scope of logging data to save. Valid values includegps
(high-level GPS status),gpsmax
(more verbose GPS logging),power
(power-usage snapshots from a connected Mojo),modem
(modem lifecycle and network state transitions) andall
(a catch-all for broad diagnostics).
NOTE: _log.qo
Notes are only created when new Notehub sessions are
created. Therefore, if using this feature with a Notecard in continuous
mode,
you may need to also specify the _session_mins
environment variable, which
defines the length of a session in minutes.
Example
Let's say you wanted to implement a very "loud" logging window that provides
comprehensive logging data to the _log.qo
Note in 5 minute chunks in
continuous
mode:
_log = all
_sync_continuous = 1
_session_mins = 5
When done, be sure to delete these environment variable to quiet the device and revert to your established firmware defaults.
Remote Relay Control via AUX Pins
Let's end with a fun one!
A personal favorite environment variable (don't we all have our favorite
environment variables!?!), the _aux_gpio_set
reserved environment variable
lets you push a one-time pulse or set a steady state of a specified AUX pin on a
Notecard
Environment Variable to Use
_aux_gpio_set
(string) is used to set specified AUX GPIOsHIGH
orLOW
.
NOTE: This environment variable does require a one-time card.aux
request
on the device in order to set up GPIO access. For example:
{"req":"card.aux","mode": "gpio","state": [{},{},{"high": true},{}]}
In this request, the "state"
array maps to AUX 1, 2, 3, and 4.
Example
What better example could I provide than a project I built to scare neighborhood children during Halloween?
Documented fully in
this Hackster project,
I set the _aux_gpio_set
environment variable to:
,,low,,1000,<current UNIX epoch time>,60
...which tells Notecard to pulse the AUX3 pin LOW
for 1000 ms (after which it
will return to HIGH
), valid from the current UNIX epoch time for 60 seconds.
The empty spaces between the commas are where you could specify the states of
the other AUX pins: 1, 2, or 4. This triggered the relay attached to the
skeleton (and hence the scares!).
Happy Hacking with environment variables! 💙