RelayX Device SDK for Python
Official Python SDK for connecting IoT devices to the RelayX platform.
Installation
pip install relayx_device_sdk
Quick Start
import asyncio
from relayx_device_sdk import RelayDevice
device = RelayDevice({
"api_key": "<YOUR_API_KEY>",
"secret": "<YOUR_SECRET>",
"mode": "production", # or "test"
})
async def main():
await device.connect()
# Publish telemetry
await device.telemetry.publish("temperature", 22.5)
# Emit logs (batched to backend, mirrored to console)
device.log.info("device booted")
device.log.warn("disk usage at", 87, "%")
# Listen for RPC calls
async def on_reboot(req):
print("Reboot requested:", req.payload)
await req.respond({"status": "rebooting"})
await device.rpc.listen("reboot", on_reboot)
# Listen for commands
def on_firmware_update(msg):
print("Firmware update:", msg.payload)
await device.command.listen("firmware_update", on_firmware_update)
# Disconnect when done
await device.disconnect()
asyncio.run(main())
Configuration
device = RelayDevice({
"api_key": "<YOUR_API_KEY>", # JWT issued by RelayX
"secret": "<YOUR_SECRET>", # NKEY seed
"mode": "production", # "production" | "test"
})
Functionality
Connection
await device.connect() # returns True on success, False if already connected or failed
await device.disconnect() # drains NATS connection, cleans up consumers
# Listen for connection status changes
device.connection.listeners(lambda event: print("Status:", event["type"]))
# event["type"]: "connected" | "disconnected" | "reconnecting" | "reconnected" | "auth_failed"
Telemetry
Fire-and-forget sensor data publishing. Readings are validated against the device schema fetched on connect.
await device.telemetry.publish("temperature", 22.5) # number
await device.telemetry.publish("status", "online") # string
await device.telemetry.publish("active", True) # boolean
await device.telemetry.publish("metadata", {"fw": "1.2"}) # json
Each message is published with a server-synced timestamp.
Schema validation: On connect, the SDK fetches the device schema from the server. If a schema exists, publish() will throw a ValidationError if the metric name is not in the schema or the reading type does not match.
Remote Procedure Calls (RPC)
Register handlers for incoming RPC calls.
# Register a handler
async def on_get_status(req):
print("Payload:", req.payload)
# Respond with success
await req.respond({"uptime": 12345})
# Or respond with error
# await req.error({"code": "UNAVAILABLE", "message": "Device busy"})
await device.rpc.listen("get_status", on_get_status)
# Unregister
await device.rpc.off("get_status")
Duplicate listeners for the same name throw DuplicateListenerError.
Commands
One-way commands delivered for long running tasks that do not require a status update.
def on_firmware_update(msg):
print("Command:", msg.payload)
# Process based on data...
await device.command.listen("firmware_update", on_firmware_update)
await device.command.off("firmware_update")
Config
Get and set device configuration
# Fetch current config
config = await device.config.get()
print(config)
# Update config
success = await device.config.set({"interval": 10000, "name": "sensor-1"})
Events
Fire-and-forget event publishing of events (fault codes, etc).
await device.event.send("door_opened", {"door_id": "front", "timestamp": device.time.now()})
Logs
Structured device logging with three levels (info, warn, error). Each
call accepts a variadic argument list — strings, numbers, booleans, plain
dicts, lists, datetimes, None, and exception instances are all accepted;
callables and other non-serializable values raise ValidationError.
device.log.info("hello world")
device.log.info("a number reading", 42)
device.log.warn("careful — disk usage at 87%")
device.log.error("parse failed", ValueError("bad json"))
device.log.info("an object", {"port": 8080, "retries": 3})
Locally, each call also mirrors to Python's standard logging module
(at INFO/WARNING/ERROR) so you keep your normal dev experience.
Batching. Entries are buffered in memory and flushed to the backend either
when 15 entries accumulate or after 5 seconds, whichever comes first.
disconnect() flushes any pending buffer.
Time
NTP-synchronized clock. Syncs with time.google.com on connect and every 3 hours. Auto-resyncs on reconnect if stale.
# Initialize (called automatically on connect)
await device.time.init()
# Get current server-corrected timestamp (ms)
now = device.time.now()
# Convert SDK timestamp to datetime
dt = device.time.to_date(now)
# Convert datetime to SDK timestamp
ts = device.time.to_timestamp(datetime.now())
# Set timezone for display
device.time.set_timezone("America/New_York")
Error Handling
The SDK exports four error types:
from relayx_device_sdk import (
NotConnectedError, # Operation attempted while disconnected
DuplicateListenerError, # rpc.listen() or command.listen() called twice for same name
ValidationError, # Invalid arguments or schema mismatch
TimeoutError, # Request/reply timed out
)
Offline Behavior
- Telemetry & Events (
publish): Messages are buffered in memory while disconnected and flushed automatically on reconnect. - Logs (
device.log.*): Entries are buffered and flushed on the same 15-entry / 5-second policy. Any buffer left atdisconnect()is flushed before the connection drains. - RPC & Commands (
listen): ThrowNotConnectedErrorif transport is disconnected. - Config (
get/set): ThrowNotConnectedErrorif transport is disconnected.
Testing
pytest
The SDK is designed for full unit testability. All subsystems accept a transport dependency that can be mocked:
from relayx_device_sdk import RelayDevice
mock_transport = ... # mock methods
device = RelayDevice._create_for_test(
{"api_key": "test", "secret": "test", "mode": "test"},
mock_transport,
)
License
Apache-2.0
Metadata
Release files for relayx-device-sdk 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| relayx_device_sdk-0.1.2.tar.gz | 20.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| relayx_device_sdk-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 41.9 kB
Release files / relayx_device_sdk-0.1.2.tar.gz
| Download URL | relayx_device_sdk-0.1.2.tar.gz |
|---|---|
| Size | 20.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
01e3d3faff13317006b3a9effba06b86c18f7cf991bceca77703acab3d146bed
|
|
BLAKE2b-256 checksum How to use checksums |
2133054b51a993cb731b0dda8e970ddef6317fa33ba1cebfc1056e56a990203c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.4
|
Release files / relayx_device_sdk-0.1.2-py3-none-any.whl
| Download URL | relayx_device_sdk-0.1.2-py3-none-any.whl |
|---|---|
| Size | 21.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
876b62fd9f8e8da6769e654ac0717fc5ae00d72a877ba13102a4c181ed870296
|
|
BLAKE2b-256 checksum How to use checksums |
b9f7d3f3e8a7c3a4f439587d5a86fcb421027af93e2386c1e3de6c875e00c735
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.4
|