Skip to main content

Otensor Python SDK — para makers com hardware Linux/Raspberry Pi

Project description

otensor-sdk

PyPI Python License

Python SDK that runs on your device — publishes telemetry and receives commands from the Otensor IoT platform. Built for makers on Raspberry Pi and other Linux hardware.

PT-BR — SDK Python que roda no dispositivo: publica telemetria e recebe comandos da plataforma Otensor. Feito para makers com Raspberry Pi e outro hardware Linux. A documentação abaixo está em inglês.

from otensor_sdk import OtensorSDK

device = OtensorSDK(api_base_url=..., api_key=..., device_id=...).connect()
sensor = device.slot("main")

sensor.publish_property("temperature", 24.5)

@sensor.on_action("set_pixels")
def light_up(payload: dict) -> None:
    print("platform asked for:", payload)

Which package do I need?

Otensor ships two Python packages with different jobs:

otensor-sdk (this one) otensor
Runs On the hardware (Raspberry Pi, Linux board) Anywhere (laptop, server)
Job Publish telemetry, execute commands React to events, write automations
Talks to MQTT broker + REST API REST API

Use both if you want a device that reports data and logic that reacts to it. They are independent — neither requires the other.

Requirements

  • Python 3.11+
  • An Otensor instance (self-hosted or managed)
  • An API key (sk-…) and a device registered in the dashboard

Install

pip install otensor-sdk

Hardware wrappers (otensor_sdk.sensehat, otensor_sdk.gpio) rely on sense-hat and gpiozero, which ship with Raspberry Pi OS. They are not pip dependencies of this package, so installing here never drags in hardware libraries you don't need.

Configuration

API_BASE_URL=https://api.your-otensor.example   # or http://localhost:8000
API_KEY=sk-...
DEVICE_ID=...

Quick start

import os
from otensor_sdk import OtensorSDK

sdk = OtensorSDK(
    api_base_url=os.environ["API_BASE_URL"],
    api_key=os.environ["API_KEY"],
    device_id=os.environ["DEVICE_ID"],
)

device = sdk.connect()          # fetches MQTT credentials and connects
main = device.slot("main")      # a slot is one capability of the device

# Register handlers BEFORE publishing, so a command arriving right after
# connect() is not missed.
@main.on_action("set_pixels")
def handle_set_pixels(payload: dict) -> None:
    print("light up:", payload)

main.publish_property("temperature", 24.5)

Slots

A device declares capabilities, each bound to a named slot — a board can carry a sensor unit on main, a relay on relay1 and a motion sensor on pir1 at the same time. Properties and actions are always scoped to a slot, so the platform validates each reading against the right schema.

device.slot("main").publish_property("humidity", 61.2)
device.slot("relay1").publish_property("state", True)

Publishing on a schedule

TelemetryPublisher groups every source into one message per tick, instead of one message per property:

from otensor_sdk import TelemetryPublisher

publisher = TelemetryPublisher(device, interval=5.0)
publisher.set_source("main", "temperature", read_temperature)
publisher.set_source("main", "humidity", read_humidity)

publisher.run_forever()          # blocks until Ctrl-C
# publisher.publish_once()       # or drive the loop yourself

Complete example — no hardware required

Runs anywhere with simulated sensors, so you can see the full loop before touching a Raspberry Pi:

import os
import random
from otensor_sdk import OtensorSDK, TelemetryPublisher

sdk = OtensorSDK(
    api_base_url=os.environ["API_BASE_URL"],
    api_key=os.environ["API_KEY"],
    device_id=os.environ["DEVICE_ID"],
)

device = sdk.connect()
main = device.slot("main")

@main.on_action("set_pixels")
def set_pixels(payload: dict) -> None:
    print("LED matrix ->", payload.get("pixels"))

@main.on_action("clear_display")
def clear_display(payload: dict) -> None:
    print("LED matrix cleared")

publisher = TelemetryPublisher(device, interval=5.0)
publisher.set_source("main", "temperature", lambda: round(random.uniform(18, 32), 1))
publisher.set_source("main", "humidity", lambda: round(random.uniform(40, 80), 1))

try:
    publisher.run_forever()
except KeyboardInterrupt:
    device.disconnect()

Raspberry Pi hardware

from otensor_sdk.sensehat import SenseHatUnit
from otensor_sdk.gpio import DigitalInput, DigitalOutput

unit = SenseHatUnit()
unit.bind("main", device, publisher)          # sensors + LED matrix, wired in one call

DigitalOutput(pin=17).bind("relay1", device)  # actions: turn_on / turn_off / toggle
DigitalInput(pin=4).bind("pir1", device)      # publishes motion_detected on edge

bind() registers the action handlers and the telemetry sources for that slot, so you don't wire each property by hand.

Reliability

Built for devices that stay online for weeks on flaky networks:

  • Reconnect-safe commands — the cmd topic is re-subscribed on every connect, including automatic reconnects. Without this, telemetry keeps flowing while commands go silently mute after the first network blip.
  • State republishdevice.on_reconnect(fn) fires on first connect and every reconnect. Hardware wrappers use it to re-publish current state, which the dashboard would otherwise show as stale until the next physical change.
  • Last Will — the broker marks the device offline if it drops without a clean disconnect.
  • Local ackdevice.on_ack(fn) fires in-process the moment this device confirms a command, with {commandId, slot, action, success, error?}. Lets local code know its own command finished without a REST round-trip.

API reference

Symbol Purpose
OtensorSDK(api_base_url, api_key, device_id) Entry point; holds credentials
.connect() -> Device Fetches MQTT session and connects
Device.slot(name) -> SlotHandle Handle scoped to one capability
Device.publish_telemetry(nested) Publish {slot: {property: value}} directly
Device.on_reconnect(fn) / .on_ack(fn) Lifecycle callbacks
Device.disconnect() Stop the MQTT loop
SlotHandle.publish_property(name, value) One reading for this slot
SlotHandle.on_action(name) Decorator registering a command handler
TelemetryPublisher(device, interval) Batched periodic publishing
.set_source(slot, property, fn) Register a value producer
.run_forever() / .publish_once() Drive the publish loop

Exceptions: OtensorError (base), OtensorAuthError, OtensorSessionError, OtensorHardwareError.

Versioning

Semantic versioning. While on 0.x, a minor bump may carry breaking changes — pin the minor version in production:

otensor-sdk~=0.2.0

License

MIT

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

otensor_sdk-0.2.0.tar.gz (80.0 kB view details)

Uploaded Source

Built Distribution

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

otensor_sdk-0.2.0-py3-none-any.whl (14.4 kB view details)

Uploaded Python 3

File details

Details for the file otensor_sdk-0.2.0.tar.gz.

File metadata

  • Download URL: otensor_sdk-0.2.0.tar.gz
  • Upload date:
  • Size: 80.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for otensor_sdk-0.2.0.tar.gz
Algorithm Hash digest
SHA256 56f9380da61adb7d1b0a665d162d0924ca24fe0aedf32c25ba88841a14317f40
MD5 7dfe403b1da7a36815ddf3f9fab1362c
BLAKE2b-256 66d9ba45a054e0a52673e967ae279430339dd71a80da231b5ef910d5121f96c2

See more details on using hashes here.

Provenance

The following attestation bundles were made for otensor_sdk-0.2.0.tar.gz:

Publisher: publish-sdk-python.yml on Oseiasdfarias/otensor-platform

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file otensor_sdk-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: otensor_sdk-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 14.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for otensor_sdk-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 613616c0ad2091d4419c21b51e2c404c7f4b485dc13f5de4673c62f8bd18fa2c
MD5 393ec88cbe17b9db0efb1ff010a8b5b5
BLAKE2b-256 f1a2a5730a59fce7a5ba7d587037a9580b81c9459e3a44d1d2a23b1062fcc567

See more details on using hashes here.

Provenance

The following attestation bundles were made for otensor_sdk-0.2.0-py3-none-any.whl:

Publisher: publish-sdk-python.yml on Oseiasdfarias/otensor-platform

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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