lorawan-connection
Documentation · Building a device library
Backend-neutral LoRaWAN events and device collections for Python 3.12+. The base package has no runtime dependencies. Install the optional ChirpStack or The Things Stack backend to connect to a server.
A vendor DeviceCollection creates supported models and routes incoming events
to them automatically. Applications use device-added callbacks to observe those
models and subscribe to their state updates.
With a connection already created, declare and use the models your library supports:
from lorawan_connection import Device, DeviceCollection, DeviceDescriptor, DeviceEvent
class Sensor(Device):
identifiers = {
"chirpstack": (123, "known-model"),
"tts": ("example-brand", "known-model"),
}
def __init__(self, descriptor: DeviceDescriptor) -> None:
super().__init__(descriptor)
self.temperature: float | None = None
self.humidity: float | None = None
def handle_event(self, event: DeviceEvent) -> None:
# Decode an event, update model attributes, then call self.notify().
pass
class Sensors(DeviceCollection[Sensor]):
DEVICES = (Sensor,)
sensors = Sensors(connection)
unsubscribe = sensors.subscribe_device_added(
lambda device: print(device.descriptor.name)
)
Each model declares native (brand_id, model_id) pairs by stack. The collection
selects models from DEVICES; alternatively pass them to
DeviceCollection(connection, [Sensor]).
Call await sensors.async_setup() to receive inventory and live events.
Applications observe models through add_update_listener(). Models decode readings,
update their attributes, then call notify(). Closing the collection removes
subscriptions and closes models, leaving the connection open.
Events
Events are typed dataclasses. An UplinkEvent exposes data: bytes and f_port
directly; an AckEvent exposes queue_item_id and acknowledged. Dispatch on
event.type or use isinstance() to narrow the event type without a cast.
Inventory events take only descriptor and received_at. Their network and device
identifiers are properties derived from the descriptor. The
event guide
lists every field.
Version 0.11 replaces the event envelopes from 0.10; see the migration notes.
Install
pip install lorawan-connection
The quickstart replays a SenseCAP S2101 capture and prints 21.4 °C and 31.4% humidity.
Backends
| Server | Install | Import |
|---|---|---|
| ChirpStack | pip install "lorawan-connection[chirpstack]" |
lorawan_connection.backend.chirpstack.ChirpStackConnection |
| The Things Stack | pip install "lorawan-connection[tts]" |
lorawan_connection.backend.tts.TTSConnection |
Adapters load only when explicitly imported. Both supply inventory before live activity. Collections select models by catalog identity. Provision devices on the server before connecting. The application owns connection startup, recovery, and shutdown; missed telemetry is not replayed.
ChirpStack drops retained events older than five seconds before each device stream starts. Keep server and client clocks synchronized. TTS supports separate Identity and Application Servers.
Sending commands
Models encode commands and call async_send_downlink(data=..., f_port=...).
By default, the call requests a confirmed downlink and waits for its ACK. Use
wait_for_ack=False to return after enqueueing an unconfirmed command.
An ACK confirms delivery; device reports update model attributes. A caller can
limit its wait with asyncio.timeout(), but the queued command may still execute.
Optional expires_at limits queue retention on ChirpStack. TTS rejects explicit expiry.
The Dragino example models the LT-22222-L with identities from both the ChirpStack and TTS catalogs.
Testing device libraries
Use MockConnection from lorawan_connection.mock in place of a server connection.
Seed it with device descriptors, then call the collection's async_setup().
connection.emit(event) delivers events to subscribed collections. Queued commands
are recorded in connection.downlinks, keyed by queue ID. Send ACK events explicitly
to test command completion; connection.disconnect() simulates connection loss.
See the testing guide.
Device-library CLI
For a device library named my_sensors that exports Sensors, put this in
my_sensors/__main__.py:
from lorawan_connection.cli_helper import run
from . import Sensors
if __name__ == "__main__":
run(Sensors.DEVICES)
The helper prints public model attributes and properties as updates arrive.
Select --backend chirpstack (the default) or --backend tts. Add --list for
inventory only, or --json for machine-readable output. --help works without
backend extras installed.
pip install "lorawan-connection[chirpstack]"
python -m my_sensors --server https://chirpstack.example.com:443 --api-key-file /path/to/key
See the CLI guide and Connecting to ChirpStack.
Add a backend
The backend guide covers optional dependency packaging, complete inventory, subscription ordering, event translation, downlink acknowledgements, transport cleanup, and CLI selection. Adapters implement the connection protocol without importing an application framework.
Home Assistant
These APIs are proposed and are not yet part of Home Assistant:
- Connection providers
configure backends and register them with
lorawan.async_register_connection(). - Device implementations
use
DeviceManagerto access matching devices on all available connections.
Development
uv sync --group compatibility --all-extras
uv run ruff check .
uv run ruff format --check .
uv run mypy
uv run pytest --cov --cov-report=term-missing
uv run python examples/replay.py
cd docs
npm ci
npm run build
CI tests Python 3.12, 3.13, and 3.14. Compatibility tests check event translation
against chirpstack-api==4.19.0. The optional backend uses the same bindings.
The documentation build validates internal links and produces llms.txt.
The repository follows the packaging, documentation, and release approach of
modbus-connection.
The source version stays 0.0.0; the publish workflow sets the version from the
release tag. See releasing for release instructions.
Metadata
Release files for lorawan-connection 0.11.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| lorawan_connection-0.11.0.tar.gz | 114.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| lorawan_connection-0.11.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 172.5 kB
Release files / lorawan_connection-0.11.0.tar.gz
| Download URL | lorawan_connection-0.11.0.tar.gz |
|---|---|
| Size | 114.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1271b397dfd679f89fd9de2ad028dfc088c1074f1ff081695cc154e20af7c745
|
|
BLAKE2b-256 checksum How to use checksums |
8556d443ce57094e3d6e9ab8075f5d22abab0aa214982733c2655072df0e82d6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Oct 7, 2026.
Transparency logRelease files / lorawan_connection-0.11.0-py3-none-any.whl
| Download URL | lorawan_connection-0.11.0-py3-none-any.whl |
|---|---|
| Size | 58.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6dd8c71f7cf7b8d44fbd039c656283016b5b1fa10f038c0aee61f9db023cc937
|
|
BLAKE2b-256 checksum How to use checksums |
652d92c7df0a6c4370856857f302b04e80ffa6f29f38a41087d5c287996d3405
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Oct 7, 2026.
Transparency log