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
vsstring-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.