Skip to main content

SenseCAP LoRaWAN

Read SenseCAP sensors through ChirpStack or The Things Stack using lorawan-connection.

Model Readings Automatic discovery
S2100 Data logger input channels ChirpStack, TTS
S2101 Air temperature, humidity ChirpStack, TTS
S2102 Light intensity ChirpStack, TTS
S2103 Air temperature, humidity, CO₂ ChirpStack, TTS
S2104 Soil temperature, moisture ChirpStack, TTS
S2105 Soil temperature, moisture, conductivity ChirpStack, TTS
S2106 Temperature, pH ChirpStack
S2107 Three temperature probes, including buffered readings ChirpStack
S2120 Temperature, humidity, light, UV, wind, pressure, rainfall ChirpStack, TTS
A1101 Vision AI measurements ChirpStack
A1102 Vision detections and digital meter readings Explicit Python use
T1000 A/B Position, temperature, light, motion, Wi-Fi/BLE scans ChirpStack, TTS
T1000-E Position, temperature, light, acceleration, Wi-Fi/BLE scans Explicit Python use
T2000 A/B/C Position, acceleration, motion, Wi-Fi/BLE scans ChirpStack, TTS
WM1110 GNSS fragments, Wi-Fi/BLE scans, environmental and custom readings Explicit Python use
Gen1 sensors Air temperature/humidity, CO₂, light, pressure, soil temperature/moisture TTS

Coverage follows every device family in Seeed's SenseCAP-Decoder. The A1102, T1000-E, and WM1110 classes have no automatic discovery identifiers: they are absent from the SenseCAP catalogs checked for this release. Use their decode() methods directly, or subclass them with your deployment's model identity.

Tracker support requires SenseCAP LoRaWAN firmware. Meshtastic firmware and T1000 Mapper payloads are outside this decoder set. Wi-Fi/BLE scans and GNSS fragments remain scan data; the library does not resolve them through a location service or assemble fragmented GNSS messages. This library decodes uplinks and does not implement device configuration commands.

Raw payloads are decoded locally; a server-side payload formatter is not required.

Command-line reader

The sensecap-lorawan command lists devices or prints readings as they arrive. Install uv to run it with uvx, or use pip install "sensecap-lorawan[chirpstack]" for ChirpStack and pip install "sensecap-lorawan[tts]" for The Things Stack.

ChirpStack

Use a ChirpStack v4 gRPC endpoint, an API key, and the tenant UUID. The endpoint must expose the gRPC API; forwarding only the web interface is not sufficient.

export CHIRPSTACK_API_KEY="your-api-key"
uvx --from "sensecap-lorawan[chirpstack]" sensecap-lorawan \
  --backend chirpstack \
  --server https://chirpstack.example.com:8080 \
  --tenant YOUR_TENANT_UUID \
  --application YOUR_APPLICATION_UUID

Repeat --application to select more applications. If omitted, all accessible applications in the selected tenant are used. A global key can omit --tenant to discover its accessible tenants.

The Things Stack

Use the Application Server gRPC endpoint and an application API key with device read and application traffic read rights. Specify each application explicitly.

export TTS_API_KEY="your-api-key"
uvx --from "sensecap-lorawan[tts]" sensecap-lorawan \
  --backend tts \
  --server https://eu1.cloud.thethings.network:8884 \
  --identity-server https://eu1.cloud.thethings.network:8884 \
  --application YOUR_APPLICATION_ID

Set --identity-server to your deployment's Identity Server if it differs from the Application Server. Repeat --application for multiple applications.

Add --list to print the current devices and exit, or --json for newline-delimited JSON output. Use --api-key-file /path/to/key instead of an environment variable if preferred. Stop watching with Ctrl+C. Run sensecap-lorawan --help for all options.

With a pip installation, use sensecap-lorawan directly in place of the uvx --from ... sensecap-lorawan prefix. python -m sensecap_lorawan also works.

Python

from lorawan_connection.backend.chirpstack import ChirpStackConnection
from sensecap_lorawan import SenseCapDeviceCollection


async def list_sensors(
    endpoint: str, api_key: str, tenant: str, application: str
) -> None:
    connection = ChirpStackConnection(
        endpoint,
        api_key,
        tenant_id=tenant,
        application_ids=[application],
        network_id=endpoint,
    )
    devices = SenseCapDeviceCollection(connection)
    try:
        await connection.async_connect()
        await devices.async_setup()
        for device in devices.devices.values():
            print(device.descriptor.name, type(device).__name__)
    finally:
        devices.close()
        await connection.close()

The collection also accepts a TTSConnection. Subscribe with devices.subscribe_device_added(listener) and device.add_update_listener(listener) to receive live readings. Values remain None until the sensor reports them.

Reading measurements

Existing properties such as S2101.temperature, S2101.humidity, and S2102.illuminance remain available. All models also expose measurements[channel][measurement_id], whose Measurement contains value, timestamp, and protocol-specific attributes. Timestamps are timezone-aware UTC values when transmitted by the device; otherwise they are None.

from sensecap_lorawan import S2107

payload = S2107.decode(bytes.fromhex("470000ff9c8000"))
for measurement in payload.measurements:
    print(measurement.channel, measurement.value)
# 1 0.0
# 2 -1.0
# 3 None

For a live device, use device.measurement_value(4203, channel=2) or device.temperature(channel=2) on an S2107. The S2100 uses input channel numbers as measurement IDs within channel 1, matching Seeed's decoder. Unknown seven-byte measurement IDs are retained. See Seeed's measurement ID list for their meanings and units.

metadata contains reported versions, intervals, model information, and errors. battery_percentage reads the battery value from the vendor payload; battery_level remains the standardized LoRaWAN status value. Tracker event measurements contain numeric event IDs, positioning status is a numeric code, and Wi-Fi/BLE scan values are lists of {mac, rssi} dictionaries.

Direct decoding raises ValueError for malformed or unknown frame layouts. Live models discard those payloads atomically. Partial updates retain other readings; older readings cannot replace newer values on the same channel and measurement ID. Device timestamps take precedence over receipt time for buffered readings. Fault/absent values become None; zero remains a valid reading. The seven-byte protocol's two-byte trailer is not CRC-validated, matching Seeed's decoder.

Development

uv sync
uv run pytest
uv run ruff check .
uv run mypy
uv build

Tests include captured S2101/S2102 uplinks, reference outputs for every decoder family, and malformed, partial, and out-of-order messages. See fixture provenance and regeneration.

Releases

The source version stays 0.0.0. Publishing a GitHub release named 0.1.0, for example, builds that version and publishes it to PyPI through Trusted Publishing. See RELEASING.md for the one-time publisher setup.

License

Apache-2.0. Extracted from the SenseCAP examples in lorawan-connection.

Metadata

Release files for sensecap-lorawan 0.1.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 sensecap-lorawan 0.1.0
File Size Uploaded
sensecap_lorawan-0.1.0.tar.gz 13.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sensecap-lorawan 0.1.0
File Interpreter ABI Platform
sensecap_lorawan-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 31.2 kB

Release files / sensecap_lorawan-0.1.0.tar.gz

Download URL sensecap_lorawan-0.1.0.tar.gz
Size 13.8 kB
Tags Source
SHA-256 checksum
How to use checksums
8eb871f0bd3fd89f9956bac5ce6e0d742add295827b8f599578a15aceea9e4eb
BLAKE2b-256 checksum
How to use checksums
0ee9525b9b6965fa92c1dd95ca5b51a9236f8d2626c7d285d4a3649522679e4a
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 14, 2026.

Transparency log

Release files / sensecap_lorawan-0.1.0-py3-none-any.whl

Download URL sensecap_lorawan-0.1.0-py3-none-any.whl
Size 17.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5f629e6a4bc93a564b656a1b106f6db3c345d1ddb701a6407c57f7da004399f8
BLAKE2b-256 checksum
How to use checksums
3926298710b524e302f1f53fbcf20b411edcb8e30ec8b18dcce2df1bc72987bb
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 14, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

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