IoT Otomasyon

The Things Network MQTT Entegrasyonu: LoRaWAN Uplink'lerini Kendi Broker'ınıza Köprüleyin

The Things Network'ün MQTT sunucusuna abone olun, LoRaWAN uplink'lerini bir payload formatter ile çözümleyin ve kısa bir Python köprüsüyle temiz sensör JSON'unu kendi topic ağacınıza yeniden yayınlayın.

LoRaWAN sensör uplink'lerini bir ağ geçidinden bulut MQTT broker topic ağacına taşıyan The Things Network MQTT köprüsü
Bunu kendi MQTT broker’ınızda çalıştırınFree planla özel, yönetilen bir MQTT broker alın ve hazır kod örnekleriyle başlayın.
Ücretsiz deneyin Kod örnekleri Kart gerekmez

The Things Network MQTT sunucusu her uygulamaya LoRaWAN uplink'lerinin canlı bir akışını sunar; bu da uzun menzilli sensör verilerini kendi sistemlerinize çekmeyi kolaylaştırır. Bu eğitimde bir payload formatter yazacak, bir API anahtarıyla TTN MQTT sunucusuna bağlanacak ve çözümlenmiş ölçümleri temiz JSON olarak kendi broker topic ağacınıza yeniden yayınlayan küçük bir Python köprüsü çalıştıracaksınız; böylece panolar, Node-RED ve otomasyonlar bu verileri diğer cihazlarınızla birlikte kullanabilir.

TTN'yi Neden Kendi Broker'ınıza Köprülemelisiniz?

The Things Network (TTN), LoRaWAN'ın radyo tarafıyla ilgilenir: ağ geçitleri, cihaz aktivasyonu, tekilleştirme ve şifre çözme. MQTT sunucusu her uplink'i, paketi duyan her ağ geçidinden gelen meta verileri içeren büyük bir JSON belgesi olarak yayınlar. Bu, hata ayıklama için mükemmeldir ancak uzun vadeli bir veri modeli olarak kullanışsızdır:

  • topic'ler sizin saha hiyerarşiniz değil, TTN'nin yapısıdır (v3/<app>@ttn/devices/<device>/up);
  • payload'lar büyük ve iç içedir, oysa tüketicilerin çoğu üç dört değer ister;
  • Wi-Fi cihazlarınız, PLC'leriniz ve kontrolcüleriniz zaten başka bir broker üzerindedir.

Bir köprü bu üç sorunu da çözer. TTN'ye abone olur, önemli olanı ayıklar ve kompakt mesajları diğer her şeyle aynı topic ağacına yayınlar. Tüketicilerin hiçbir zaman TTN kimlik bilgilerine ihtiyacı olmaz ve ileride özel bir ağ sunucusuna geçerseniz yalnızca köprü değişir. Akıllı tarım IoT rehberi bunun çiftlik genelindeki bir tasarımda nereye oturduğunu açıklar.

Adım 1: Payload'u TTN'de Çözümleyin

LoRaWAN cihazları kompakt baytlar gönderir. TTN Console'da Applications > uygulamanız > Payload formatters > Uplink altına Custom Javascript formatter türünde bir payload formatter ekleyin. Bu örnek; nem (uint16, yüzdenin onda biri), toprak sıcaklığı (int16, derecenin onda biri) ve pil (uint16, milivolt) gönderen bir toprak düğümünü çözümler:

function decodeUplink(input) {
  var b = input.bytes;
  if (input.fPort !== 1 || b.length < 6) {
    return { errors: ["unexpected port or length"] };
  }
  var moisture = ((b[0] << 8) | b[1]) / 10;
  var tRaw = (b[2] << 8) | b[3];
  if (tRaw & 0x8000) tRaw -= 0x10000;
  var battery = ((b[4] << 8) | b[5]) / 1000;
  return {
    data: {
      moisture_pct: moisture,
      soil_temp_c: tRaw / 10,
      battery_v: battery
    },
    warnings: [],
    errors: []
  };
}

Herhangi bir cihaz sahaya konmadan önce çıktıyı doğrulamak için Test panelini 0136 008C 0E74 gibi bir hex payload ile kullanın. Çözümlenen nesne her uplink'te uplink_message.decoded_payload olarak görünür.

Adım 2: TTN'den MQTT Kimlik Bilgilerini Alın

Console'da Integrations > MQTT bölümünü açın. Şunları göreceksiniz:

Ayar Değer
Sunucu Kümeniz, örneğin eu1.cloud.thethings.network
Portlar 1883 (şifresiz) ve 8883 (TLS)
Kullanıcı adı <application-id>@ttn
Parola Bir API anahtarı; Generate new API key'e tıklayın

API anahtarını hemen kopyalayın; TTN onu yalnızca bir kez gösterir. Anahtar uygulama verilerinize erişim sağladığı için TTN'ye her zaman 8883 portundan bağlanın. Resmi The Things Stack belgelerinin MQTT sunucusu bölümü; join, downlink ve hizmet olayları dahil olmak üzere topic'lerin tam listesini verir.

Tek bir uygulamanın uplink topic'i şudur:

v3/<application-id>@ttn/devices/<device-id>/up

Herhangi bir kod yazmadan önce akışı kontrol edebilirsiniz:

mosquitto_sub -h eu1.cloud.thethings.network -p 8883 --capath /etc/ssl/certs \
  -u 'my-farm-app@ttn' -P 'NNSXS.YOUR_TTN_API_KEY' \
  -t 'v3/my-farm-app@ttn/devices/+/up' -v

Adım 3: Python ile The Things Network MQTT Köprüsü

Köprü iki paho-mqtt 2.x client'ı kullanır: biri TTN'ye abone olur, diğeri sizin broker'ınıza yayın yapar. Önce herkese açık test broker'ına karşı çalıştırın; herkese açık alan herkes tarafından okunabildiği için t6n1b4 değerini kendi rastgele dizenizle değiştirin.

import json
import os
import ssl

import paho.mqtt.client as mqtt

TTN_HOST = "eu1.cloud.thethings.network"
TTN_APP = os.environ.get("TTN_APP", "my-farm-app")
TTN_KEY = os.environ["TTN_API_KEY"]

OUT_HOST = os.environ.get("OUT_HOST", "broker.connectmq.com")
OUT_PORT = int(os.environ.get("OUT_PORT", "1883"))
OUT_USER = os.environ.get("OUT_USER")          # üretimde ayarlayın
OUT_PASS = os.environ.get("OUT_PASS")
OUT_CLIENT_ID = os.environ.get("OUT_CLIENT_ID", "ttn-bridge-out-t6n1b4")
OUT_PREFIX = os.environ.get("OUT_PREFIX", "connectmq/demo/t6n1b4/farm")

# --- giden broker ----------------------------------------------------------
out = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=OUT_CLIENT_ID)
if OUT_USER:
    out.username_pw_set(OUT_USER, OUT_PASS)
if OUT_PORT == 8883:
    out.tls_set(cert_reqs=ssl.CERT_REQUIRED)
out.will_set(f"{OUT_PREFIX}/bridge/status", "offline", qos=1, retain=True)

def out_on_connect(client, userdata, flags, reason_code, properties):
    print("out broker:", reason_code)
    client.publish(f"{OUT_PREFIX}/bridge/status", "online", qos=1, retain=True)

out.on_connect = out_on_connect
out.connect(OUT_HOST, OUT_PORT, keepalive=60)
out.loop_start()

# --- TTN ---------------------------------------------------------------------
def ttn_on_connect(client, userdata, flags, reason_code, properties):
    print("ttn:", reason_code)
    client.subscribe(f"v3/{TTN_APP}@ttn/devices/+/up", qos=1)

def ttn_on_message(client, userdata, msg):
    try:
        up = json.loads(msg.payload)
        device = up["end_device_ids"]["device_id"]
        um = up["uplink_message"]
        decoded = um.get("decoded_payload")
    except (ValueError, KeyError) as exc:
        print("skipping malformed uplink:", exc)
        return
    if not decoded:
        print(f"{device}: no decoded payload (check the formatter)")
        return

    rx = um.get("rx_metadata", [])
    best = max(rx, key=lambda g: g.get("rssi", -999)) if rx else {}
    record = {
        "ts": up.get("received_at"),
        **decoded,
        "rssi": best.get("rssi"),
        "snr": best.get("snr"),
        "gateways": len(rx),
        "f_cnt": um.get("f_cnt"),
    }
    topic = f"{OUT_PREFIX}/{device}/telemetry"
    out.publish(topic, json.dumps(record), qos=1, retain=True)
    print(topic, record)

ttn = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
                  client_id=f"ttn-bridge-in-{TTN_APP}")
ttn.username_pw_set(f"{TTN_APP}@ttn", TTN_KEY)
ttn.tls_set(cert_reqs=ssl.CERT_REQUIRED)
ttn.on_connect = ttn_on_connect
ttn.on_message = ttn_on_message
ttn.connect(TTN_HOST, 8883, keepalive=60)
ttn.loop_forever()

Çalıştırın:

pip install paho-mqtt
export TTN_API_KEY='NNSXS.YOUR_TTN_API_KEY'
python ttn_bridge.py

Temiz çıktıyı başka bir terminalden izleyin:

mosquitto_sub -h broker.connectmq.com -p 1883 -i watch-t6n1b4 \
  -t 'connectmq/demo/t6n1b4/farm/#' -v

Her uplink, {"ts":"2026-10-16T06:15:02Z","moisture_pct":31.0,"soil_temp_c":14.0,"battery_v":3.7,"rssi":-108,"snr":4.5,"gateways":2,"f_cnt":412} gibi retained bir mesaja dönüşür. Retained olduğu için sonradan başlayan bir pano da her sensörün son ölçümünü anında görür; bu, yalnızca 15 dakikada bir veri gönderen cihazlar için önemlidir.

Tasarım Notları

RSSI, SNR ve ağ geçidi sayısı neden dahil ediliyor? Bunlar; arızalanan bir antenin, yeri değiştirilen bir ağ geçidinin veya çamura gömülen bir sensörün en erken uyarı işaretleridir. Saklamanın maliyeti neredeyse sıfırdır.

Neden retained message? LoRaWAN cihazları çoğu zaman sessizdir. Retain olmadan, iki uplink arasında bağlanan herhangi bir tüketici bir sonrakine kadar hiçbir şey görmez.

Neden her iki tarafta QoS 1? TTN teslimat yaparken köprü yeniden başlayabilir; yeniden bağlanan bir client ile QoS 1 boşlukları azaltır. Ödünleşimler için MQTT QoS seviyeleri açıklaması yazısına bakın.

Topic derinliği. connectmq/demo/t6n1b4/farm/<device>/telemetry altı seviyeye sahiptir ve herkese açık test broker'ının sekiz seviyelik sınırının rahatça içindedir. Üretimde farm1/north/<device>/telemetry gibi kendi hiyerarşinizi kullanın.

Mesaj boyutu. Birkaç ağ geçidinden meta veri içeren ham bir TTN uplink'i birkaç kilobayta ulaşabilir. Yeniden yayınlanan kayıt birkaç yüz bayttır; herkese açık test alanının 64 KB ve ConnectMQ ücretsiz planının 256 KB sınırının çok altındadır ve pille desteklenen panolar ile mobil client'lar için işlemesi çok daha ucuzdur.

Boşlukları ve Tekrarları Yönetme

LoRaWAN tasarımı gereği kayıplı bir radyo bağlantısıdır: cihazlar onay almadan iletim yapar ve hiçbir ağ geçidinin duymadığı bir paket basitçe kaybolur. Her kayda dahil edilen çerçeve sayacı (f_cnt), tüketicilerin boşlukları tespit etmesini sağlar. Sayaç 410'dan 413'e atlarsa iki uplink MQTT'de değil, radyo tarafında kaybolmuştur. Bu ayrım, birisi eksik veri bildirdiğinde zaman kazandırır.

Köprü, QoS 1 bir mesaj aktarılırken TTN'ye yeniden bağlanırsa aynı uplink'i iki kez de görebilir. Veri saklayan tüketiciler, cihaz ID'si ile çerçeve sayacının birleşimini benzersiz bir anahtar olarak kabul etmeli ve tekrarları yok saymalıdır. Sayacın, bir cihaz ağa yeniden katıldığında sıfırlandığını unutmayın; bu nedenle onu kalıcı bir tanımlayıcı olarak değil, kısa zaman aralıklarında boşluk tespiti için kullanın.

Bir cihaza komut göndermek için (örneğin yeni bir raporlama aralığı), köprü broker'ınızdaki bir komut topic'ine abone olabilir ve onu TTN'nin downlink topic'ine iletebilir:

import base64

def forward_downlink(device_id, port, raw_bytes):
    body = {"downlinks": [{
        "f_port": port,
        "frm_payload": base64.b64encode(raw_bytes).decode(),
        "priority": "NORMAL",
    }]}
    ttn.publish(f"v3/{TTN_APP}@ttn/devices/{device_id}/down/push",
                json.dumps(body), qos=1)

# örnek: port 2 üzerinden aralığı 30 dakikaya ayarla (tek bayt)
# forward_downlink("soil-node-07", 2, bytes([30]))

Class A cihazlar downlink'leri yalnızca bir sonraki uplink'lerinden sonra alır; bu nedenle komutlar raporlama aralığına eşit bir gecikmeyle ulaşır. Downlink'leri seyrek tutun; LoRaWAN yayın süresi (airtime) ve görev döngüsü (duty cycle) kuralları onları maliyetli kılar.

Güvenilir Şekilde Çalıştırma

  1. Köprüyü otomatik yeniden başlatmalı bir systemd hizmeti veya konteyner olarak çalıştırın.
  2. TTN API anahtarını betikte değil, bir ortam değişkeninde veya gizli bilgi deposunda tutun.
  3. API anahtarına yalnızca ihtiyaç duyduğu yetkileri verin (uygulama trafiğini okuma ve kullanılıyorsa downlink yazma).
  4. bridge/status topic'ini izleyin: süreç ölürse son vasiyet onu offline yapar.
  5. Topluluk ağı için TTN'nin adil kullanım politikasını unutmayın; ağ, sık mesaj gönderen cihazlar için değil, düşük frekanslı sensörler için tasarlanmıştır.

Özel Bir Broker ile Üretim

OUT_HOST=broker.connectmq.com, OUT_PORT=8883, OUT_USER, OUT_PASS ve OUT_CLIENT_ID değerlerini özel broker'ınızla birlikte verilen kimlik bilgilerine ayarlayın ve OUT_PREFIX değerini kendi hiyerarşinizle değiştirin. Betiğin geri kalanı aynı kalır. Barındırılan bir MQTT broker, LoRaWAN verilerinize, Wi-Fi sensörlerinize ve kontrolcülerinize bakımını sizin yapmanız gerekmeyen, ortak ve şifreli tek bir yuva sağlar. TTN yerine kendi ağ sunucunuzu çalıştırıyorsanız ChirpStack MQTT eğitimi eşdeğer köprüyü gösterir; toprak nemi sensörü MQTT projesi ise binalara yakın tarlalar için bir Wi-Fi alternatifidir. Daha fazla örnek IoT otomasyon rehberinde toplanmıştır; MQTT sizin için yeniyse bir MQTT broker'ın ne yaptığına dair arka plan bilgisi yardımcı olur.

LoRaWAN Verilerinizi ConnectMQ'ya Taşıyın

ConnectMQ, köprülenen TTN verileriniz için TLS'li özel bir MQTT broker, canlı bir topic gezgini, bir pano ve düşük pil ya da kuru toprak gibi değerler için eşik uyarı kuralları sunar. app.connectmq.com adresinde kredi kartı gerektirmeden ücretsiz bir Serverless broker oluşturun ve köprünün çıktısını ona yönlendirin.

Sık Sorulan Sorular

TTN MQTT kullanıcı adı ve parolası nedir?

Kullanıcı adı, uygulama ID'nizin sonuna @ttn eklenmiş halidir (The Things Network topluluk sürümü için); parola ise Integrations > MQTT altında oluşturulan bir API anahtarıdır.

Uplink'lerimde decoded_payload neden eksik?

Herhangi bir uplink payload formatter yapılandırılmamıştır ya da formatter hata vermiştir. Onu Console'un formatter panelinde gerçek bir hex payload ile test edin.

TTN'yi kod yazmadan doğrudan başka bir broker'a bağlayabilir miyim?

TTN webhook'lar ve başka entegrasyonlar sunar; ancak kendi topic yapınızla kendi MQTT broker'ınıza yayın yapmak için bunun gibi küçük bir köprü en basit ve en şeffaf seçenektir.

Köprünün ağ geçidinin yakınında çalışması gerekir mi?

Hayır. Her iki bağlantı da internet üzerinden olduğu için herhangi bir sunucuda, bir Raspberry Pi'da veya bir konteynerde çalışabilir.

İlgili yazılar

Zigbee2MQTT Kurulum Rehberi: Koordinatörden Panoya

Zigbee2MQTT'yi Docker ile kurun, koordinatörü ve MQTT bağlantısını yapılandırın, cihazları eşleştirip yeniden adlandırın, onları MQTT üzerinden kontrol edin ve durumlarını bir panoda görüntüleyin; önce ücretsiz herkese açık bir broker'da test edin.

7 dk okuma

Tüm yazılar →

Özel MQTT broker’ınız birkaç tık uzağınızda

Hesabınızı oluşturun, broker kimlik bilgilerinizi alın ve ilk cihazınızı bağlayın — kurulacak, yamalanacak ya da ölçeklendirilecek sunucu yok.