Raspberry Pi LoRa MQTT alıcısı, Wi-Fi için fazla uzaktaki sensörlerden veri toplamanın en basit yoludur: bir tarla, bir çiftlik, bir otopark ya da büyük bir sahanın en uç noktası. Bu eğitimde SX127x tabanlı bir radyoyu (RFM95W, RFM96W veya bir LoRa bonnet) Pi'ye bağlayacak, kendi vericilerinizden noktadan noktaya paketler alacak ve her birini JSON olarak bir MQTT broker'a yeniden yayınlayacaksınız. broker.connectmq.com ile başlayıp üretime hazır bir kurulumla bitireceksiniz.
Noktadan Noktaya LoRa ve LoRaWAN
LoRa bir radyo modülasyonudur; LoRaWAN ise onun üzerine kurulmuş, cihaz kaydı, şifreleme anahtarları, bir ağ sunucusu ve çok kanallı gateway'ler içeren tam bir ağ protokolüdür. Zaten bir LoRaWAN ağı işletiyorsanız, ağ sunucunuz uplink'leri MQTT'ye yayınlar ve bunun yerine ChirpStack MQTT entegrasyonuna ihtiyacınız vardır.
Noktadan noktaya LoRa bunların hepsini atlar. Vericiniz (genellikle SX1276 modüllü bir ESP32 veya Arduino) sabit bir frekansta sabit ayarlarla küçük bir paket gönderir ve tek kanallı bir alıcı onu duyar. Anlaşılması kolaydır ve tamamen sizin kontrolünüzdedir; bu da onu her iki ucun da size ait olduğu hobi projeleri, prototipler ve özel sensör ağları için uygun kılar. Bunun bedeli; adreslemeyi, bütünlük kontrollerini ve görev döngüsü (duty cycle) sınırlarını kendinizin yönetmesidir.
Donanım
| Parça | Notlar |
|---|---|
| Raspberry Pi | 40 pinli başlığa sahip herhangi bir model; bir Zero 2 W yeterlidir |
| SX127x radyo | Adafruit LoRa Radio Bonnet, RFM95W breakout veya benzeri bir SPI modülü |
| Anten | Bandınıza göre ayarlanmış; asla antensiz yayın yapmayın |
| Verici düğüm | ESP32, Arduino veya eşleşen radyolu ikinci bir Pi |
| Frekans | Avrupa'da 868 MHz, Kuzey Amerika'da 915 MHz, bazı bölgelerde 433 MHz; yerel kurallara uyun |
Bir breakout kartın kablolaması SPI pinlerini izler: SCK'yi GPIO 11'e, MOSI'yi GPIO 10'a, MISO'yu GPIO 9'a, CS'yi CE1'e (GPIO 7), RESET'i GPIO 25'e, ayrıca 3,3 V ve toprağı bağlayın. Adafruit bonnet tam olarak bu pinleri kullanır; aşağıdaki kodun varsayılan olarak bunları kullanmasının nedeni budur.
Kütüphaneleri Kurun
sudo raspi-config ile SPI'ı etkinleştirin (Interface Options, SPI), ardından Linux üzerinde board ve busio modüllerini sağlayan Adafruit Blinka'yı ve RFM9x sürücüsünü içeren bir ortam oluşturun:
sudo raspi-config nonint do_spi 0
ls /dev/spidev*
python3 -m venv ~/lora/.venv
source ~/lora/.venv/bin/activate
pip install adafruit-blinka adafruit-circuitpython-rfm9x "paho-mqtt>=2.0"
Adafruit sitesindeki Blinka kurulum rehberi, bazı Pi modelleri için ek adımlar listeler; örneğin yeni sürümlerde lgpio kurulumu. import board başarısız olursa, devam etmeden önce o rehberi izleyin.
Radyo Ayarlarını Eşleştirin
Bir LoRa alıcısı yalnızca aynı frekans, yayılma faktörü (spreading factor), bant genişliği, kodlama oranı, senkronizasyon kelimesi ve önsözle (preamble) gönderilen paketleri duyar. Uyuşmazlık hata üretmez; sessizlik üretir. Ayarları bir kez yazın ve her iki tarafta da kullanın.
| Ayar | Örnek değer | Notlar |
|---|---|---|
| Frekans | 868,1 MHz | Bölgenizde yasal olmalıdır |
| Yayılma faktörü | 7 | Yüksek değer daha uzun menzil, daha yavaş yayın süresi demektir |
| Bant genişliği | 125 kHz | Yaygın varsayılan |
| Kodlama oranı | 4/5 | Sürücüde 5 olarak ayarlanır |
| CRC | Açık | Verici ve alıcıda etkinleştirin |
| Başlık | Vericiye bağlı | Aşağıdaki RadioHead notuna bakın |
RadioHead başlığı tuzağı. Adafruit RFM9x sürücüsü RadioHead kuralını izler ve varsayılan olarak alınan paketlerden 4 baytlık bir başlığı (to, from, id, flags) kırpar. Sandeep Mistry'nin Arduino LoRa kütüphanesini kullanan vericiler bu başlığı eklemez; bu yüzden payload'unuzun ilk dört baytı sessizce kaybolur. Vericiniz RadioHead kullanmıyorsa, aşağıdaki betikte olduğu gibi receive(with_header=True) çağırın.
Raspberry Pi LoRa MQTT Betiği
Bu örnekteki verici, n1,21.4,63,3.92 gibi kısa bir metin payload'u gönderir (düğüm kimliği, sıcaklık, nem, pil voltajı). Alıcı bunu doğrular, radyo meta verilerini ekler ve düğüm başına bir topic'e yayınlar. Bilinmeyen veya hatalı paketler sessizce atılmak yerine hata ayıklama için ayrı bir ham topic'e gider.
import json
import os
import time
import uuid
import adafruit_rfm9x
import board
import busio
import digitalio
import paho.mqtt.client as mqtt
BROKER = os.getenv("MQTT_HOST", "broker.connectmq.com")
PORT = int(os.getenv("MQTT_PORT", "1883"))
USERNAME = os.getenv("MQTT_USERNAME")
PASSWORD = os.getenv("MQTT_PASSWORD")
CLIENT_ID = os.getenv("MQTT_CLIENT_ID", f"lora-rx-{uuid.uuid4().hex[:8]}")
PREFIX = os.getenv("TOPIC_PREFIX", "connectmq/demo/l9r3x5/lora")
FREQ_MHZ = float(os.getenv("LORA_FREQ", "868.1"))
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
cs = digitalio.DigitalInOut(board.CE1)
reset = digitalio.DigitalInOut(board.D25)
rfm9x = adafruit_rfm9x.RFM9x(spi, cs, reset, FREQ_MHZ)
rfm9x.spreading_factor = 7
rfm9x.signal_bandwidth = 125000
rfm9x.coding_rate = 5
rfm9x.enable_crc = True
def on_connect(client, userdata, flags, reason_code, properties):
print("MQTT connected:", reason_code)
client.publish(f"{PREFIX}/receiver/status", "online", qos=1, retain=True)
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=CLIENT_ID)
if USERNAME:
client.username_pw_set(USERNAME, PASSWORD)
if PORT == 8883:
client.tls_set()
client.will_set(f"{PREFIX}/receiver/status", "offline", qos=1, retain=True)
client.reconnect_delay_set(1, 60)
client.on_connect = on_connect
client.connect_async(BROKER, PORT, keepalive=60)
client.loop_start()
def parse(text):
parts = text.split(",")
if len(parts) != 4 or not parts[0].startswith("n"):
return None
node, temp, hum, vbat = parts
return node, {"temperature": float(temp), "humidity": float(hum), "vbat": float(vbat)}
print(f"listening on {FREQ_MHZ} MHz")
try:
while True:
packet = rfm9x.receive(timeout=5.0, with_header=True)
if packet is None:
continue
meta = {"rssi": rfm9x.last_rssi, "snr": rfm9x.last_snr, "ts": int(time.time())}
try:
parsed = parse(packet.decode("ascii").strip())
except (UnicodeDecodeError, ValueError):
parsed = None
if parsed:
node, values = parsed
client.publish(f"{PREFIX}/{node}", json.dumps({**values, **meta}), qos=1, retain=True)
print(node, values, meta)
else:
client.publish(f"{PREFIX}/raw", json.dumps({"hex": packet.hex(), **meta}), qos=0)
except KeyboardInterrupt:
pass
finally:
client.publish(f"{PREFIX}/receiver/status", "offline", qos=1, retain=True)
client.loop_stop()
client.disconnect()
Arduino LoRa kütüphanesini kullanan bir ESP32 vericide eşleşen yapılandırma LoRa.begin(868.1E6), LoRa.setSpreadingFactor(7), LoRa.setSignalBandwidth(125E3), LoRa.setCodingRate4(5) ve LoRa.enableCrc() şeklindedir. Ardından LoRa.beginPacket(); LoRa.print("n1,21.4,63,3.92"); LoRa.endPacket(); ile gönderin.
Sonuçları herhangi bir makineden izleyin:
mosquitto_sub -h broker.connectmq.com -p 1883 -i lora-viewer-l9r3x5 -t "connectmq/demo/l9r3x5/lora/#" -v
Paketleri Sağlamlaştırmak
Düz metinde hata ayıklamak kolaydır ama yayın süresini (airtime) boşa harcar; LoRa'da kıt kaynak da yayın süresidir. Bağlantı çalıştığında şu iyileştirmeleri düşünün:
- İkili payload'lar. Değerleri sabit ölçeklemeyle paketleyin; örneğin sıcaklığı yüzde birlik hassasiyetle int16 olarak. 4 alanlı bir okuma yaklaşık 16 bayttan 7 bayta iner; bu da yayın süresini kısaltır ve pil ömrünü uzatır.
- Düğüm kimliği ve sıra numarası. Bir sıra sayacı, alıcının kaçırılan ve yinelenen paketleri tespit etmesini sağlar; ayrıca düğüm başına paket kaybını ayrı bir metrik olarak raporlamanıza olanak tanır.
- Bütünlük. Radyo CRC'si bozulmayı yakalar. Komşular aynı ayarlarla yayın yapabilecekse, size ait olmayan paketleri yok saymak için kısa bir tanımlayıcı veya bir HMAC ekleyin.
- Görev döngüsü. Birçok bölge, bir cihazın bir alt bantta saatte ne kadar süre yayın yapabileceğini kısıtlar. Uzun yayılma faktörleri ve sık gönderimler bu sınırı hızla aşabilir; bu yüzden payload'ları küçük, aralıkları makul tutun.
- Alıcı sağlığı. Alıcıdan bir heartbeat yayınlayın ve düğüm başına son görülme zamanını izleyin; böylece ölü bir verici ile ölü bir alıcı panelinizde farklı görünür.
Her paketle yayınlanan SNR ve RSSI değerleri, anten yerleşimi için en iyi aracınızdır. Pozitif SNR rahat bir bağlantı demektir; yayılma faktörünüzün hassasiyet sınırına yaklaşan değerler ise menzilin sınırında olduğunuzu gösterir.
Gözetimsiz Çalıştırma
Bir ahır duvarındaki veya direkteki alıcı, elektrik kesintilerini ve ağ kopmalarını atlatabilmelidir. Betiği otomatik olarak yeniden başlaması için bir systemd servisi olarak çalıştırın, uplink kesikken okumaları SQLite'ta çevrimdışı MQTT arabelleği ile yerel olarak saklayın ve SD kart yıpranması ile güç kaynakları için Raspberry Pi güvenilirlik ipuçlarını izleyin. Hücresel bağlantılı uzak sahalar için MQTT iyi bir seçimdir, çünkü bağlantı yalnızca dışa doğrudur ve protokol ek yükü küçüktür.
Test Broker'ından Ayrılmak
Genel MQTT test broker'ı radyo bağlantısını doğru kurmak için mükemmeldir, ancak orada yayınlanan her şey herkes tarafından görülebilir. Gerçek bir kurulum için ConnectMQ üzerinde bir broker oluşturun, portaldan oluşturulan kullanıcı adını, parolayı ve client ID'yi alın ve alıcıyı ortamda MQTT_PORT=8883 ve bu değerlerle başlatın. TLS bir Let's Encrypt sertifikası kullanır; bu yüzden tls_set() Pi'nin varsayılan CA deposuyla çalışır. Bir bulut MQTT broker, farklı sahalardaki birden fazla alıcının, panellerinizin ve uyarı kurallarınızın tek bir yerden okuyabileceği tek bir topic ağacına yayın yapmasını da sağlar.
Pi'de MQTT'ye yeni mi başlıyorsunuz? Raspberry Pi MQTT eğitimi burada kullanılan temelleri anlatır; Raspberry Pi IoT gateway rehberi ise bir LoRa alıcısının tek bir cihaz üzerinde BLE, Modbus ve diğer girişlerle nasıl birlikte çalışabileceğini gösterir.
LoRa Verilerinizi ConnectMQ'ya Gönderin
app.connectmq.com adresinde kredi kartı gerekmeden ücretsiz bir Serverless broker oluşturun; alıcınız için TLS kimlik bilgilerine dakikalar içinde sahip olursunuz. ConnectMQ'nun canlı topic gezgini her düğümü raporladığı anda gösterir; eşik tabanlı uyarı kuralları da bir sınırı aşan sıcaklık veya pil değerini işaretleyebilir.
Sık Sorulan Sorular
Tek bir SX127x alıcısı LoRaWAN gateway olarak çalışabilir mi?
Tam anlamıyla hayır. LoRaWAN gateway'leri, SX1302 gibi konsantratör yongaları kullanarak aynı anda birden fazla kanalı ve yayılma faktörünü dinler. Tek bir SX127x bir seferde tek bir yapılandırmayı duyar; bu da noktadan noktaya kullanıma uygundur.
Ne kadar menzil bekleyebilirim?
Menzil büyük ölçüde anten yüksekliğine, araziye ve yayılma faktörüne bağlıdır. Yükseltilmiş antenlerle görüş hattı, binaların içinden geçmeye göre çok daha uzağa ulaşır; bu yüzden RSSI ve SNR'yi sahada ölçün.
Alıcım neden eksik baytlı paketler alıyor?
Neredeyse her zaman RadioHead başlığı uyuşmazlığından. Verici 4 baytlık RadioHead başlığını eklemiyorsa receive(with_header=True) kullanın.
Pi düğümlere geri komut gönderebilir mi?
Evet, RFM9x sürücüsü yayın yapabilir. Bir komut topic'ine abone olun ve rfm9x.send() çağırın; ancak düğümlerin o anda dinliyor olması gerektiğini unutmayın; pille çalışan vericiler genellikle yalnızca yayın yaptıktan hemen sonra kısa bir süre dinler.



