A client library for accessing Dali IoT
Project description
Lunatone Dali-2 IoT
Typed Python client for the Lunatone DALI-2 IoT gateway, covering both the REST API and the streaming WebSocket API.
Features
- Sync (
Client) and async (AsyncClient) HTTP clients — one method per OpenAPI operation, all 71 of them. - Async streaming
WebSocketClientwith one typed dataclass per wire event (devices, zones, sequences, schedulers, circadians, trigger actions, DALI bus traffic, datetime, ping, message flash). - Typed dataclasses for every request body and response (
Device,Zone,Scheduler,ControlData,Info,EthernetSettings, …) — noAny, no dict guessing. - Single source of truth: the REST shapes mirror
openapi.json; the WebSocket shapes mirror the streaming JSON protocol the gateway emits on its rootws://endpoint.
Installation
pip install lunatone-dali2-iot
REST API
Synchronous
from dali2iot import Client, ControlData, Kelvin, RGB
with Client(base_url="http://192.168.1.41") as client:
for device in client.list_devices():
print(f"#{device.id} {device.name} — {device.dali_types}")
client.update_device(1, name="Hall light", groups=[0, 1])
# Apply RGB at 100 % brightness
client.control_device(1, ControlData(dimmable_rgb=RGB(r=1, g=0, b=0, dimmable=100)))
# Or warm white at 30 %
client.control_device(1, ControlData(dimmable_kelvin=Kelvin(kelvin=2700, dimmable=30)))
Asynchronous
import asyncio
from dali2iot import AsyncClient, ControlData
async def main() -> None:
async with AsyncClient(base_url="http://192.168.1.41") as client:
for device in await client.list_devices():
print(device.id, device.name)
await client.control_device(1, ControlData(dimmable=50))
asyncio.run(main())
Coverage
Every operation in openapi.json has a method on both clients, grouped by tag:
| Tag | Methods |
|---|---|
devices |
list_devices, get_device, update_device, delete_device, delete_all_devices |
control |
control_device, control_group, control_zone, control_broadcast |
zones |
list_zones, get_zone, create_zone, update_zone, delete_zone, delete_all_zones |
dali (scan) |
get_scan, start_scan, cancel_scan |
link |
enable_linking, disable_linking |
info / system |
get_info, update_info, reset, reboot |
datetime / location |
get_datetime, set_datetime, get_timezones, get_location, set_location, detect_location |
settings / ethernet |
get_settings, update_settings, get_ethernet, update_ethernet |
email |
get_email_settings, update_email_settings, test_email_settings |
sensors |
list_sensors, get_sensor, refresh_sensors, refresh_sensor |
sequencer |
list_sequences, get_sequence, create_sequence, update_sequence, delete_sequence, start_sequence, stop_sequence, get_test_sequence, update_test_sequence |
circadian |
list_circadians, get_circadian, create_circadian, update_circadian, delete_circadian, start_circadian, stop_circadian |
scheduler |
list_schedules, get_scheduler, create_scheduler, update_scheduler, delete_scheduler, start_scheduler, stop_scheduler |
trigger-actions |
list_trigger_actions, get_trigger_action, create_trigger_action, update_trigger_action, delete_trigger_action, start_trigger_action, stop_trigger_action |
WebSocket API
The gateway streams JSON events covering device updates, automation changes, raw DALI bus traffic, and connection health. Every wire event has a typed class — use match/isinstance to dispatch.
import asyncio
from dali2iot import (
DevicesEvent,
DevicesDeletedEvent,
PingEvent,
ScanProgressEvent,
WebSocketClient,
)
async def main() -> None:
async with WebSocketClient(base_url="http://192.168.1.41") as ws:
async for event in ws:
match event:
case DevicesEvent(devices=devs):
for d in devs:
print("device update:", d.id, d.features)
case DevicesDeletedEvent(deleted=ids):
print("forgotten:", ids)
case ScanProgressEvent(scan=scan):
print(f"scan {scan.progress * 100:.0f}% — {scan.status}")
case PingEvent(echo=msg):
print("ping", msg)
asyncio.run(main())
Filtering noisy events
from dali2iot import Filter, WebSocketClient
async with WebSocketClient(base_url="http://192.168.1.41") as ws:
await ws.set_filter(Filter(dali_monitor=True)) # suppress DaliMonitorEvent
Direct DALI bus access
from dali2iot import DaliFrame, DaliFrameMode, WebSocketClient, DaliAnswerEvent
async with WebSocketClient(base_url="http://192.168.1.41") as ws:
# QUERY CONTROL GEAR PRESENT to address 0
await ws.send_dali_frame(DaliFrame(
line=0, number_of_bits=16,
mode=DaliFrameMode(wait_for_answer=True, priority=3),
dali_data=[1, 145],
))
async for event in ws:
if isinstance(event, DaliAnswerEvent):
print("bus replied:", event.dali_data)
break
Event types
InfoEvent, PingEvent, MessageFlashEvent, DateTimeEvent, DaliStatusEvent, DaliMonitorEvent, DaliFrameEvent, DaliAnswerEvent, ScanProgressEvent, DevicesEvent / DevicesDeletedEvent, ZonesEvent / ZonesDeletedEvent, SequencesEvent / SequencesDeletedEvent, SchedulersEvent / SchedulersDeletedEvent, CircadiansEvent / CircadiansDeletedEvent, TriggerActionsEvent / TriggerActionsDeletedEvent, plus UnknownEvent for anything new.
Project layout
dali2iot/
__init__.py # public re-exports
client.py # Client + AsyncClient (REST)
websocket.py # WebSocketClient + 21 event classes
models.py # typed dataclasses for every entity / request body
errors.py # ApiError, DaliIotError
openapi.json # REST schema reference
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
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 lunatone_dali2_iot-2.1.0.tar.gz.
File metadata
- Download URL: lunatone_dali2_iot-2.1.0.tar.gz
- Upload date:
- Size: 29.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8e5633e20d0647132ba268c51145eec270e9330b375887fb5cee78d674e5589c
|
|
| MD5 |
ec88b28cded831a3acec7235e13880b7
|
|
| BLAKE2b-256 |
bb1c3f5c576efd0ca18641eb1017b2de2f4c067d0e20997c7cc8aeaf6ceaf7bb
|
Provenance
The following attestation bundles were made for lunatone_dali2_iot-2.1.0.tar.gz:
Publisher:
publish-package.yml on KiraLT/lunatone-dali2-iot
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lunatone_dali2_iot-2.1.0.tar.gz -
Subject digest:
8e5633e20d0647132ba268c51145eec270e9330b375887fb5cee78d674e5589c - Sigstore transparency entry: 1441561262
- Sigstore integration time:
-
Permalink:
KiraLT/lunatone-dali2-iot@bc7d14a58424affb3de9ca9813bfda2dbd919551 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/KiraLT
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-package.yml@bc7d14a58424affb3de9ca9813bfda2dbd919551 -
Trigger Event:
push
-
Statement type:
File details
Details for the file lunatone_dali2_iot-2.1.0-py3-none-any.whl.
File metadata
- Download URL: lunatone_dali2_iot-2.1.0-py3-none-any.whl
- Upload date:
- Size: 30.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bb72e1f17630ed08fb200f78bd514a6db7a6c7c6660971f8234034adf2b23f13
|
|
| MD5 |
8bce1145082bc698c2352b1bd448a43d
|
|
| BLAKE2b-256 |
f4969f2dbc6acdad0bf9539219f186706c21f82559cb983c6acba8b44ac0ceb5
|
Provenance
The following attestation bundles were made for lunatone_dali2_iot-2.1.0-py3-none-any.whl:
Publisher:
publish-package.yml on KiraLT/lunatone-dali2-iot
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lunatone_dali2_iot-2.1.0-py3-none-any.whl -
Subject digest:
bb72e1f17630ed08fb200f78bd514a6db7a6c7c6660971f8234034adf2b23f13 - Sigstore transparency entry: 1441561440
- Sigstore integration time:
-
Permalink:
KiraLT/lunatone-dali2-iot@bc7d14a58424affb3de9ca9813bfda2dbd919551 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/KiraLT
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-package.yml@bc7d14a58424affb3de9ca9813bfda2dbd919551 -
Trigger Event:
push
-
Statement type: