ttn_fetch.py

Arduino MKR WAN 1310 · File : ttn_fetch.py · Language : Python · Use case : Récupérer les uplinks LoRaWAN depuis l'API TTN

On the server side, this Python script queries The Things Network v3 API to fetch the latest uplinks from a MKR WAN 1310: timestamp, gateway-seen RSSI and base64 payload. The building block of a dashboard or an email alert.

Hardware

An Arduino MKR WAN 1310 (SAMD21 microcontroller, LoRa modem driven by an onboard ESP32 that also exposes Wi-Fi, LoRa antenna and Wi-Fi antenna). A TTN account, an application with a joined device, an API token (ttn-lvc CLI or integration key).

Wiring

None; the board is not even needed to test — use uplinks already received.

How it works

GET /as/applications/{app}/devices/{dev}/uplinks returns frames decrypted by the server. The frm_payload field is base64: decode it with base64.b64decode to recover your bytes.

Running it

Install Arduino SAMD Boards and the MKRWAN 2.x library (MKRWAN1310), select the board, upload. The 1310 is driven through AT commands over its internal ESP32; for LoRa, plan a second LoRa board on the other end.

Variants

Switch to MQTT (mqtt.ttn.cloud) for real time without polling, or schedule the script via cron for daily archiving.

ttn_fetch.py

#!/usr/bin/env python3
"""Uplinks TTN v3 d'une application via l'API HTTP.

Usage : TTN_TOKEN=xxx python ttn_fetch.py [app] [device]
Le token doit etre une cle d'integration "Link API".
"""
import os
import sys

import requests

BASE = "https://eu1.cloud.thethings.network/api/v3"
APP = sys.argv[1] if len(sys.argv) > 1 else "mon-app"
DEV = sys.argv[2] if len(sys.argv) > 2 else "mon-device"
HEADERS = {"Authorization": f"Bearer {os.environ['TTN_TOKEN']}"}


def principal() -> None:
    url = f"{BASE}/as/applications/{APP}/devices/{DEV}/uplinks"
    r = requests.get(url, params={"limit": 10, "order": "DESC"},
                     headers=HEADERS, timeout=15)
    r.raise_for_status()
    for up in reversed(r.json().get("uplinks", [])):
        t = up.get("received_at", "?")[:19]
        meta = up.get("received_at_metadata", {})
        rssi = meta.get("lorawan_metadata", {}).get(
            "received_signal_strength", "?")
        print(f"{t} rssi={rssi} b64={up.get('frm_payload', '')}")


if __name__ == "__main__":
    principal()

← Back to the board