ESP32 ve Arduino

ESP32'de MicroPython umqtt: umqtt.simple ve umqtt.robust ile Publish ve Subscribe

MicroPython çalıştıran bir ESP32'yi umqtt.simple ile bir MQTT broker'a bağlayın, umqtt.robust ile otomatik yeniden bağlanma ekleyin, komutları bloklamadan alın ve bu minimal istemcilerin neleri yapamadığını öğrenin.

Sensör ölçümlerini yayınlayan MicroPython umqtt betiği çalıştıran ESP32 kartı
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

ESP32'de MicroPython umqtt, derleme adımı olmadan ve hata ayıklama için etkileşimli bir komut istemiyle, birkaç satır Python ile MQTT kullanmanızı sağlar. Bu eğitimde bir ESP32'yi umqtt.simple ile broker.connectmq.com'a bağlıyor, umqtt.robust ile otomatik yeniden bağlanma ekliyor, gelen komutları bloklamadan işliyor ve bu istemcilere production'da güvenmeden önce bilmeniz gereken sınırları açıklıyoruz.

MQTT Cihazları İçin Neden MicroPython

Arduino core ile C++ daha hızlıdır ve daha fazla kütüphaneye sahiptir, ancak geliştirme döngüsünün hızında MicroPython öne çıkar. Bir dosyayı düzenler, karta kopyalar ve saniyeler içinde çalıştırırsınız. REPL, Wi-Fi, sensörler ve MQTT ile etkileşimli olarak denemeler yapmanıza izin verir; bu da bir şeyin neden çalışmadığını anlamaya çalışırken paha biçilmezdir.

micropython-lib içindeki umqtt paketi iki modül sunar:

  • umqtt.simple: minimal bir MQTT 3.1.1 istemcisi. Bağlanma, publish, subscribe, ping, last will. Hiçbir şey otomatik olarak gerçekleşmez.
  • umqtt.robust: simple üzerine kurulu ince bir alt sınıf; publish(), wait_msg() ve birkaç başka çağrıdaki soket hatalarını yakalar ve otomatik olarak yeniden bağlanır.

Her ikisi de herhangi bir ESP32'ye rahatça sığacak kadar küçüktür.

Kartın Hazırlanması

  1. Resmi indirme sayfasından ESP32'niz için güncel bir MicroPython firmware'ini esptool.py ile yükleyin.
  2. Bilgisayarınıza mpremote kurun: pip install mpremote.
  3. umqtt paketinin zaten mevcut olup olmadığını kontrol edin. Bazı firmware derlemeleri onu içerir, bazıları içermez. REPL'de import umqtt.simple başarısız olursa mip ile kurun:
mpremote connect auto mip install umqtt.simple
mpremote connect auto mip install umqtt.robust

mip, kartın internete bağlı olmasını gerektirir. Kart henüz Wi-Fi'a bağlı değilse kurulumu önce bağlantı kuran bir betikten çalıştırın veya modül dosyalarını mpremote cp ile elle kopyalayın. MicroPython paket yönetimi belgeleri tüm seçenekleri açıklar.

Wi-Fi'a Bağlanma

Her açılışta çalışması için bunu boot.py dosyasına koyun:

import network
import time

WIFI_SSID = "YOUR_WIFI"
WIFI_PASS = "YOUR_WIFI_PASSWORD"

def connect_wifi(timeout=15):
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    if not wlan.isconnected():
        wlan.connect(WIFI_SSID, WIFI_PASS)
        start = time.time()
        while not wlan.isconnected():
            if time.time() - start > timeout:
                raise RuntimeError("Wi-Fi connection timed out")
            time.sleep(0.25)
    print("Wi-Fi OK", wlan.ifconfig()[0])
    return wlan

connect_wifi()

umqtt.simple ile Publish

İlk betik broker.connectmq.com'un herkese açık alanına bağlanır ve her beş saniyede bir ölçüm yayınlar. Client ID, çipin benzersiz kimliğinden oluşturulur; böylece asla boş olmaz ve başka bir kartla asla çakışmaz.

import time
import ubinascii
import machine
import esp32
from umqtt.simple import MQTTClient

BROKER = "broker.connectmq.com"
PREFIX = b"connectmq/demo/2b7e95"
CLIENT_ID = b"mpy-" + ubinascii.hexlify(machine.unique_id())

client = MQTTClient(CLIENT_ID, BROKER, port=1883, keepalive=30)
client.set_last_will(PREFIX + b"/status", b"offline", retain=True, qos=1)
client.connect()
client.publish(PREFIX + b"/status", b"online", retain=True, qos=1)
print("Connected as", CLIENT_ID)

while True:
    temp_c = (esp32.raw_temperature() - 32) / 1.8   # dahili sensörden kaba bir ölçüm
    payload = '{"temp":%.1f,"uptime":%d}' % (temp_c, time.ticks_ms() // 1000)
    client.publish(PREFIX + b"/telemetry", payload.encode())
    time.sleep(5)

raw_temperature() bulunmayan ESP32 varyantlarında bu satırı gerçek bir sensör okumasıyla değiştirin. Mesajları bilgisayarınızdan izleyin:

mosquitto_sub -h broker.connectmq.com -p 1883 -i pc-2b7e95 -t 'connectmq/demo/2b7e95/#' -v

Topic'lerin ve payload'ların byte türünde olduğuna dikkat edin. umqtt birçok yerde str kabul eder, ancak tutarlı biçimde byte kullanmak sürprizleri önler; özellikle her zaman byte alan callback'lerde.

Komutları Bloklamadan Almak

Mesaj almak için bir callback kaydedin ve subscribe olun. Ardından düzenli olarak ya bir mesaj gelene kadar bekleyen wait_msg() fonksiyonunu ya da bekleyen bir şey yoksa hemen dönen check_msg() fonksiyonunu çağırmanız gerekir. Başka işler de yapan bir döngüde check_msg() kullanın:

import time
import ubinascii
import machine
from umqtt.simple import MQTTClient

BROKER = "broker.connectmq.com"
PREFIX = b"connectmq/demo/2b7e95"
CLIENT_ID = b"mpy-" + ubinascii.hexlify(machine.unique_id())
led = machine.Pin(2, machine.Pin.OUT)

def on_message(topic, msg):
    print("Received", topic, msg)
    if topic == PREFIX + b"/led/set":
        led.value(1 if msg == b"ON" else 0)
        client.publish(PREFIX + b"/led/state", msg, retain=True)

client = MQTTClient(CLIENT_ID, BROKER, port=1883, keepalive=30)
client.set_callback(on_message)
client.connect()
client.subscribe(PREFIX + b"/led/set", qos=1)

last_ping = time.ticks_ms()
last_publish = time.ticks_ms()

while True:
    client.check_msg()                       # bekleyen mesajı işle

    now = time.ticks_ms()
    if time.ticks_diff(now, last_publish) > 10000:
        client.publish(PREFIX + b"/telemetry", b'{"alive":true}')
        last_publish = now
        last_ping = now
    elif time.ticks_diff(now, last_ping) > 20000:
        client.ping()                        # boştayken bağlantıyı canlı tut
        last_ping = now

    time.sleep_ms(50)

Test edin:

mosquitto_pub -h broker.connectmq.com -p 1883 -i pc-2b7e95-pub -t connectmq/demo/2b7e95/led/set -m ON

Gözden kaçması kolay iki nokta var. Birincisi, umqtt.simple keepalive ping'lerini kendiliğinden göndermez. Bir keepalive ayarlayıp bundan daha seyrek publish yapıyorsanız, yukarıdaki döngüde olduğu gibi ping() çağırmanız gerekir; aksi halde broker bağlantınızı keser. İkincisi, set_callback() mutlaka subscribe() öncesinde çağrılmalıdır.

umqtt.robust ile Otomatik Yeniden Bağlanma

umqtt.simple bağlantı koptuğunda OSError fırlatır ve siz bunu ele almazsanız betiğiniz durur. umqtt.robust ana çağrıları sarmalar ve denemeler arasında kısa bir gecikmeyle yeniden bağlanır. Tek değişiklik import satırıdır:

from umqtt.robust import MQTTClient

Bir püf noktası var. Robust istemci soketi yeniden bağlar, ancak sizin yerinize yeniden subscribe olmaz ve clean session ile broker aboneliklerinizi unutur. Güvenilir bir yöntem, bağlanma adımını bir fonksiyona sarmak ve onu hem açılışta hem de kendi yakaladığınız her hatadan sonra çağırmaktır:

def connect_and_subscribe():
    client.connect(clean_session=True)
    client.subscribe(PREFIX + b"/led/set", qos=1)
    client.publish(PREFIX + b"/status", b"online", retain=True, qos=1)

connect_and_subscribe()

while True:
    try:
        client.check_msg()
        # ... periyodik publish ...
    except OSError as e:
        print("MQTT error", e, "- reconnecting")
        time.sleep(5)
        try:
            connect_and_subscribe()
        except OSError:
            pass
    time.sleep_ms(50)

Tamamen gözetimsiz çalışan cihazlar için machine.WDT(timeout=30000) ekleyin ve döngü içinde besleyin; böylece tam bir kilitlenme kartı yeniden başlatır.

MicroPython umqtt ESP32 Projesini Yapılandırmak

Bir betik birkaç düzine satırı aştığında, onu herhangi bir Python projesinde yapacağınız gibi bölün. Kart üzerinde iyi çalışan bir düzen:

  • boot.py yalnızca Wi-Fi bağlantısını kurar; böylece uygulamadaki bir hata sizi asla REPL'in dışında bırakmaz.
  • config.py broker host'unu, portu, topic önekini ve kimlik bilgilerini tutar. Sürüm kontrolünün dışında tutun ve her karta ayrı ayrı kopyalayın.
  • main.py config modülünü import eder, istemciyi oluşturur ve ana döngüyü, istisnayı loglayıp kısa bir gecikmeden sonra machine.reset() çağıran bir try/except içinde çalıştırır.

İki alışkanlık çok fazla hata ayıklama süresi kazandırır. Ana döngüyü, REPL'de Ctrl+C'ye basıldığında genel hata yakalayıcınıza takılmak yerine KeyboardInterrupt ile temiz biçimde duracak şekilde sarmalayın. Döngüde payload string'leri oluşturuyorsanız periyodik olarak gc.collect() çağırın; MicroPython'un heap'i küçüktür ve parçalanma dakikalar sonra değil, saatlerce çalıştıktan sonra MemoryError olarak ortaya çıkar.

JSON yayınlamanın en kolay yolu yerleşik json modülüdür: client.publish(topic, json.dumps({"temp": 22.4})). Komutları ayrıştırmak da callback içinde json.loads(msg) ile aynı şekilde çalışır; bozuk bir mesajın cihazı çökertmemesi için bunu bir try içine alın.

Bilmeniz Gereken umqtt Sınırlamaları

Sınırlama Etkisi Çözüm
Yalnızca MQTT 3.1.1 MQTT 5 özellikleri (properties), reason code'lar veya shared subscription özellikleri yok MQTT 5'e ihtiyacınız varsa farklı bir istemci kullanın
Yalnızca QoS 0 ve 1 QoS 2 desteklenmez Çoğu telemetri ve komut için QoS 1 yeterlidir
Otomatik keepalive ping'i yok Boştaki bağlantılar düşürülür Periyodik olarak ping() çağırın
Bloklayan soket çağrıları connect() ve wait_msg() betiği bloklar check_msg() kullanın; karmaşık cihazlar için asyncio tabanlı bir istemci düşünün
Yeniden bağlanmada otomatik subscribe yok Yeniden bağlandıktan sonra komutlar gelmez Kendi yeniden bağlanma fonksiyonunuzda yeniden subscribe olun
Çevrimdışı mesaj kuyruğu yok Bağlantı yokken yayınlanan mesajlar kaybolur Gerekirse ölçümleri kendiniz tamponlayın

Aynı anda birden fazla iş yapması gereken cihazlar için keepalive ve yeniden bağlanmayı arka planda yöneten topluluk kaynaklı asyncio tabanlı MQTT istemcileri mevcuttur. Basit sensörler ve aktüatörler için umqtt en hafif seçenek olmaya devam eder.

8883 Portunda TLS Kullanımı

Özel bir broker için bağlantıyı şifreleyin. umqtt.simple'ın yeni sürümleri bir SSLContext alan ssl argümanını kabul eder; eski sürümler bunun yerine ssl_params sözlüğüyle birlikte ssl=True kullanır, bu yüzden kurduğunuz sürümü kontrol edin.

import ssl
from umqtt.simple import MQTTClient

ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ctx.verify_mode = ssl.CERT_REQUIRED
ctx.load_verify_locations(cafile="isrg-root-x1.der")   # Let's Encrypt kök CA'sı

client = MQTTClient(
    b"YOUR_CLIENT_ID",
    "broker.connectmq.com",
    port=8883,
    user=b"YOUR_USERNAME",
    password=b"YOUR_PASSWORD",
    keepalive=30,
    ssl=ctx,
)
client.connect()

Önce ISRG Root X1 sertifikasını mpremote cp ile karta kopyalayın. TLS hatırı sayılır miktarda RAM gerektirir; PSRAM'li kartlar bunu daha rahat kaldırır. Broker'ınız için oluşturulan client ID, kullanıcı adı ve parolayı birebir kullanın, çünkü ConnectMQ client ID'yi verilen kimlik bilgilerine bağlar.

İlgili Rehberler

C++ ile çalışmayı tercih ediyorsanız ESP32 PlatformIO MQTT proje rehberi iyi yapılandırılmış bir Arduino kurulumunu gösterir, ESP32 MQTT Last Will rehberi ise ilk betikte kullanılan durum desenini açıklar. ESP32 IoT eğitimi cihazdan dashboard'a kadar tüm resmi ele alır; protokolde yeniyseniz bir MQTT broker'ın ne yaptığı yazısıyla başlayın.

MicroPython Cihazlarınızı ConnectMQ'ya Bağlayın

Buradaki tüm örnekler kayıt gerektirmeden herkese açık MQTT test broker'ı ile çalışır. Denemelerin ötesine geçtiğinizde ConnectMQ size 8883 portunda TLS ve kartınızın ne gönderdiğini kontrol edebileceğiniz tarayıcı içi bir MQTT istemcisi ile özel bir bulut MQTT broker sunar. Ücretsiz Serverless planında app.connectmq.com adresinden bir tane oluşturun, kredi kartı gerekmez.

Sık Sorulan Sorular

umqtt MQTT 5'i destekliyor mu?

Hayır. Hem umqtt.simple hem de umqtt.robust MQTT 3.1.1'i uygular. ConnectMQ gibi MQTT 5'i destekleyen broker'lar 3.1.1 bağlantılarını da kabul eder.

MicroPython MQTT istemcim neden bir dakika sonra bağlantıyı kesiyor?

Bir keepalive ayarladınız ancak bu süre içinde hiçbir şey göndermiyorsunuz. umqtt otomatik ping göndermez; bu yüzden düzenli olarak client.ping() çağırın veya keepalive süresinden daha sık publish yapın.

wait_msg() ile check_msg() arasındaki fark nedir?

wait_msg() bir mesaj gelene kadar bloklar. check_msg() bekleyen bir mesaj varsa onu işler ve hemen döner; bu da sensör okuyan döngüler için uygundur.

umqtt QoS 2 kullanabilir mi?

Hayır. QoS 0 ve 1'i destekler; bu da cihaz kullanım senaryolarının çoğunu karşılar.

İlgili yazılar

ESP32 NTP MQTT Zaman Damgası: Her Mesaja Doğru Zaman Ekleyin

ESP32 saatini NTP ile eşitleyin, ISO 8601 ve epoch milisaniye zaman damgalarını biçimlendirin ve bunları MQTT payload'larına ekleyin; böylece ölçümler geç yayınlansa bile gerçek alınma zamanlarını korur.

6 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.