---
title: Time & Location Requests
description: Once the Notecard is connected to a cell network or GPS, there are a number of requests available for obtaining the time, location, and using the onboard GPS module for location tracking.
source_url: https://dev.blues.io/notecard/notecard-walkthrough/time-and-location-requests/
canonical_url: https://dev.blues.io/notecard/notecard-walkthrough/time-and-location-requests/
markdown_url: https://dev.blues.io/notecard/notecard-walkthrough/time-and-location-requests.md
---

# Time & Location Requests

Once the Notecard has connected to Notehub, there are a number of requests available for obtaining the time, location, and (on cellular-based Notecards) using the onboard GPS module for location tracking.

## Obtaining the Current Time and Date

To obtain the current time, expressed as a Unix epoch value, use the [`card.time`](https://dev.blues.io/api-reference/notecard-api/card-requests.md#card-time) request.

> Upon power-up, the Notecard must complete a sync to Notehub in order to obtain time and location data.

**JSON**

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

**C/C++**

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

NoteRequest(req);
```

**Python**

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

rsp = card.Transaction(req)
```

Sending this request yields a response that includes the current UNIX Epoch `time`, geographic `area`, local time `zone`, `minutes` East of GMT, latitude (`lat`), longitude (`lon`), and `country`.

```json
{
 "time": 1598478570,
 "area": "Beverly, MA",
 "zone": "CDT,America/New_York",
 "minutes": -300,
 "lat": 42.5776,
 "lon": -70.87134,
 "country": "US"
}
```

> **Note:**
>
> **Tower Location vs. Notecard Location**
>
> It's important to note that the location values returned by a `card.time` request correspond to the **cellular tower** to which the Notecard last connected. This may differ widely from the physical location of the Notecard. For greater accuracy of location, you'll want to use the [`card.location`](https://dev.blues.io/api-reference/notecard-api/card-requests.md#card-location) APIs described below.

Until the Notecard has connected to Notehub, it does not know the time. In those cases, `card.time` requests respond with an `err` field and a `zone` value of `UTC,Etc/UTC`.

```json
{
 "err": "time is not yet set {no-time}",
 "zone": "UTC,Etc/UTC"
}
```

## Using Cell Tower & WiFi Triangulation

For improved location accuracy without using GPS, the Notecard provides optional triangulation capabilities that can gather information about surrounding cell towers and/or local WiFi access points to ascertain a location upon each new Notehub session.

Due to the low-power nature of the Notecard, triangulation-derived location data is only available if the Notecard has detected motion with its onboard accelerometer (unless overridden by `card.triangulate` arguments).

**Cell tower triangulation** is available on the Notecard Cellular and Notecard Cell+WiFi. Cell tower triangulation should be used sparingly if your device is battery-powered, as it can add 1-2 minutes of connection time whenever the Notecard powers on the cellular modem to establish a connection with Notehub. Cell tower triangulation is disabled by default on all Notecards.

**WiFi triangulation** is available on any Notecard that has access to a WiFi module (either on the Notecard or on a connected host). Unlike cell tower triangulation, WiFi triangulation adds only 1-2 seconds of processing time, uses minimal power, and can be nearly as accurate as a GPS-derived location. WiFi triangulation is enabled by default on the Notecard WiFi and Notecard Cell+WiFi, and is disabled by default on the Notecard Cellular.

> **Warning:**
>
> WiFi triangulation is an experimental, technical preview feature that is free for use today, but may use [event credits](https://dev.blues.io/notehub/notehub-walkthrough.md#understanding-event-credits) in the future. Blues reserves the right to rate limit excessive WiFi triangulation requests at our discretion.

> **Note:**
>
> Triangulation requires that the Notecard has made a successful network connection upon startup to obtain the current time. See [Functions that Require Setting Time](https://dev.blues.io/notecard/notecard-walkthrough/advanced-notecard-configuration.md#functions-that-require-setting-time) for the full list of features with this prerequisite.

### Enabling Triangulation

To enable triangulation, use the `card.triangulate` request with the `mode` argument set to `wifi`, `cell`, or both, separated by a comma:

**JSON**

```json
{
  "req": "card.triangulate",
  "mode": "wifi,cell"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.triangulate");
JAddStringToObject(req, "mode", "wifi,cell");

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.triangulate"}
req["mode"] = "wifi,cell"

rsp = card.Transaction(req)
```

This request will return an object confirming that triangulation is enabled with the mode provided, and a `motion` field indicating the last time device movement was detected.

```json
{
  "mode": "wifi,cell",
  "motion": 1606761044
}
```

### When Triangulation Scans Happen

The Notecard attempts to collect and transmit scan data at the start of each new Notehub [session](https://dev.blues.io/api-reference/glossary.md#session). Whether it actually does so depends on two conditions:

**Motion (on by default):** The scan is skipped if the device has not moved since the last scan, as determined by the Notecard’s onboard accelerometer. This prevents unnecessary scans on stationary devices. See [Configuring USB Power and Motion-based Triangulation](#configuring-usb-power-and-motion-based-triangulation) for how to override this.

**Time (optional):** A minimum delay, in minutes, that must elapse between successive scans. This is configured at two levels:

- `_tri_mins` — a [reserved environment variable](https://dev.blues.io/guides-and-tutorials/notecard-guides/understanding-environment-variables.md#reserved-environment-variables) set from Notehub. All new Notehub projects default this to `1440` (once per day).
- `minutes` — a device-local floor set via the `card.triangulate` request (defaults to `0`, meaning no device-local delay). Applies only when the `_tri_mins` environment variable is unset or `0`.

The `_tri_mins` environment variable can also be changed from the **Settings** of your Notehub project:

![notehub triangulation rate settings](https://dev.blues.io/images/guides/notecard-guides/notehub-triangulation.png?v=a64de2c1)

> **Note:**
>
> After a WiFi scan, Notecard may skip triangulation if the strongest access points are largely the same as those found in the previous scan. In that case, Notecard treats the location as unchanged and does not send redundant scan data to Notehub.

The `card.triangulate` request does not itself perform triangulation with the Notecard. Rather, it gathers cell tower and/or WiFi access point data that Notehub uses to perform device triangulation. You'll see this information appear in Notehub as [`_geolocate.qo` Notes](https://dev.blues.io/api-reference/system-notefiles.md#geolocate-qo).

![List of \_geolocate.qo Notes in Notehub](https://dev.blues.io/images/guides/notecard-guides/geolocate-notes.png?v=30c1cd43)

The Notecard sends scan data at the start of each new [session](https://dev.blues.io/api-reference/glossary.md#session) (subject to the motion and time conditions described above). Notehub uses that data to resolve a location. Once a session begins, the triangulated location for that session will appear in all Notehub events that occur during that session.

All triangulated location fields are prepended with `tri_` and may be routed. For example:

```json
"tri_when": 1656011112,
"tri_lat": 43.07113895,
"tri_lon": -89.43272533,
"tri_location": "Shorewood Hills WI",
"tri_country": "US",
"tri_timezone": "America/Chicago",
"tri_points": 16,
```

### Providing WiFi Information to the Notecard

The Notecard WiFi and Notecard Cell+WiFi have onboard WiFi modules that automatically scan access points and provide the appropriate information to Notehub to perform WiFi triangulation requests.

If you are using a Notecard Cellular and would like to leverage Notehub's WiFi triangulation requests, you must manually retrieve this access-point information from a connected host, and provide it to the `card.triangulate` request's `text` argument.

The format of the `text` field must be a newline-terminated list of WiFi access points that follows a pattern similar to the [ESP32's AT+CWLAP](https://docs.espressif.com/projects/esp-at/en/latest/AT_Command_Set/Wi-Fi_AT_Commands.html#cmd-lap) command output.

**JSON**

```json
{
  "req": "card.triangulate",
  "text": "+CWLAP:(4,\"Blues\",-51,\"74:ac:b9:12:12:f8\",1)\n+CWLAP:(3,\"AAAA-62DD\",-70,\"6c:55:e8:91:62:e1\",11)\n+CWLAP:(4,\"Blues\",-81,\"74:ac:b9:11:12:23\",1)\n+CWLAP:(4,\"Blues\",-82,\"74:ac:a9:12:19:48\",11)\n+CWLAP:(4,\"Free Parking\",-83,\"02:18:4a:11:60:31\",6)\n+CWLAP:(5,\"GO\",-84,\"01:13:6a:13:90:30\",6)\n+CWLAP:(4,\"AAAA-5C62-2.4\",-85,\"d8:97:ba:7b:fd:60\",1)\n+CWLAP:(3,\"DIRECT-a5-HP MLP50\",-86,\"fa:da:0c:1b:16:a5\",6)\n+CWLAP:(3,\"DIRECT-c6-HP M182 LaserJet\",-88,\"da:12:65:44:31:c6\",6)\n\n"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.triangulate");
JAddStringToObject(req, "text", "+CWLAP:(4,\"Blues\",-51,\"74:ac:b9:16:15:f8\",1)\n+CWLAP:(3,\"CBCI-62DD\",-70,\"6c:55:e8:91:62:e1\",11)\n+CWLAP:(4,\"Blues\",-81,\"74:ac:b9:16:16:80\",1)\n+CWLAP:(4,\"Blues\",-82,\"74:ac:b9:16:19:48\",11)\n+CWLAP:(4,\"Free Parking\",-83,\"02:18:4a:13:90:31\",6)\n+CWLAP:(5,\"GO\",-84,\"02:18:4a:13:90:30\",6)\n+CWLAP:(3,\"\",-84,\"7a:8a:20:51:da:c7\",6)\n+CWLAP:(4,\"CBCI-5C62-2.4\",-85,\"d8:97:ba:7b:fd:60\",1)\n+CWLAP:(3,\"PBW\",-85,\"78:8a:20:51:da:c7\",6)\n+CWLAP:(3,\"DIRECT-a5-HP MLP50\",-86,\"fa:da:0c:1b:16:a5\",6)\n+CWLAP:(3,\"DIRECT-c6-HP M182 LaserJet\",-88,\"da:12:65:44:31:c6\",6)\n\n");

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.triangulate"}
req["text"] = "+CWLAP:(4,\"Blues\",-51,\"74:ac:b9:12:12:f8\",1)\n+CWLAP:(3,\"AAAA-62DD\",-70,\"6c:55:e8:91:62:e1\",11)\n+CWLAP:(4,\"Blues\",-81,\"74:ac:b9:11:12:23\",1)\n+CWLAP:(4,\"Blues\",-82,\"74:ac:a9:12:19:48\",11)\n+CWLAP:(4,\"Free Parking\",-83,\"02:18:4a:11:60:31\",6)\n+CWLAP:(5,\"GO\",-84,\"01:13:6a:13:90:30\",6)\n+CWLAP:(4,\"AAAA-5C62-2.4\",-85,\"d8:97:ba:7b:fd:60\",1)\n+CWLAP:(3,\"DIRECT-a5-HP MLP50\",-86,\"fa:da:0c:1b:16:a5\",6)\n+CWLAP:(3,\"DIRECT-c6-HP M182 LaserJet\",-88,\"da:12:65:44:31:c6\",6)\n\n"

rsp = card.Transaction(req)
```

This request will return an object with the current triangulation configuration parameters, and a `length` field indicating the size of the `text` buffer provided in the request.

```json
{
  "usb": true,
  "mode": "wifi",
  "length": 398,
  "on": true,
  "time": 1606770857,
  "motion": 1606770581
}
```

> **Note:**
>
> The [Notecard Auxiliary WiFi Arduino library](https://github.com/blues/notecard-aux-wifi) provides an easy way to programmatically pull a list of WiFi access points from a WiFi enabled host MCU in the required format.

### Configuring USB Power and Motion-based Triangulation

The `card.triangulate` request provides options for configuring the Notecard based on its power state and movement. Set the `usb` argument to `true` to instruct the Notecard to only perform triangulation when connected to USB power, and set `on` to `true` if you want the Notecard to triangulate even when the device has not moved. Both flags require the `set` argument in order to take effect.

**JSON**

```json
{
  "req": "card.triangulate",
  "mode": "wifi,cell",
  "on": true,
  "usb": true,
  "set": true
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.triangulate");
JAddStringToObject(req, "mode", "wifi,cell");
JAddBoolToObject(req, "on", true);
JAddBoolToObject(req, "usb", true);
JAddBoolToObject(req, "set", true);

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.triangulate"}
req["mode"] = "wifi,cell"
req["on"] = True
req["usb"] = True
req["set"] = True

rsp = card.Transaction(req)
```

This request will return an object with the current triangulation configuration parameters, a `motion` field indicating the time of the last device movement, and `time` field indicating the time of the last triangulation scan.

```json
{
  "mode": "wifi,cell",
  "usb": true,
  "on": true,
  "time": 1606758961,
  "motion": 1606761044
}
```

### Ascertaining an Approximate Device Location

When `card.location.mode` is set to `"mode":"off"`, which is the default behavior of the Notecard WiFi, Notehub will automatically download to the Notecard its "best guess" as to the general location of the device. This location is either the WiFi triangulation result (preferred), cell tower triangulation result, or nearest cell tower.

When subsequently issuing a `card.location` request, the Notecard will return the approximate location (which is updated every time a new Notehub [session](https://dev.blues.io/api-reference/glossary.md#session) is created).

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

```json
{
 "status": "GPS is off {gps-inactive}",
 "mode": "off",
 "lat": 43.07426250000001,
 "lon": -89.442609375,
 "dop": 20,
 "time": 1709312128
}
```

> **Note:**
>
> This functionality is not available on the Notecard for LoRa.

### Disabling Triangulation

You can disable triangulation by setting the `_tri` [reserved environment variable](https://dev.blues.io/guides-and-tutorials/notecard-guides/understanding-environment-variables.md#reserved-environment-variables) to `"off"` in Notehub at the project, fleet, or device level. This disables both cell and WiFi triangulation and takes precedence over any mode configured on the device via `card.triangulate`.

> **Note:**
>
> The change only takes effect after your device has performed an inbound sync to retrieve the updated environment variable. Read more about how environment variables work in [Understanding Environment Variables](https://dev.blues.io/guides-and-tutorials/notecard-guides/understanding-environment-variables.md).

### Suppressing Location Data

While `_tri` controls whether triangulation is *performed*, you can also prevent the Notecard from *transmitting* specific categories of location data to Notehub, regardless of how that data was acquired. Set any of the following reserved environment variables to `1` (at the project, fleet, or device level):

- `_suppress_where` — prevents the Notecard from including its GPS/GNSS-derived location in the data it sends to Notehub.
- `_suppress_tower` — prevents the Notecard from including the identifier of the most recently used cell tower.
- `_suppress_tri` — prevents the Notecard from uploading the WiFi access point and cell tower scan results used for triangulation.

Each variable governs a single category of location data. To suppress all three categories of location data the Notecard reports to Notehub, set all three.

> **Note:**
>
> These variables suppress data at the source, before it leaves the Notecard, and are independent of `_tri`. For example, `_suppress_tri` stops triangulation scan results from being uploaded even if triangulation is still enabled via `card.triangulate`.

#### Suppressing Notehub-Side Geolocation

The variables above stop location data at its source, before it leaves the Notecard. A separate set of reserved environment variables instead prevents *Notehub* from performing its own server-side geolocation lookups. These are useful for privacy-sensitive applications where a device still reports the cell tower and WiFi scan data that Notehub would normally use, but you do not want Notehub to derive or store an estimated location:

- `_suppress_geolocation` — suppresses all Notehub geolocation lookups, both cell tower and triangulation.
- `_suppress_tower_geolocation` — suppresses cell tower lookups only.
- `_suppress_tri_geolocation` — suppresses triangulation lookups only.

To enable any of these environment variables, set them to a boolean value at the project, fleet, or device level (e.g. `true` or `1`).

## Working with GPS on the Notecard

The Notecard Cellular and Notecard Cell+WiFi include an onboard GPS module that can be used for location tracking, when paired with an appropriate antenna.

> **Warning:**
>
> 1. Notecard's cellular radio and internal GPS module cannot be enabled at the same time. When building a location-aware product, be sure one or both are in `periodic` mode and that you allot enough time for Notecard to switch between cellular and GPS functions, which can take 1-2 minutes depending on the strength of the cellular connection and/or the visibility of GPS satellites.
>
>    Alternatively, you can use an [external GPS module](https://dev.blues.io/example-apps/samples/continuous-asset-tracking-with-external-gps-and-immediate-location-sync.md) to enable both cellular and GPS connectivity simultaneously.
>
> 2. Notecard will not enable its internal GPS module until it has made a successful **cellular** connection upon startup to obtain the current time.

To conserve power, the GPS module on the Notecard is off, by default. You can confirm this with the `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)
```

Which will return the following:

```json
{
 "status": "GPS is off {gps-inactive}",
 "mode": "off"
}
```

When using GPS mode, you'll want to decide whether your application should enable GPS periodically to conserve battery at the cost of accuracy between readings, or continuously in real-time.

> **Note:**
>
> As of [Notecard firmware v6.1.1](https://dev.blues.io/notecard/notecard-firmware-releases.md#lts-v6-1-1-january-3-2024), if a GPS location is not available the `card.location` request returns the `lat` and `lon` from the device's most recent cell tower location or [triangulated location](https://dev.blues.io/notecard/notecard-walkthrough/time-and-location-requests.md#using-cell-tower-and-wifi-triangulation).
>
> When a GPS location is available you'll see a `"GPS updated"` message in the `status` of your `card.location` request, and the `lat` and `lon` that appear in the response will be from the onboard GPS module.

## Sampling GPS Readings with Periodic Mode

If you prefer to enable GPS readings on an interval, use `periodic` mode. In this mode, the Notecard enables GPS at a frequency you define using either a set number of seconds or using a voltage-variable value.

In both cases, regardless of the periodic value, the GPS module will only turn on to update the location if the Notecard has moved since the last time GPS was enabled. The `seconds` value sets the *minimum interval* at which the Notecard will enable its GPS.

**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)
```

> **Note:**
>
> If `seconds` is less than `300` (five minutes), the Notecard will leave its onboard GPS/GNSS module on continuously during periods of sustained movement, rather than powering it on and off repeatedly. This keeps readings current while the device is active, but it also increases power consumption, so choose short intervals with battery life in mind.

In battery-powered designs where the GPS sampling frequency should vary with remaining battery life, use `vseconds` instead of `seconds`. The `vseconds` argument accepts a semicolon-separated string of `voltage:seconds` pairs that maps each [voltage-variable threshold bucket](https://dev.blues.io/notecard/notecard-walkthrough/low-power-firmware-design.md#customizing-voltage-variable-behaviors) to a sampling interval. For example, to sample every 15 minutes when battery is high, every 30 minutes when normal, and every 2 hours when low:

**JSON**

```json
{
  "req": "card.location.mode",
  "mode": "periodic",
  "vseconds": "usb:900;high:900;normal:1800;low:7200"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.location.mode");
JAddStringToObject(req, "mode", "periodic");
JAddStringToObject(req, "vseconds", "usb:900;high:900;normal:1800;low:7200");

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.location.mode"}
req["mode"] = "periodic"
req["vseconds"] = "usb:900;high:900;normal:1800;low:7200"

rsp = card.Transaction(req)
```

> **Note:**
>
> The voltage thresholds used to evaluate `vseconds` are configured via the [`card.voltage`](https://dev.blues.io/api-reference/notecard-api/card-requests.md#card-voltage) request’s `mode` argument (e.g. `"mode": "lipo"`).

## Sampling at Predefined Intervals

To activate the GPS module on the Notecard every 600 seconds (at most, and only if motion is detected), set `mode` to `periodic` and use the `seconds` argument in a `card.location.mode` request:

**JSON**

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

**C/C++**

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

NoteRequest(req);
```

**Python**

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

rsp = card.Transaction(req)
```

This will return an object confirming that the Notecard is in periodic mode and that GPS should be enabled no more frequently than once every 600 seconds:

```json
{
 "mode": "periodic",
 "seconds": 600
}
```

Once enabled, use the `card.location` request to monitor connection status and location:

**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)
```

While waiting for the Notecard to obtain a GPS fix, expect to see intermediate `status` messages in response to `card.location` requests:

```json
// When the module is still inactive.
{
  "status": "GPS inactive {gps-inactive}",
  "mode":   "periodic"
}
 
// When the module has started.
{
  "status": "GPS started {gps-active}",
  "mode":   "periodic"
}
 
// When the module is searching for GPS the response will include:
// - How long the current search has been running, in seconds.
// - The Signal-to-Noise Ratio (SNR) of the received satellite signals.
// - The number of satellites Notecard can currently see.
{
    "status": "GPS search (19 sec, 41dB SNR, 5 sats) {gps-active}
                {gps-signal} {gps-sats}",
    "mode":   "periodic"
}
```

You may see several variations of the third message before the module obtains a fix. Once obtained, future `card.location` requests include the current Notecard latitude (`lat`) and longitude (`lon`) values, as well as the Unix epoch time that location was captured.

```json
{
  "status": "GPS updated (58 sec, 41dB SNR, 9 sats) {gps-active}
            {gps-signal} {gps-sats} {gps}",
  "mode":   "periodic",
  "lat":    42.577600,
  "lon":    -70.871340,
  "time":   1598554399
}
```

> **Note:**
>
> To preserve battery, when the Notecard's GPS module is in periodic mode, GPS is only enabled if the built-in accelerometer detects movement since the last GPS enable. If the Notecard has not moved, a `card.location` request will indicate that GPS is inactive and provide the last location reading.
>
> ```json
> {
>  "status": "GPS inactive {gps-inactive} {gps}",
>  "mode": "periodic",
>  "lat": 42.5776,
>  "lon": -70.87134,
>  "time": 1598557149
> }
> ```

### Tracking GPS Location Readings

When operating in periodic mode, use the `card.location.track` request to configure the Notecard to store GPS readings in a Notefile. Note that the behavior in this section only applies to the capture of location events. The rules for how and when those events sync are the same as general sync settings defined with `hub.set`.

**JSON**

```json
{
  "req": "card.location.track",
  "start": true
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.location.track");
JAddBoolToObject(req, "start", true);

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.location.track"}
req["start"] = True

rsp = card.Transaction(req)
```

This will return an object confirming that tracking mode has started and the minimum duration in seconds between Notes being placed in a Notefile. The `seconds` value is the value set in a request to `card.location.mode`.

```json
{
 "seconds": 10,
 "start": true
}
```

By default, tracking notes are placed into a Notefile named `_track.qo`. To define your own Notefile, use the `file` argument.

**JSON**

```json
{
  "req": "card.location.track",
  "start": true,
  "file": "locations.qo"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.location.track");
JAddBoolToObject(req, "start", true);
JAddStringToObject(req, "file", "locations.qo");

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.location.track"}
req["start"] = True
req["file"] = "locations.qo"

rsp = card.Transaction(req)
```

> **Note:**
>
> Tracking data is available to view in Notehub, once synced, and includes a number of helpful fields that can be Routed to your cloud applications.
>
> ```json
> {
>  "bearing": 194.8890307950282,
>  "distance": 5.591816976119877,
>  "seconds": 36,
>  "hdop": 1,
>  "temperature": 49.625,
>  "time": 1598560691,
>  "usb": true,
>  "velocity": 0.014337992246461224,
>  "voltage": 4.727260437757979
> }
> ```

By default, Notecard captures tracking data only when it detects motion. To also capture periodic tracking Notes while stationary, set `heartbeat` to `true` and use `hours` to specify the interval. For example, the configuration below uses `heartbeat: true` and `hours: 24` to capture a tracking Note once per day, regardless of motion.

**JSON**

```json
{
  "req": "card.location.track",
  "start": true,
  "heartbeat": true,
  "hours": 24
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.location.track");
JAddBoolToObject(req, "start", true);
JAddBoolToObject(req, "heartbeat", true);
JAddNumberToObject(req, "hours", 24);

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.location.track"}
req["start"] = True
req["heartbeat"] = True
req["hours"] = 24

rsp = card.Transaction(req)
```

If you wish to initiate a sync to Notehub each time a tracking Note is added to the Notecard, set the `sync` field to `true`:

**JSON**

```json
{
  "req": "card.location.track",
  "sync": true
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.location.track");
JAddBoolToObject(req, "sync", true);

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.location.track"}
req["sync"] = True

rsp = card.Transaction(req)
```

To turn tracking mode off, set the `stop` argument to `true`.

**JSON**

```json
{
  "req": "card.location.track",
  "stop": true
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.location.track");
JAddBoolToObject(req, "stop", true);

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.location.track"}
req["stop"] = True

rsp = card.Transaction(req)
```

As of Notecard firmware v7.5.2, a user-defined `payload` argument (a base64-encoded binary payload) may be added to a `card.location.track` request. If supplied, the `payload` will be included in the next `_track.qo` Note.

This can be used to correlate a binary payload of data with the event's time and device's location while in tracking mode.

**JSON**

```json
{
  "req": "card.location.track",
  "payload": "ewogICAgInRlbXAiOiAyMy4xMzQKfQ=="
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.location.track");
// Notecard's C SDKs have helper methods that can help you generate these
// base64-encoded payloads. See the following for an example:
// https://gist.github.com/tjvantoll/28e70717143f3f8d5d3b71dc9e307861
JAddStringToObject(req, "payload", "ewogICAgInRlbXAiOiAyMy4xMzQKfQ==");

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.location.track"}
req["payload"] = "ewogICAgInRlbXAiOiAyMy4xMzQKfQ=="

rsp = card.Transaction(req)
```

## Always-on GPS With Continuous Mode

To set your Notecard to GPS Continuous mode, use the `card.location.mode` request:

**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)
```

Which will return an object confirming that the Notecard is in continuous mode:

```json
{"mode": "continuous"}
```

Once enabled, use the `card.location` request to monitor connection status and location:

**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)
```

While waiting for the Notecard to obtain a GPS fix, expect to see intermediate `status` messages in response to `card.location` requests.

> **Note:**
>
> The Notecard will not turn on the GPS module until it has made a successful cellular connection upon startup to obtain the current time. Once the Notecard has the time, GPS is available for use, regardless of the state of a cellular connection.

```json
// When the module is still inactive
{
  "status": "GPS inactive {gps-inactive}",
  "mode":   "continuous"
}
 
// When the module is active, but searching for GPS
{
    "status": "GPS search (19 sec, 41dB SNR, 5 sats) {gps-active}
                {gps-signal} {gps-sats}",
    "mode":   "continuous"
}
```

You may see several variations of the status message before the module obtains a fix. Once obtained, future `card.location` requests include the current Notecard latitude (`lat`) and longitude (`lon`) values, as well as the Unix epoch time that location was captured.

```json
{
  "status": "GPS updated (58 sec, 41dB SNR, 9 sats) {gps-active}
            {gps-signal} {gps-sats} {gps}",
  "mode":   "continuous",
  "lat":    42.577600,
  "lon":    -70.871340,
  "time":   1598554399
}
```

> **Warning:**
>
> **Continuous Cellular & Continuous GPS**
>
> The Notecard does not support running both a continuous cellular connection (`{"req":"hub.set", "mode":"continuous"}`) and continuous GPS. If you attempt to set both cellular and GPS to continuous mode, the Notecard will return an error. This applies both to `card.location.mode` when the cellular connection is continuous, as well as `hub.set` if GPS has been set in continuous mode.
>
> ```json
> {"err": "cannot simultaneously use continuous card.location.mode and hub.set modes"}
> ```
>
> If concurrent use of cellular and GPS is required in your solution, we recommend usage of an [external GPS module](https://dev.blues.io/notecard/notecard-walkthrough/working-with-the-notecard-aux-pins.md#using-aux-serial-gps-mode).

## Determining the Current GPS Mode

At any point, the GPS mode of the Notecard can be obtained by calling the `card.location.mode` command with no arguments.

**JSON**

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

**C/C++**

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

NoteRequest(req);
```

**Python**

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

rsp = card.Transaction(req)
```

This will return the current GPS mode alongside additional meta data if [geofencing](https://dev.blues.io/notecard/notecard-walkthrough/time-and-location-requests.md#geofencing-with-the-notecard) and/or [voltage-variable periods](https://dev.blues.io/notecard/notecard-walkthrough/low-power-firmware-design.md#sampling-at-voltage-variable-intervals) are enabled.

```json
{
  "mode": "continuous",
  "max": 100,
  "lat": 42.5776,
  "lon": -70.87134,
  "minutes": 2,
  "threshold": 4
}
```

## How Long a GPS Seek Runs

A single fix attempt (a "seek") is time-bounded by the Notecard itself, so a device that cannot see the sky will not leave its GPS module powered on indefinitely. Two thresholds apply, and both can be shortened with [reserved environment variables](https://dev.blues.io/guides-and-tutorials/notecard-guides/understanding-environment-variables.md#reserved-environment-variables) if the defaults are too long for your power budget:

| Behavior                                                                                                           | Default                            | Override              |
| ------------------------------------------------------------------------------------------------------------------ | ---------------------------------- | --------------------- |
| The seek expires and GPS is powered down, whether or not a fix was made.                                           | \~1,000 seconds (about 17 minutes) | `_gps_expiry_secs`    |
| The seek is abandoned early because the module has not tracked at least three satellites within the recent window. | 90 seconds                         | `_gps_no_signal_secs` |

## Geofencing With the Notecard

The Notecard can be configured to trigger a sync to Notehub when the device moves beyond a defined [geofence](https://en.wikipedia.org/wiki/Geo-fence). Use the `lat` and `lon` arguments to set the center of the geofence, and the `max` argument to specify the number of meters from the center. The optional `minutes` argument sets the geofence debounce period, and defaults to `5`.

> **Note:**
>
> `minutes` sets a debounce period for transitions across the geofence boundary. The Notecard reports a transition the first time a GPS fix lands on the opposite side of the boundary from the previous one, and then ignores further transitions for `minutes` minutes.
>
> Because only *changes* are reported, a device that crosses the boundary and then stays put triggers a single sync. Remaining outside the geofence does not trigger a new sync every `minutes` minutes. The debounce is there to limit chatter from a device sitting close enough to the boundary that GPS jitter repeatedly flips it from one side to the other. The debounce applies in both directions, to entering the geofence as well as leaving it.
>
> The `_gps_ring_secs` [reserved environment variable](https://dev.blues.io/guides-and-tutorials/notecard-guides/understanding-environment-variables.md#reserved-environment-variables) takes precedence over `minutes` if both are set.

**JSON**

```json
{
  "req": "card.location.mode",
  "mode": "periodic",
  "seconds": 300,
  "lat": 42.5776,
  "lon": -70.87134,
  "max": 100,
  "minutes": 2
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.location.mode");
JAddStringToObject(req, "mode", "periodic");
JAddNumberToObject(req, "seconds", 300);
JAddNumberToObject(req, "lat", 42.577600);
JAddNumberToObject(req, "lon", -70.871340);
JAddNumberToObject(req, "max", 100);
JAddNumberToObject(req, "minutes", 2);

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.location.mode"}
req["mode"] = "periodic"
req["seconds"] = 300
req["lat"] = 42.577600
req["lon"] = -70.871340
req["max"] = 100
req["minutes"] = 2

rsp = card.Transaction(req)
```

This will return an object confirming that the geofence is enabled using the parameters provided.

```json
{
 "max": 100,
 "mode": "periodic",
 "seconds": 300,
 "lat": 42.5776,
 "lon": -70.87134,
 "minutes": 2
}
```

## Location Privacy with GPS Fuzzing

In some applications, the precise location of a Notecard-powered device is sensitive information. A product's exact coordinates can be reverse-engineered to the household that owns it, a vehicle's coordinates can identify its driver, or an environmental sensor's exact location may make it a target for tampering. Data privacy regulations may also restrict how precisely device location can be reported.

To address these scenarios, Notecard supports "GPS fuzzing", a privacy feature that obfuscates reported GPS coordinates by snapping them to a coarser grid before they leave the device. The behavior is controlled by the `_gps_fuzz_degrees` [reserved environment variable](https://dev.blues.io/guides-and-tutorials/notecard-guides/understanding-environment-variables.md#reserved-environment-variables)

### How GPS Fuzzing Works

`_gps_fuzz_degrees` is a floating-point number of decimal degrees that sets the size of a grid. Notecard snaps the reported latitude and longitude to that grid by dropping the extra precision. For example, a value of `0.001` reduces each coordinate to three decimal places:

| Real coordinate | Reported coordinate |
| --------------- | ------------------- |
| `42.5771`       | `42.577`            |
| `-70.8722`      | `-70.872`           |

The larger the value, the coarser the grid and the less precise the reported location:

| Value    | Grid Size        | Reported precision                |
| -------- | ---------------- | --------------------------------- |
| `0.0001` | \~11 meters      | 4 decimal places (e.g. `42.5771`) |
| `0.001`  | \~110 meters     | 3 decimal places (e.g. `42.577`)  |
| `0.005`  | \~560 meters     | nearest multiple of `0.005`       |
| `0.01`   | \~1.1 kilometers | 2 decimal places (e.g. `42.57`)   |

When snapping a coordinate to the grid, Notecard and Notehub always drop the extra digits rather than rounding to the nearest grid line. In other words, `42.5779` becomes `42.577`, not `42.578`. For negative coordinates this means the value moves toward zero, so `-70.8729` becomes `-70.872`, not `-70.873`.

> **Note:**
>
> Fuzzing is applied at the read boundary, meaning any location data leaving Notecard (for example, via `card.location` or in a `_track.qo` Notefile) is grid-rounded. Notecard's internal motion detection and geofence logic continue to operate on the precise GPS fix, so features like [geofencing](https://dev.blues.io/notecard/notecard-walkthrough/time-and-location-requests.md#geofencing-with-the-notecard) remain accurate even when fuzzing is enabled.

### Fuzzing Cell Tower and WiFi Estimated Locations

`_gps_fuzz_degrees` also governs the precision of cell tower and WiFi estimated locations. These locations are derived by Notehub from scan data rather than computed on the device, so the same grid rounding is applied within Notehub. When `_gps_fuzz_degrees` is set for a device, Notehub quantizes the coordinates it computes (`tower_lat`/`tower_lon`, `tri_lat`/`tri_lon`, and the derived `best_lat`/`best_lon` fields) to the configured grid before storing them on the device or appending them to events.

In other words, `_gps_fuzz_degrees` is applied at two layers: on the Notecard for GPS/GNSS coordinates, and within Notehub for cell tower and WiFi estimated coordinates.

### Enabling GPS Fuzzing

`_gps_fuzz_degrees` can be set on a single Notecard with an `env.default` request, or applied to many devices at once by setting it as a project, fleet, or device-level [environment variable in Notehub](https://dev.blues.io/guides-and-tutorials/notecard-guides/understanding-environment-variables.md#setting-a-notehub-device-variable).

To enable fuzzing on a Notecard, send an `env.default` request with the desired grid size, in decimal degrees:

**JSON**

```json
{
  "req": "env.default",
  "name": "_gps_fuzz_degrees",
  "text": "0.001"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("env.default");
JAddStringToObject(req, "name", "_gps_fuzz_degrees");
JAddStringToObject(req, "text", "0.001");

NoteRequest(req);
```

**Python**

```python
req = {"req": "env.default"}
req["name"] = "_gps_fuzz_degrees"
req["text"] = "0.001"

rsp = card.Transaction(req)
```

After fuzzing is applied, a `card.location` request returns coordinates that have been quantized to the nearest multiple of the configured grid size:

```json
{
 "status": "GPS updated (58 sec, 41dB SNR, 9 sats) {gps-active} {gps}",
 "mode": "periodic",
 "lat": 42.577,
 "lon": -70.872,
 "time": 1598554399
}
```

To disable fuzzing, remove the variable by setting it to an empty string:

**JSON**

```json
{
  "req": "env.default",
  "name": "_gps_fuzz_degrees",
  "text": ""
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("env.default");
JAddStringToObject(req, "name", "_gps_fuzz_degrees");
JAddStringToObject(req, "text", "");

NoteRequest(req);
```

**Python**

```python
req = {"req": "env.default"}
req["name"] = "_gps_fuzz_degrees"
req["text"] = ""

rsp = card.Transaction(req)
```

## Disabling GPS

When you no longer need to capture GPS data from the Notecard, turn it off with a `card.location.mode` request and `mode` field set to `off`.

**JSON**

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

**C/C++**

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

NoteRequest(req);
```

**Python**

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

rsp = card.Transaction(req)
```

Which will return an object confirming that GPS is off:

```json
{"mode": "off"}
```

> **Note:**
>
> Even after GPS has been disabled, the Notecard keeps the last location obtained, which can be retrieved at any time with a `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)
> ```
>
> ```json
> {
>  "status": "GPS is off {gps-inactive} {gps}",
>  "mode": "off",
>  "lat": 42.5776,
>  "lon": -70.87134,
>  "time": 1598555070
> }
> ```

If you wish to delete the last known location stored in the Notecard, use the `delete` argument in a `card.location.mode` request.

**JSON**

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

**C/C++**

```cpp
J *req = NoteNewRequest("card.location.mode");
JAddBoolToObject(req, "delete", true);

NoteRequest(req);
```

**Python**

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

rsp = card.Transaction(req)
```

Subsequent requests to `card.location` no longer provide location data, until GPS is re-enabled and a new reading is captured.

```json
{
 "status": "GPS is off {gps-inactive} {gps}",
 "mode": "off"
}
```

[Essential Requests](https://dev.blues.io/notecard/notecard-walkthrough/essential-requests.md "Essential Requests") [Inbound Requests & Shared Data](https://dev.blues.io/notecard/notecard-walkthrough/inbound-requests-and-shared-data.md "Inbound Requests & Shared Data")
