Skip to main content

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 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 maps a stack name to its native (brand_id, model_id) in identifiers. The collection builds its catalog lookup from DEVICES. You can also pass classes at construction: DeviceCollection(connection, [Sensor]). Call await sensors.async_setup() to subscribe through the supplied connection. The collection owns its subscription; the application owns connection cleanup. The Device base supplies identity, add_update_listener(), notify(), and cleanup. Models define their own attributes, including multiple measurements or channels. Listeners take no arguments and read model attributes after a complete update. See Connecting to ChirpStack to connect the collection to a server.

Install

pip install lorawan-connection

The quickstart replays a SenseCAP S2101 capture and prints 21.4 °C and 31.4% humidity.

Included

  • Read-only event and payload Protocols. Generated payloads can pass by reference.
  • Immutable descriptors and fixture dataclasses for every supported event payload.
  • An in-memory MockConnection for device replay, event delivery, and command tests.
  • A Device base with synchronous update listeners and explicit notifications.
  • A generic DeviceCollection with inventory replay, model replacement, and retirement.
  • Synchronous callback helpers with independent, idempotent unsubscribe functions.
  • Typed exports (py.typed), a tested SenseCAP example, and Astro/Starlight documentation.

The optional lorawan_connection.backend.chirpstack backend supplies inventory and live events. Install lorawan-connection[chirpstack] to use it. Backend dependencies stay in their extras; importing the shared package does not import any adapter. Import ChirpStackConnection explicitly from lorawan_connection.backend.chirpstack. The backend drops events whose server receipt timestamps are more than five seconds before each device stream starts. Keep the client and ChirpStack clocks synchronized. The application owns its connection lifecycle; provisioning, QR parsing, and vendor decoders belong in separate libraries. The SenseCAP implementation under examples/ illustrates a separate device library.

Events are live notifications. The package does not persist history, reconnect a transport, or request replay after a gap. Providers report inventory before activity. Collections select models from catalog identity, never from names or payload guesses.

The lorawan_connection.backend.tts adapter uses The Things Stack gRPC APIs. Install lorawan-connection[tts]. It supports separate Identity and Application Servers, native catalog identity, live uplinks, lifecycle events, and command ACKs. See the TTS guide. The Dragino example's relay and digital-output methods default to no queue expiry and work through both backends. Pass an optional expires_at datetime when needed. TTS rejects explicit queue expiry; ChirpStack supports it.

Sending commands

Pass the connection to the collection. Device models encode their commands and call async_send_downlink(data=..., f_port=...). The method requests a confirmed downlink and completes after its device ACK. It returns None on success. Use wait_for_ack=False to send an unconfirmed command and return after enqueueing. Callers can bound the wait with asyncio.timeout(). Device reports update model attributes; an ACK confirms delivery, not the resulting device state.

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.

Construct DeviceEventData with keyword arguments. Supply descriptor=... to derive network_id and dev_eui, or pass both identifiers explicitly for an event without a descriptor. Conflicting explicit identifiers raise ValueError.

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 discovers supported devices and prints their state. Models supply catalog identity and update listeners through the shared Device base. The CLI reads public model attributes and properties. Select the server with --backend chirpstack or --backend tts. ChirpStack is the default. TTS requires explicit --application IDs and uses TTS_API_KEY. The helper imports the selected adapter only when connecting. --help works without backend extras installed. By default, it discovers applications across all accessible tenants and streams live updates. Use --tenant UUID or repeat --application UUID to restrict the selection. Keys that cannot list tenants require --tenant. Use --list to print inventory and exit, or --json for machine-readable output. Unmapped devices from supported vendors produce a warning on stderr, once per device per run. Each warning includes the device name, DevEUI, brand ID, and model ID.

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.

Collection subscriptions

Pass a connection to the collection, then call await devices.async_setup(). The collection selects stack and brand pairs from its registered model classes and receives existing devices before setup returns. Later events reach models automatically. devices.close() unsubscribes and closes the models without closing the connection. Listen for a model's removal with device.add_remove_listener(callback). It fires after removal or replacement closes that model, but not during ordinary shutdown.

Connection exposes only async_subscribe(*, brands, callback), on_disconnect(callback), and async_send_downlink(downlink). Collections fail pending commands when the connection is lost and keep models open. Applications own connection startup, recovery, and shutdown. The ChirpStack backend retries transient polling and device-stream failures before reporting connection loss.

For ChirpStack, call await connection.async_connect() before setting up collections. Register disconnect notifications with connection.on_disconnect(callback); the callback takes no arguments. Use await devices.async_setup() to deliver events to models. Several collections can share one connection.

Home Assistant

The Home Assistant guide covers registered connections, discovery, coordinators, and entities. Server integrations register connections with lorawan. One vendor entry handles all registered servers through DeviceManager, with one collection per connection. Platforms subscribe to ready coordinators. Temporary disconnection preserves models and registry records; reconnection reconciles the device list.

Server integrations use their config entry ID as network_id and call await lorawan.async_register_connection(hass, entry, connection=connection) after connecting. The returned callback withdraws the registration. The server integration calls it before closing its transport and owns retries and reauthentication. The guide includes a registration example and the setup and shutdown requirements.

Vendor coordinators and the manager use device_identifier() for registry identity. It returns one identifier tuple; wrap it in a set for DeviceInfo.identifiers. These Home Assistant APIs are proposals and are not yet part of Home Assistant.

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 the payload contracts 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.10.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for lorawan-connection 0.10.0
File Size Uploaded
lorawan_connection-0.10.0.tar.gz 112.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for lorawan-connection 0.10.0
File Interpreter ABI Platform
lorawan_connection-0.10.0-py3-none-any.whl Python 3 none any Details

Total release size: 172.6 kB

Release files / lorawan_connection-0.10.0.tar.gz

Download URL lorawan_connection-0.10.0.tar.gz
Size 112.9 kB
Tags Source
SHA-256 checksum
How to use checksums
f8734c875359b52513cfe0f76d13c30134b7e399830f2246f82b208353753ed4
BLAKE2b-256 checksum
How to use checksums
a72983f7bd365a231565d2d562c75ffabc6503e1c32a71ae146136b9dd08a7f7
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 5, 2026.

Transparency log

Release files / lorawan_connection-0.10.0-py3-none-any.whl

Download URL lorawan_connection-0.10.0-py3-none-any.whl
Size 59.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7cd8a4a6ed99e850d5084c2ac59bff9d503125e32eb66dd7c0549254eea2610a
BLAKE2b-256 checksum
How to use checksums
dbbf1a0546eeaea05ccca7fc466363e198acac784f57a5a54eae808f28d5d3fe
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 5, 2026.

Transparency log

Release history Release notifications | RSS feed

1.2.0

2 release files

1.1.0

2 release files

1.0.0

2 release files

0.14.1

2 release files

0.14.0

2 release files

0.13.0

2 release files

This release

0.10.0 This release

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page