Using the inMotion Data Logger
The Data Logger runs a station of sensors unattended on a small always-on machine – a Raspberry Pi, an industrial gateway, or similar – and forwards their readings to inMotion as a Site activity. It is a companion to inMotion Track (the phone app) for fixed installations where no phone is present.

Overview

A Python application for logging a station of sensors and publishing their readings to inMotion. A single YAML file declares the station: its location, its sensors, how readings are aggregated, and where they are published. Support for new hardware is added as a plugin, without modifying the core package.
  • Runs unattended – installed on a Pi or gateway and left running as a service.
  • BLE and MQTT sensors – the mqtt-generic plugin subscribes to a broker and drives a Device Config of type: mqtt; ble-generic drives a type: ble one.
  • Edge aggregation – means, extremes, and circular means are computed on the gateway over a rolling window before anything is sent.
  • Creates its own Site activity – the logger finds or creates a Site activity by name and writes records to it.
The Data Logger is not yet published to a public package index. Contact us for access.

When to Use It

Use the Data Logger when:
  • The site's connectivity is unreliable, or absent for hours at a time.
  • Several sensors at one location – say a weather station over MQTT, a soil probe over BLE, a tipping-bucket on a GPIO – should be aggregated and uploaded as one coherent Site activity.
  • You want a permanent local copy of every reading, independent of the cloud.
  • Aggregation should happen at the edge rather than in the platform.
If the site has a reliable connection and a single sensor, a direct SDK integration may be sufficient. The same Device Config works either way, so this choice can be revisited.

Describing a Station

One config file describes the station:
  • station – the name (this names the Site activity in inMotion), plus latitude, longitude, and altitude.
  • sensors – a list of plugin instances. Each mqtt-generic or ble-generic entry points at a Device Config file and the broker or device to read.
  • collectorlatest_period (snapshot cadence) and statistics_period (the aggregation window).
  • statistics – the reduction applied to each variable over the window (mean, minimum, maximum, last, circular_mean).
  • publish – where readings go: console for development, inmotion to forward to the platform, plus the durability options below.
station:
  name: "Backyard Weather - Unit 1"   # names the Site activity
  latitude: 51.5
  longitude: -0.1
  altitude: 12.0

sensors:
  - type: mqtt-generic
    params:
      device_config: device_configs/backyard-weather.yml
      broker: mqtt://localhost:1883
      topic_prefix: inmotion/backyard/unit-1
      username: ${MQTT_USERNAME}
      password: ${MQTT_PASSWORD}

statistics:
  airTemp: mean
  humidity: mean
  windSpeed: maximum
  windDir: circular_mean

collector:
  latest_period: 30 seconds
  statistics_period: 5 minutes

publish:
  reading_journal:                # pre-aggregate durability
    db_path: data-logger-readings.sqlite3
    retain: 30 minutes
  inmotion:                       # store-and-forward to the platform
    base_url:   ${INMOTION_BASE_URL}
    dev_key:    ${INMOTION_DEV_KEY}
    dev_secret: ${INMOTION_DEV_SECRET}
    api_key:    ${INMOTION_API_KEY}
    account:    ${INMOTION_ACCOUNT}
    queue_db_path: data-logger-queue.sqlite3
    retry_interval: 30 seconds
  history:                        # optional permanent local log
    db_path: data-logger-history.sqlite3
The logger finds an existing Site activity by station.name or creates one. The name identifies the activity; changing it creates a second activity, so choose it once.

Device Configs Are Shared With inMotion Track

A sensor's variables, decoding, and units are described by a Device Config – the same format used by My Device Configs in Studio and by inMotion Track's generic BLE reader. Define a device once and read it from any of them:
  • A type: ble config drives both the Data Logger's ble-generic sensor and the phone app.
  • A type: mqtt config drives the Data Logger's mqtt-generic sensor.
Don't fork the file per environment – keep one config per device and change only the broker host and credentials where it runs.

Reliable Publishing and Offline Durability

Two independent buffers cover different failure points, and the edge path uses both:
  • reading_journalpre-aggregate. Individual readings are journaled as they arrive, so a crash or power cut partway through a window doesn't lose the samples already in it. retain bounds how far back it keeps them.
  • queue_db_pathpost-aggregate. Each computed window is written to an on-disk queue and retried in order every retry_interval until inMotion acknowledges it. A multi-hour outage, or the process restarting during one, loses nothing.
history is separate again: a permanent local record of every reading regardless of network state, for offline review or a local dashboard.

Authentication on the Gateway

Forwarding to inMotion needs two credentials on the gateway, both created in Settings:
  • A Developer key (key + secret) with HMAC signing enabled – the SDK signs every request with it so inMotion can verify the body wasn't altered.
  • An API key (account key + api key) with at least Contributor access to the account the data belongs to.
All five of base_url, dev_key, dev_secret, api_key, and account must be set – an undefined value fails startup by design. Keep them in a permissions-restricted environment file, not in the YAML and not in version control.

Protect dev_secret. It is the one long-lived secret that lets requests be signed as your account. If the gateway is lost or compromised, revoke that Developer key in Settings.

See Data Platform for the full authentication model (Developer keys vs API keys, HMAC signing) and the Python SDK.

Setup

  1. Set up the gateway. Install the Data Logger with uv. For MQTT sensors, start a broker – the Data Logger includes a docker-compose.yml that starts a hardened Mosquitto alongside the logger (no anonymous access, a password file, localhost-published ports, a TLS template). Give each device its own broker account.
  2. Point the sensors at it. Configure the weather station (or other device) to publish to the local broker, using the same topic layout and payload it would use against the cloud.
  3. Write the station config. station.name / lat / lon / altitude, one mqtt-generic or ble-generic sensor per device pointing at its Device Config, then collector windows and per-variable statistics.
  4. Validate offline. Run data-logger validate --device-config <file> --broker mqtt://localhost:1883 --topic-prefix <prefix> --duration 2m with the device publishing. It reports decode results, range violations, and each aggregation window as it fires – no credentials, nothing sent. Fix the config here; data-logger reset clears local state to start clean.
  5. Enable forwarding. Add the publish.inmotion block (with queue_db_path and retry_interval) and publish.reading_journal; add publish.history for a permanent local log.
  6. Run in production. data-logger --config station.yaml. Confirm the Site activity appears in Studio, then disconnect the gateway's network for a few minutes and confirm the queue drains and backfills when it returns.
  7. Run as a service. Run it as a service (systemd) so it restarts on boot and on crash, keep the gateway clock synced with NTP (record timestamps come from the gateway), and watch queue depth as a health signal.

Next Steps