DataNet Python SDK
Async Python client for the DataNet realtime platform. Supports pub/sub over WebSocket with automatic reconnection and heartbeats. Payloads can be JSON values and nested data structures, bytes-like binary payloads, or content-type-labeled formats such as DMX, Art-Net, float vectors, BLE batches, and compact interaction frames.
Requirements
- Python 3.11+
aiohttp>= 3.9websockets>= 12.0
Installation
Install from PyPI:
pip install datanet-sdk
For local development from this repo:
pip install -e .[dev]
Quick start
Async pattern (recommended)
import asyncio
from datanet import DataNet
async def main():
dn = DataNet(api_key="ak_your_key_here")
async def on_message(data, meta):
print(f"[{meta.channel}] {data}")
async with dn: # connects, disconnects on exit
dn.subscribe("project.abc.sensor", on_message)
await asyncio.sleep(60) # keep running
asyncio.run(main())
Sync / background-thread pattern
For scripts that don't manage their own event loop:
import time
from datanet import DataNet
dn = DataNet(api_key="ak_your_key_here")
@dn.on("connect")
async def handle_connect():
print("Connected!")
@dn.on("error")
async def handle_error(exc):
print(f"Error: {exc}")
async def on_sensor(data, meta):
print(f"sensor reading: {data}")
dn.connect_sync() # blocks until connected, runs in bg thread
dn.subscribe("project.abc.sensor", on_sensor)
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
dn.disconnect_sync()
API reference
DataNet(api_key, device_id=None, client_id=None, device_name=None, api_url=..., ws_url=..., max_reconnect_attempts=5)
| Parameter | Default | Description |
|---|---|---|
api_key |
— | Your DataNet API key (ak_...) |
device_id |
— | Stable device identifier for presence/history |
client_id |
— | Optional app/client identifier |
device_name |
— | Optional display name for dashboards/admin tools |
api_url |
https://api.datanet.art |
REST API base URL |
ws_url |
wss://ws.datanet.art |
WebSocket base URL |
max_reconnect_attempts |
5 |
Max consecutive reconnects; 0 = unlimited |
Payload formats
The Python SDK supports the same protocol classes as the JavaScript SDK:
- JSON scalars, arrays, dictionaries, and nested structures via
publish(...). - Bytes-like values (
bytes,bytearray,memoryview) viapublish(...)auto-detection. - Explicit binary packets via
publish_binary(...). - DMX frames via
build_dmx_frame(...)/publish_dmx(...). - Art-Net ArtDMX packets via
build_art_dmx_packet(...)/publish_artnet(...). - Mixed JSON and binary subscriptions via
subscribe_any(...).
Binary messages include metadata with the packet: channel, from_,
timestamp, content_type, bytes, and optional custom metadata.
When connected to an older gateway that still emits raw binary WebSocket frames,
the SDK falls back safely and marks those messages with metadata={"raw": True}.
from datanet import DataNet, build_dmx_frame
dn = DataNet(api_key="ak_your_key_here")
frame = build_dmx_frame([255, 80, 20, 180], 512)
async with dn:
await dn.publish_binary(
"project.abc.lighting.dmx",
frame,
content_type="binary/dmx",
metadata={"universe": 1, "format": "dmx512"},
)
Local development
When you want to test against a local gateway instead of production, pass the URLs explicitly:
dn = DataNet(
api_key="ak_local_key_here",
api_url="http://localhost:8080",
ws_url="ws://localhost:8080",
)
The bundled examples automatically load configuration from a repo-level .env
file if present. Copy the template once, add your real key/channel values, and
keep .env local:
cp .env.example .env
The examples also support shell environment overrides, which take precedence
over values in .env:
DATANET_API_KEY='ak_local_key_here' \
DATANET_CHANNEL='demo.text.basic' \
DATANET_API_URL='http://localhost:8080' \
DATANET_WS_URL='ws://localhost:8080' \
python examples/publish.py
Binary examples
The JSON examples use DATANET_CHANNEL.
The binary DMX examples use DATANET_BINARY_CHANNEL first, then fall back to
DATANET_CHANNEL if no binary channel is set. Use the same binary channel for
both publisher and subscriber:
DATANET_API_KEY='ak_local_key_here' \
DATANET_BINARY_CHANNEL='project.abc.lighting.dmx' \
python examples/binary_dmx_subscribe.py
In another terminal:
DATANET_API_KEY='ak_local_key_here' \
DATANET_BINARY_CHANNEL='project.abc.lighting.dmx' \
python examples/binary_dmx_publish.py
To drive the browser p5 visualizer demo directly with pixel coordinates:
DATANET_API_KEY='ak_local_key_here' \
DATANET_CHANNEL='demo.text.basic' \
DATANET_API_URL='http://localhost:8080' \
DATANET_WS_URL='ws://localhost:8080' \
DATANET_X_MIN='0' \
DATANET_X_MAX='1000' \
DATANET_Y_MIN='0' \
DATANET_Y_MAX='450' \
python examples/publish_p5.py
Methods
| Method | Description |
|---|---|
await connect() |
Fetch JWT and open WebSocket |
connect_sync(timeout=10) |
Same, but runs in a background thread |
await disconnect() |
Close connection and stop run loop |
disconnect_sync(timeout=10) |
Close a sync/background-thread connection |
await get_presence(channel) |
Return authoritative {occupancy, members} presence data |
subscribe(channel, handler) |
Register an async message handler |
unsubscribe(channel, handler=None) |
Remove handler (or all) from channel |
await publish(channel, data, content_type=None, metadata=None) |
Send JSON, or auto-detect bytes-like binary data |
await publish_binary(channel, data, content_type=..., metadata=None) |
Send binary bytes with content type and metadata |
await publish_dmx(channel, values, length=512, metadata=None) |
Publish a clamped DMX frame as binary/dmx |
await publish_artnet(channel, dmx, ..., metadata=None) |
Publish an ArtDMX packet as binary/artnet |
subscribe_binary(channel, handler, content_type=None) |
Register an async binary handler |
subscribe_any(channel, handler) |
Register an async handler for JSON and binary messages |
on(event, handler) |
Register an event handler (decorator or direct) |
get_presence() reuses the JWT from connect(), requires the API key's
presence scope, and should be called occasionally or on a throttled timer:
presence = await dn.get_presence("project.abc.demo")
print(presence["occupancy"], presence["members"])
Events
| Event | Handler signature | Fired when |
|---|---|---|
"connect" |
async def() |
WebSocket connection established |
"disconnect" |
async def() |
Connection closed |
"error" |
async def(exc) |
An error occurs |
MessageMeta
Passed as the second argument to every message handler:
@dataclass
class MessageMeta:
channel: str # e.g. "project.abc.sensor"
from_: str # sender connection ID
timestamp: int # Unix timestamp (ms) from the server
BinaryMessageMeta
Passed as the second argument to every binary message handler:
@dataclass
class BinaryMessageMeta:
channel: str
from_: str
timestamp: int
content_type: str
bytes: int
metadata: dict | None = None
Reconnection
The SDK reconnects automatically with exponential backoff:
| Attempt | Delay |
|---|---|
| 1st | 1 s |
| 2nd | 2 s |
| 3rd | 4 s |
| 4th | 8 s |
| 5th | 16 s |
| subsequent | capped at 30 s |
All subscriptions are replayed after each reconnect.
Logging
The SDK uses Python's standard logging module under the logger name datanet.client.
import logging
logging.basicConfig(level=logging.DEBUG)
Examples
See the examples/ directory:
basic_subscribe.py— subscribe and print messagespublish.py— publish simulated sensor readingspublish_p5.py— publish p5-stylex/ycoordinatesbinary_dmx_publish.py— publish binary DMX framesbinary_dmx_subscribe.py— subscribe to binary DMX frames
Standalone showcase projects that use the published package live in datanet-examples.
For custom clients or other SDK implementations, see PROTOCOL.md.
Tests
python -m pip install -e .[dev]
python -m pytest
About
DataNet is developed and supported by Studio Jordan Shaw, a creative technology studio building tools for realtime, networked, and physical-digital work.
- DataNet: datanet.art
- Studio: jordanshaw.com
- Instagram: @jshaw3
- GitHub: datanet-art
- Source: datanet-python
- Examples: datanet-examples
License
MIT
Release files for datanet-sdk 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| datanet_sdk-0.1.1.tar.gz | 27.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| datanet_sdk-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 43.7 kB
Release files / datanet_sdk-0.1.1.tar.gz
| Download URL | datanet_sdk-0.1.1.tar.gz |
|---|---|
| Size | 27.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d5e7cc8e1cdf3b7c8699068405a3d22afd97ac8d06e6c94b1f04bcc0808a53f8
|
|
BLAKE2b-256 checksum How to use checksums |
22be9a625678d499deb1d887385b1e64047a49b76a77d025a59d2714e1917f91
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 18, 2026.
Transparency logRelease files / datanet_sdk-0.1.1-py3-none-any.whl
| Download URL | datanet_sdk-0.1.1-py3-none-any.whl |
|---|---|
| Size | 16.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
928cda3729c256312bdfb61eadbb8fb9150343802f80305fff516299e9a1c6d8
|
|
BLAKE2b-256 checksum How to use checksums |
928c83bceb282c5f2207a48c6eacaa099d689cf8029d552917a26c889d3aa47c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 18, 2026.
Transparency log