---
title: Taking an Immediate GPS Reading
description: Force Notecard to take an immediate GPS/GNSS reading from host firmware, such as for an SOS alert, then restore your tracker's power-saving location mode.
source_url: https://dev.blues.io/example-apps/samples/taking-an-immediate-gps-reading/
canonical_url: https://dev.blues.io/example-apps/samples/taking-an-immediate-gps-reading/
markdown_url: https://dev.blues.io/example-apps/samples/taking-an-immediate-gps-reading.md
---

# Taking an Immediate GPS Reading

## Introduction {#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 {#wireless-connectivity-with-blues}

This sample app is built around the [Blues Notecard](https://blues.com/products/notecard/) and [Blues Notehub](https://blues.com/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 {#general-information}

### System Hardware {#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](https://shop.blues.com/products/notecard-cell-wifi?utm_source=dev-blues\&utm_medium=web\&utm_campaign=store-link) | Wireless connectivity module with built-in GNSS for location tracking. |
| [Blues Notecarrier CX](https://shop.blues.com/products/notecarrier-cx?utm_source=dev-blues\&utm_medium=web\&utm_campaign=store-link) | 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](https://dev.blues.io/example-apps/samples/continuous-asset-tracking-with-external-gps-and-immediate-location-sync.md) or a paired [Starnote](https://dev.blues.io/starnote/satellite-best-practices.md#use-starnote-as-an-external-gps).

### List of Acronyms {#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 {#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:

1. Record the `time` of Notecard's last location reading.
2. Switch Notecard to `continuous` location mode.
3. Poll Notecard until it reports a reading with a newer `time`, or until the search times out.
4. Restore Notecard's `periodic` location 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 {#requirements}

1. A Notehub project to receive the SOS Notes. Create a free project at [notehub.io](https://notehub.io/).
2. A host microcontroller or single-board computer that controls Notecard, and some event that should trigger a reading. This sample uses a button press.
3. A GPS/GNSS antenna with a clear view of the sky.

## Technical Implementation {#technical-implementation}

tip

**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 →](https://dev.blues.io/tools-and-sdks/generative-ai-tools/blues-expert-mcp.md)

The sections below walk through the pattern one step at a time, then put it together in a [complete firmware sample](#complete-firmware). 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](https://dev.blues.io/tools-and-sdks/firmware-libraries.md). This sample's host firmware uses the [Notecard Arduino library](https://dev.blues.io/tools-and-sdks/firmware-libraries/arduino-library.md).

### Hardware Setup {#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](https://dev.blues.io/quickstart/notecard-quickstart.md) and the [Notecarrier CX Quickstart](https://dev.blues.io/quickstart/notecarrier-cx-quickstart.md).

### Notecard Configuration {#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](https://dev.blues.io/api-reference/notecard-api/hub-requests/latest.md#hub-set) 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.

**JSON**

```json
{
  "req": "hub.set",
  "product": "<your-product-uid>",
  "mode": "periodic",
  "outbound": 60,
  "inbound": 240
}
```

**C/C++**

```cpp
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);
```

**Python**

```python
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](https://dev.blues.io/api-reference/notecard-api/card-requests/latest.md#card-location-mode) sets the tracker's normal location schedule. Here, Notecard samples its location at most once an hour, and only if it has moved.

**JSON**

```json
{
  "req": "card.location.mode",
  "mode": "periodic",
  "seconds": 3600
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.location.mode");
JAddStringToObject(req, "mode", "periodic");
JAddNumberToObject(req, "seconds", 3600);

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.location.mode"}
req["mode"] = "periodic"
req["seconds"] = 3600

rsp = card.Transaction(req)
```

## Reading Location on Demand {#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 {#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](https://dev.blues.io/api-reference/notecard-api/card-requests/latest.md#card-location) request.

**JSON**

```json
{
  "req": "card.location"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.location");

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.location"}

rsp = card.Transaction(req)
```

The response includes a `time`, which is when Notecard captured that location:

```json
{
 "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`.

```cpp
J *rsp = notecard.requestAndResponse(notecard.newRequest("card.location"));
JTIME lastFixTime = JGetInt(rsp, "time");
notecard.deleteResponse(rsp);
```

### Step 2: Turn On Continuous GPS/GNSS Mode {#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"`.

**JSON**

```json
{
  "req": "card.location.mode",
  "mode": "continuous"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.location.mode");
JAddStringToObject(req, "mode", "continuous");

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.location.mode"}
req["mode"] = "continuous"

rsp = card.Transaction(req)
```

### Step 3: Wait for the Reading {#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:

```json
{
 "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.

```cpp
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 {#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.

**JSON**

```json
{
  "req": "card.location.mode",
  "mode": "periodic"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.location.mode");
JAddStringToObject(req, "mode", "periodic");

NoteRequest(req);
```

**Python**

```python
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 {#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](https://dev.blues.io/notehub/notehub-walkthrough.md#finding-a-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.

```cpp
#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 {#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:

```json
{
  "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 {#potential-issues}

1. **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](https://dev.blues.io/support/diagnosing-gps-issues.md) for more information.
2. **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](https://dev.blues.io/support/diagnosing-cellular-connectivity-issues.md) for more information.

## Additional Resources {#additional-resources}

- [Asset Tracking with GPS Guide](https://dev.blues.io/guides-and-tutorials/notecard-guides/asset-tracking-with-gps.md)
- [Working with GPS on the Notecard](https://dev.blues.io/notecard/notecard-walkthrough/time-and-location-requests.md#working-with-gps-on-the-notecard)
- [Diagnosing GPS Issues on the Notecard](https://dev.blues.io/support/diagnosing-gps-issues.md)
- [Building a Simple Asset Tracker](https://dev.blues.io/example-apps/samples/building-a-simple-asset-tracker.md)
- [Notecarrier CX Quickstart](https://dev.blues.io/quickstart/notecarrier-cx-quickstart.md)

Can we improve this page? [Send us feedback](mailto:devrel@blues.com)
