Taking an Immediate GPS Reading
Introduction
This sample app shows how to make a Notecard-based tracker take a GPS/GNSS reading on demand. Most trackers sample their location on a schedule to save power, but some events can't wait for the next scheduled reading. A lone worker pressing a panic button, a vehicle detecting a crash, or a technician asking a device to check in all need an accurate location right away.
The sample's firmware waits for a button press, takes an immediate location reading, sends an SOS Note with the result to the cloud, and then returns the tracker to its normal, power-saving location schedule.
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-18μ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 sample's pattern works with any Notecard that has access to a GPS/GNSS module, and any host microcontroller or single-board computer. For demonstration purposes, this sample uses the following hardware.
| Component | Purpose |
|---|---|
| Blues Notecard Cell+WiFi | Wireless connectivity module with built-in GNSS for location tracking. |
| Blues Notecarrier CX | Carrier board with an onboard STM32L433 host MCU (Cygnet), a programmable USER_BTN button, and a LiPo connector. |
| Single-cell 3.7V LiPo battery with a 2-pin JST PH connector | Power source. |
The same steps apply if your Notecard gets its location from an external GPS/GNSS module or a paired Starnote.
List of Acronyms
| Acronym | Definition |
|---|---|
| MCU | Microcontroller |
| SoM | System-on-Module |
| GPS | Global Positioning System, a satellite-based radio navigation system |
| GNSS | Global Navigation Satellite System, a generic term for any satellite constellation that provides positioning and timing services |
| SOS | A distress signal, used here for a high-priority alert that includes the device's location |
Summary
A battery-powered tracker usually runs Notecard's location sampling in
periodic mode, where Notecard powers on its GPS/GNSS module at an interval
you choose, and only when its accelerometer says the device has moved. That
schedule is what lets a tracker last for months on a battery, but it also means
the most recent location can be minutes or hours old.
Notecard doesn't have a single "read my location now" request. Instead, a host
can get the same result by temporarily switching Notecard's location mode to
continuous, which starts a GPS/GNSS search immediately, and then switching it
back once a new reading arrives. The pattern has four steps:
- Record the
timeof Notecard's last location reading. - Switch Notecard to
continuouslocation mode. - Poll Notecard until it reports a reading with a newer
time, or until the search times out. - Restore Notecard's
periodiclocation mode.
Because continuous mode keeps the GPS/GNSS module powered, the host should
only stay in it long enough to get the reading it needs.
Requirements
- A Notehub project to receive the SOS Notes. Create a free project at notehub.io.
- A host microcontroller or single-board computer that controls Notecard, and some event that should trigger a reading. This sample uses a button press.
- A GPS/GNSS antenna with a clear view of the sky.
Technical Implementation
Let AI write your firmware. Blues Expert MCP connects your AI coding assistant (Claude Code, Codex, GitHub Copilot, Cursor) directly to our API docs, providing live request validation and firmware best practices for Arduino, C, Zephyr, and Python. Install the Blues Expert MCP →
The sections below walk through the pattern one step at a time, then put it together in a complete firmware sample. The Notecard requests are the same no matter which language your host runs, so you can implement this pattern with any of the Notecard SDKs. This sample's host firmware uses the Notecard Arduino library.
Hardware Setup
This sample assumes you know how to connect Notecard to the Notecarrier CX, and how to flash firmware to the Notecarrier CX's host. If not, start with the Notecard Quickstart and the Notecarrier CX Quickstart.
Notecard Configuration
Let's start with a standard Notecard configuration for a battery-powered tracker: syncing with Notehub periodically, and sampling its location on a schedule. This is the configuration the tracker runs most of the time, and the one it returns to after each immediate reading. The firmware sends these requests every time it boots, and Notecard saves them to flash.
First, the hub.set API
associates Notecard with your Notehub project. periodic mode keeps the
cellular modem off between syncs, which saves power and leaves the modem free
of the built-in GPS/GNSS module, since the two can't run at the same time.
{
"req": "hub.set",
"product": "<your-product-uid>",
"mode": "periodic",
"outbound": 60,
"inbound": 240
}J *req = NoteNewRequest("hub.set");
JAddStringToObject(req, "product", "<your-product-uid>");
JAddStringToObject(req, "mode", "periodic");
JAddNumberToObject(req, "outbound", 60);
JAddNumberToObject(req, "inbound", 240);
NoteRequest(req);req = {"req": "hub.set"}
req["product"] = "<your-product-uid>"
req["mode"] = "periodic"
req["outbound"] = 60
req["inbound"] = 240
rsp = card.Transaction(req)Next, the card.location.mode API sets the tracker's normal location schedule. Here, Notecard samples its location at most once an hour, and only if it has moved.
{
"req": "card.location.mode",
"mode": "periodic",
"seconds": 3600
}J *req = NoteNewRequest("card.location.mode");
JAddStringToObject(req, "mode", "periodic");
JAddNumberToObject(req, "seconds", 3600);
NoteRequest(req);req = {"req": "card.location.mode"}
req["mode"] = "periodic"
req["seconds"] = 3600
rsp = card.Transaction(req)Reading Location on Demand
Now that you know the configuration to use, let's look at the steps you need to take to get an immediate reading.
Step 1: Store the Time of the Last Location Reading
Notecard stores its last-known location so that you can retrieve it with a card.location request.
{
"req": "card.location"
}J *req = NoteNewRequest("card.location");
NoteRequest(req);req = {"req": "card.location"}
rsp = card.Transaction(req)The response includes a time, which is when Notecard captured that location:
{
"status": "GPS updated (478 sec, 27/33 dB SNR, 4/7 sats, HDOP 1) {gps-active} {gps-signal} {gps-sats} {gps}",
"mode": "periodic",
"lat": 43.96320156666668,
"lon": -83.24814393333334,
"time": 1657306363
}Store that time on your host. In a later step, a different time tells you
Notecard has taken a new reading. If Notecard has never taken a reading, the
response has no time, and the code below stores 0.
J *rsp = notecard.requestAndResponse(notecard.newRequest("card.location"));
JTIME lastFixTime = JGetInt(rsp, "time");
notecard.deleteResponse(rsp);Step 2: Turn On Continuous GPS/GNSS Mode
Next, force Notecard to take a new reading as quickly as possible by setting
its location mode to "continuous".
{
"req": "card.location.mode",
"mode": "continuous"
}J *req = NoteNewRequest("card.location.mode");
JAddStringToObject(req, "mode", "continuous");
NoteRequest(req);req = {"req": "card.location.mode"}
req["mode"] = "continuous"
rsp = card.Transaction(req)Step 3: Wait for the Reading
In continuous mode, Notecard starts a GPS/GNSS search immediately. A reading isn't instantaneous, though, and can take anywhere from seconds to minutes depending on your antenna and its view of the sky.
To wait for it, make card.location requests in a loop. While Notecard is
searching, the response only contains status information:
{
"status": "GPS search (201 sec, 34/34 dB SNR, 0/1 sats, HDOP 0) {gps-active} {gps-signal} {gps-sats}",
"mode": "continuous"
}Once Notecard has a reading, the response includes the new latitude,
longitude, and time. When that time differs from the one you stored in
step 1, you have a new reading. The code below also checks that time is
present, because a request that fails returns no time at all.
If the tracker can't see the sky, the search may never succeed, and an endless
loop would drain its battery. So the loop below gives up after five minutes, or
as soon as Notecard returns "stop": true, which it does in continuous mode
when it can't find a GPS/GNSS signal.
const uint32_t timeoutMs = 5 * 60 * 1000;
const uint32_t startMs = millis();
while (millis() - startMs < timeoutMs) {
J *rsp = notecard.requestAndResponse(notecard.newRequest("card.location"));
if (JIsPresent(rsp, "time") && (JTIME)JGetInt(rsp, "time") != lastFixTime) {
double lat = JGetNumber(rsp, "lat");
double lon = JGetNumber(rsp, "lon");
// Use the new coordinates here.
notecard.deleteResponse(rsp);
break;
}
bool noSignal = JGetBool(rsp, "stop");
notecard.deleteResponse(rsp);
if (noSignal) {
break;
}
delay(2000);
}Step 4: Restore Your GPS/GNSS Configuration
Once you have a reading, or have given up on one, restore the tracker's normal
location mode, as staying in continuous mode uses a considerable amount of
battery.
{
"req": "card.location.mode",
"mode": "periodic"
}J *req = NoteNewRequest("card.location.mode");
JAddStringToObject(req, "mode", "periodic");
NoteRequest(req);req = {"req": "card.location.mode"}
req["mode"] = "periodic"
rsp = card.Transaction(req)card.location.mode remembers the arguments you passed in previous calls, so
you don't need to pass seconds again.
Complete Firmware
The sketch below combines the configuration and the four steps above. When you
press the Notecarrier CX's USER_BTN button, it lights LED_BUILTIN, takes an
immediate reading, restores periodic mode, and adds an SOS Note to sos.qo
with "sync": true so that Notecard sends it to Notehub right away. If the
search fails, the Note is still sent, without coordinates.
Replace <your-product-uid> with your Notehub project's
ProductUID before
flashing. To see the sketch's Serial output, power the board over USB with
the DIP switch next to the USB-C connector in the HST position.
#include <Notecard.h>
#define PRODUCT_UID "<your-product-uid>"
// How often Notecard samples its location when it isn't handling an SOS.
#define LOCATION_INTERVAL_SECONDS 3600
// How long to wait for an immediate reading before giving up.
#define FIX_TIMEOUT_MS (5 * 60 * 1000UL)
Notecard notecard;
volatile bool buttonPressed = false;
void onButtonPress() {
buttonPressed = true;
}
JTIME getLastFixTime() {
J *rsp = notecard.requestAndResponse(notecard.newRequest("card.location"));
JTIME time = JGetInt(rsp, "time");
notecard.deleteResponse(rsp);
return time;
}
void setLocationMode(const char *mode) {
J *req = notecard.newRequest("card.location.mode");
JAddStringToObject(req, "mode", mode);
notecard.sendRequest(req);
}
// Polls card.location until it reports a reading newer than lastFixTime.
// Returns false on timeout, or if Notecard reports it can't find a signal.
bool waitForNewFix(JTIME lastFixTime, double *lat, double *lon) {
const uint32_t startMs = millis();
while (millis() - startMs < FIX_TIMEOUT_MS) {
J *rsp = notecard.requestAndResponse(notecard.newRequest("card.location"));
if (JIsPresent(rsp, "time") && (JTIME)JGetInt(rsp, "time") != lastFixTime) {
*lat = JGetNumber(rsp, "lat");
*lon = JGetNumber(rsp, "lon");
notecard.deleteResponse(rsp);
return true;
}
bool noSignal = JGetBool(rsp, "stop");
notecard.deleteResponse(rsp);
if (noSignal) {
return false;
}
delay(2000);
}
return false;
}
void sendSOS() {
JTIME lastFixTime = getLastFixTime();
setLocationMode("continuous");
double lat = 0;
double lon = 0;
bool located = waitForNewFix(lastFixTime, &lat, &lon);
setLocationMode("periodic");
J *req = notecard.newRequest("note.add");
JAddStringToObject(req, "file", "sos.qo");
JAddBoolToObject(req, "sync", true);
J *body = JAddObjectToObject(req, "body");
JAddBoolToObject(body, "located", located);
if (located) {
JAddNumberToObject(body, "lat", lat);
JAddNumberToObject(body, "lon", lon);
}
notecard.sendRequest(req);
Serial.println(located ? "SOS sent with location." : "SOS sent without a GPS fix.");
}
void setup() {
Serial.begin(115200);
delay(1000);
notecard.begin();
notecard.setDebugOutputStream(Serial);
J *req = notecard.newRequest("hub.set");
JAddStringToObject(req, "product", PRODUCT_UID);
JAddStringToObject(req, "mode", "periodic");
JAddNumberToObject(req, "outbound", 60);
JAddNumberToObject(req, "inbound", 240);
notecard.sendRequest(req);
req = notecard.newRequest("card.location.mode");
JAddStringToObject(req, "mode", "periodic");
JAddNumberToObject(req, "seconds", LOCATION_INTERVAL_SECONDS);
notecard.sendRequest(req);
pinMode(LED_BUILTIN, OUTPUT);
pinMode(USER_BTN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(USER_BTN), onButtonPress, FALLING);
}
void loop() {
if (!buttonPressed) {
delay(50);
return;
}
digitalWrite(LED_BUILTIN, HIGH);
sendSOS();
digitalWrite(LED_BUILTIN, LOW);
// Ignore any presses that arrived while the SOS was in progress.
buttonPressed = false;
}Expected Results
Notecard needs to complete its first sync with Notehub before it enables GPS/GNSS, so give a newly-configured tracker a few minutes before pressing the button.
After you press USER_BTN, the red LED stays on while Notecard searches for a
location. Once it turns off, an sos.qo event appears in your Notehub project:
{
"file": "sos.qo",
"body": {
"located": true,
"lat": 43.96320156666668,
"lon": -83.24814393333334
}
}If located is false, Notecard couldn't get a reading within the timeout.
Notehub still adds a tower-based location to every event in its best_*
fields, so you know roughly where the device was.
Potential Issues
- No GPS/GNSS fix: Confirm the GPS/GNSS antenna is connected and has a clear view of the sky. The first reading in a new location can take several minutes. See Diagnosing GPS Issues on the Notecard for more information.
- SOS Note doesn't reach Notehub: Verify the cellular antenna is connected and that the device is within cellular coverage. See Diagnosing Cellular Connectivity Issues for more information.