Otensor Python SDK — para makers com hardware Linux/Raspberry Pi
Project description
otensor-sdk
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
cmdtopic 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 republish —
device.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 ack —
device.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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
56f9380da61adb7d1b0a665d162d0924ca24fe0aedf32c25ba88841a14317f40
|
|
| MD5 |
7dfe403b1da7a36815ddf3f9fab1362c
|
|
| BLAKE2b-256 |
66d9ba45a054e0a52673e967ae279430339dd71a80da231b5ef910d5121f96c2
|
Provenance
The following attestation bundles were made for otensor_sdk-0.2.0.tar.gz:
Publisher:
publish-sdk-python.yml on Oseiasdfarias/otensor-platform
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
otensor_sdk-0.2.0.tar.gz -
Subject digest:
56f9380da61adb7d1b0a665d162d0924ca24fe0aedf32c25ba88841a14317f40 - Sigstore transparency entry: 2210040256
- Sigstore integration time:
-
Permalink:
Oseiasdfarias/otensor-platform@bf26938b9ec435a870ed3c79674e816d53102412 -
Branch / Tag:
refs/tags/sdk-python-v0.2.0 - Owner: https://github.com/Oseiasdfarias
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-sdk-python.yml@bf26938b9ec435a870ed3c79674e816d53102412 -
Trigger Event:
push
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
613616c0ad2091d4419c21b51e2c404c7f4b485dc13f5de4673c62f8bd18fa2c
|
|
| MD5 |
393ec88cbe17b9db0efb1ff010a8b5b5
|
|
| BLAKE2b-256 |
f1a2a5730a59fce7a5ba7d587037a9580b81c9459e3a44d1d2a23b1062fcc567
|
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
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
otensor_sdk-0.2.0-py3-none-any.whl -
Subject digest:
613616c0ad2091d4419c21b51e2c404c7f4b485dc13f5de4673c62f8bd18fa2c - Sigstore transparency entry: 2210040271
- Sigstore integration time:
-
Permalink:
Oseiasdfarias/otensor-platform@bf26938b9ec435a870ed3c79674e816d53102412 -
Branch / Tag:
refs/tags/sdk-python-v0.2.0 - Owner: https://github.com/Oseiasdfarias
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-sdk-python.yml@bf26938b9ec435a870ed3c79674e816d53102412 -
Trigger Event:
push
-
Statement type: