Skip to content

NATS Messaging

Why NATS

NATS is a lightweight, high-performance pub/sub messaging system. On an edge device with limited resources, it provides:

  • Low overhead — the broker runs in a few megabytes of RAM
  • No per-message storage — no queue persistence needed for real-time sensor data
  • Subject-based routing — services subscribe to specific topic patterns
  • Request/reply — synchronous command/response without additional infrastructure

The ToloMEO platform uses NATS as the transport between edge devices and the cloud. Py ToloMEO uses the nats-py async client wrapped by NATSMessageStrategy.

Topic Naming Convention

Topics are prefixed by category. Service-addressed topics include {service} as the second segment; broadcast event topics do not:

Subject Category Owner Description
commands.{service}.req commands Service Inbound commands from operator
events.data events Service Outbound sensor readings
events.params events Service Outbound command responses
events.infos events Service Outbound OTA status and info events
heartbeat.{service}.service heartbeat Service Liveness pulse every 10 s

Why SenML

SenML (RFC 8428) is a standard format for IoT sensor measurements. Py ToloMEO uses a SenML-inspired structure because:

  • Standardised — well-understood in the IoT ecosystem
  • Compact — short field names (bn, n, v, u, t)
  • Extensible — the vs string-value field carries JSON command payloads without breaking the SenML schema

The vs field holding a JSON string (not a nested object) is an explicit design choice: it keeps the outer SenML record valid and makes it straightforward to add new command types without modifying the outer envelope.

Synchronous Reply-To

NATS supports a reply-to subject pattern for synchronous request/response. NATSService.remote_handler always publishes the command response to events.params; when the inbound message carries a reply-to value, that value is passed through to the underlying NATS publish call as request/reply correlation metadata (the message's Reply-To field), not as an alternative publish destination. This lets an operator correlate the response with the originating request without changing where the response is published.