Skip to main content

RelayX Device SDK for Python — IoT device communication over NATS

Project description

RelayX Device SDK for Python

Official Python SDK for connecting IoT devices to the RelayX platform.

View Full Documentation →

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 at disconnect() is flushed before the connection drains.
  • RPC & Commands (listen): Throw NotConnectedError if transport is disconnected.
  • Config (get/set): Throw NotConnectedError if 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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

relayx_device_sdk-0.1.1.tar.gz (19.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

relayx_device_sdk-0.1.1-py3-none-any.whl (21.7 kB view details)

Uploaded Python 3

File details

Details for the file relayx_device_sdk-0.1.1.tar.gz.

File metadata

  • Download URL: relayx_device_sdk-0.1.1.tar.gz
  • Upload date:
  • Size: 19.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.4

File hashes

Hashes for relayx_device_sdk-0.1.1.tar.gz
Algorithm Hash digest
SHA256 64cc99bed7c68b543ce88ee3ce520de83227edebebede47d38714df8eb4644d8
MD5 0f6edb468d6a5b528ba04248ae1f7449
BLAKE2b-256 67435b3234a8af2a32f1257bb0c0fc8d15f918bb68340508bb5252b8256e5480

See more details on using hashes here.

File details

Details for the file relayx_device_sdk-0.1.1-py3-none-any.whl.

File metadata

File hashes

Hashes for relayx_device_sdk-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 aa7c9625f4705e8156d5d02147ae76e83e060c27ba3308cc60a7aeb8f73cd387
MD5 316d5c182df3a5532337d6c75340f1b8
BLAKE2b-256 fd9a9ae242cda9e480bbc8b4366657ed9e5f1517b74ddbab7910c6b4c8373d56

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page