IoT Eğitimleri

Paho MQTT 2.0 Callback API Sürümü: Geçiş Hatalarını Adım Adım Düzeltme

paho-mqtt 2.0 bir gecede pek çok Python kodunu bozdu. Neyin değiştiğini, callback_api_version hatasını tek satırda nasıl düzelteceğinizi ve çalışan bir örnekle tüm callback'leri VERSION2 imzalarına nasıl taşıyacağınızı öğrenin.

VERSION1'den VERSION2 callback'lerine paho mqtt 2.0 callback api sürümü geçişini gösteren kod farkı
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

Paho MQTT 2.0 callback API sürümü değişikliği, Python MQTT betiklerinin bir pip install --upgrade sonrasında aniden çalışmayı bırakmasının en yaygın nedenidir. Bu rehber paho-mqtt 2.0'da tam olarak neyin değiştiğini açıklıyor, hata için tek satırlık düzeltmeyi veriyor ve ardından her callback'in önerilen VERSION2 imzalarına taşınmasını adım adım gösteriyor. Sonunda broker.connectmq.com adresine bağlanan, şablon olarak kullanabileceğiniz eksiksiz ve çalışan bir örneğiniz olacak.

Muhtemelen Gördüğünüz Hatalar

Buraya bir arama motorundan geldiyseniz, büyük ihtimalle şunlardan biriyle karşılaşmışsınızdır:

ValueError: Unsupported callback API version: version 2.0 added a callback_api_version, see docs/migrations.rst for details
TypeError: Client.__init__() missing 1 required positional argument: 'callback_api_version'
DeprecationWarning: Callback API version 1 is deprecated, update to latest version
TypeError: on_connect() takes 4 positional arguments but 5 were given

İlk ikisi istemcinin 1.x yöntemiyle oluşturulmasından kaynaklanır. ValueError, mqtt.Client("my-device") örneğinde olduğu gibi bir client ID'yi ilk konumsal argüman olarak verdiğinizde ortaya çıkar, çünkü o konum artık callback API sürümüne aittir. Üçüncüsü, eski API'yi açıkça seçtiğinizi bildiren bir uyarıdır. Dördüncüsü ise VERSION2'ye geçip bir callback'i eski parametre sayısıyla bıraktığınızda görülür.

paho-mqtt 2.0'da Neler Değişti

Eclipse Paho Python istemcisinin 2024 başında yayımlanan 2.0 sürümü, yıllardır ilk büyük sürümdü. Öne çıkan değişiklik, callback'lerin artık sürümlenmesidir. 1.x'te callback'lere geçirilen parametreler MQTT 3.1.1 ile MQTT 5 arasında farklılık gösteriyordu; bazıları düz tamsayılar, bazıları ise reason code nesneleri kullanıyordu. Sürüm 2 bunları birleştirir: her callback, protokol sürümünden bağımsız olarak aynı parametreleri alır ve sonuç kodları her zaman ReasonCode nesneleridir.

Kodu yeni imzalarla sessizce bozmamak için geliştiriciler seçimi açıkça yapmanızı zorunlu kıldı. Client() fonksiyonunun ilk argümanı artık iki değeri olan callback_api_version parametresidir:

Değer Davranış Önerilir mi?
CallbackAPIVersion.VERSION1 Eski 1.x callback imzaları, kullanımdan kaldırma uyarısı verir Yalnızca geçici bir köprü olarak
CallbackAPIVersion.VERSION2 Yeni birleşik imzalar, her yerde ReasonCode nesneleri Evet, tüm yeni ve taşınan kodlar için

2.0'daki diğer dikkate değer değişiklikler arasında Python 2.7 ve çok eski Python 3 sürümleri için desteğin kaldırılması ve ReasonCodes sınıfının ReasonCode olarak yeniden adlandırılması yer alır. Tam liste resmi paho-mqtt geçiş notlarında bulunur.

Düzeltme 1: Tek Satırlık Köprü (VERSION1)

Üretim ortamı çöktüyse ve hemen geri getirmeniz gerekiyorsa, paho'ya eski davranışı korumasını söyleyin:

import paho.mqtt.client as mqtt

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, client_id="my-device")

Mevcut tüm callback'leriniz değişmeden çalışmaya devam eder. Kullanımdan kaldırma uyarısını görürsünüz; bu, VERSION1'in gelecekteki bir büyük sürümde kaldırılacağının hatırlatıcısıdır. Bunu bir çözüm değil, bir yara bandı olarak görün.

Alternatif bir yara bandı, eski kütüphaneyi pip install "paho-mqtt<2.0" ile sabitlemektir. Bu işe yarar, ancak güvenlik ve hata düzeltmelerini engeller ve genellikle zaten 2.x gerektiren diğer paketlerle çakışır. Sabitleme yerine VERSION1 bayrağını tercih edin ve gerçek geçişi planlayın.

Düzeltme 2: Paho MQTT 2.0 Callback API Sürüm 2'ye Geçiş

Gerçek çözüm VERSION2 geçmek ve callback imzalarını güncellemektir. İşte tüm callback'ler yan yana:

Callback 1.x / VERSION1 imzası VERSION2 imzası
on_connect (client, userdata, flags, rc) (client, userdata, flags, reason_code, properties)
on_disconnect (client, userdata, rc) (client, userdata, disconnect_flags, reason_code, properties)
on_subscribe (client, userdata, mid, granted_qos) (client, userdata, mid, reason_code_list, properties)
on_unsubscribe (client, userdata, mid) (client, userdata, mid, reason_code_list, properties)
on_publish (client, userdata, mid) (client, userdata, mid, reason_code, properties)
on_message (client, userdata, message) değişmedi
on_log (client, userdata, level, buf) değişmedi

VERSION1'de MQTT 5 ile bunların bazılarında zaten ek parametreler vardı; VERSION2 bu farkı ortadan kaldırır ve değişikliğin bütün amacı da budur.

Geçiş kontrol listesi

Kodunuzu bu sırayla elden geçirin:

  1. Her mqtt.Client(...) çağrısını, diğer tüm argümanları anahtar kelimeyle geçerek mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=..., ...) olarak değiştirin.
  2. on_connect fonksiyonuna properties ekleyin ve rc adını reason_code yapın. rc == 0 ifadesini not reason_code.is_failure ile değiştirin (tamsayılarla karşılaştırma hâlâ çalışır, ancak özellik daha okunaklıdır).
  3. flags["session present"] ifadesini flags.session_present ile değiştirin.
  4. on_disconnect fonksiyonuna yeni disconnect_flags parametresini ve properties ekleyin.
  5. on_subscribe içinde granted_qos yerine reason_code_list kullanın ve her girdiyi kontrol edin: başarı kodlarının değeri 0 ile 2 arasındadır (verilen QoS), başarısız olanlarda is_failure ayarlıdır.
  6. on_publish ve on_unsubscribe fonksiyonlarına reason_code ve properties ekleyin.
  7. Kod tabanında ReasonCodes arayın ve ReasonCode olarak değiştirin.
  8. Hiçbir VERSION1 istemcisi kalmadığını kanıtlamak için testlerinizi uyarıları hataya çevirerek (python -W error::DeprecationWarning) çalıştırın.

Eksiksiz Bir VERSION2 Örneği

Bu betik tüm yaygın callback'leri yeni imzalarla kullanır. Herkese açık MQTT test broker'ının diğer kullanıcılarıyla topic paylaşmamak için k7f3q2 değerini kendi rastgele dizginizle değiştirin:

import time
import uuid

import paho.mqtt.client as mqtt

BROKER = "broker.connectmq.com"
PREFIX = "connectmq/demo/k7f3q2"


def on_connect(client, userdata, flags, reason_code, properties):
    if reason_code.is_failure:
        print(f"Connect failed: {reason_code}")
        return
    print(f"Connected (session present: {flags.session_present})")
    client.subscribe(f"{PREFIX}/#", qos=1)


def on_subscribe(client, userdata, mid, reason_code_list, properties):
    for rc in reason_code_list:
        print("Subscribe rejected:" if rc.is_failure else "Granted QoS:", rc)


def on_publish(client, userdata, mid, reason_code, properties):
    print(f"Publish {mid} acknowledged: {reason_code}")


def on_message(client, userdata, msg):
    print(f"{msg.topic}: {msg.payload.decode()}")


def on_disconnect(client, userdata, disconnect_flags, reason_code, properties):
    print(f"Disconnected: {reason_code}")


client = mqtt.Client(
    mqtt.CallbackAPIVersion.VERSION2,
    client_id=f"migrate-{uuid.uuid4().hex[:8]}",
    protocol=mqtt.MQTTv5,
)
client.on_connect = on_connect
client.on_subscribe = on_subscribe
client.on_publish = on_publish
client.on_message = on_message
client.on_disconnect = on_disconnect

client.connect(BROKER, 1883, keepalive=60)
client.loop_start()
time.sleep(1)

for i in range(3):
    client.publish(f"{PREFIX}/test", f"hello {i}", qos=1)
    time.sleep(1)

client.disconnect()
client.loop_stop()

Çalıştırdığınızda bağlantıyı, verilen QoS'u, üç publish onayını ve ConnectMQ herkese açık broker'ı tarafından geri yansıtılan üç mesajı görmelisiniz. protocol değerini mqtt.MQTTv311 yapın; aynı callback'ler hiçbir düzenleme olmadan çalışmaya devam eder ve VERSION2'nin vaat ettiği tam olarak budur. Kütüphanenin kendisinde yeniyseniz önce paho mqtt python eğitimiyle başlayın.

Geçişten Sonraki Tuzaklar

1.x'e sabitlenmiş üçüncü taraf kütüphaneler. Paho'yu sarmalayan bazı paketler gereksinimlerinde paho-mqtt<2.0 belirtmiştir. pip show ve pip check ile kontrol edin. Bakımı süren sarmalayıcıların çoğunun güncel sürümleri 2.x'i destekler; onları yükseltin veya eski araçları kendi sanal ortamlarında izole edin.

Konumsal argümanlar. Her mqtt.Client("id", False, None, mqtt.MQTTv311) çağrısı artık bir konum kaymıştır. Hepsini anahtar kelime argümanlarına dönüştürün; bu, gelecekteki yükseltmeleri zahmetsiz hale getirir.

Dekoratörlerle kaydedilen callback'ler. @client.connect_callback() ve benzeri dekoratörleri kullanan kodlarda dekore edilen fonksiyonların imzaları da güncellenmelidir.

Yutulan istisnalar. Paho varsayılan olarak callback'ler içinde fırlatılan istisnaları programınızı çökertmek yerine loglar. Bu nedenle yanlış bir imza "hiçbir şey olmuyor" gibi görünebilir. TypeError görünür olsun diye geçiş sırasında client.enable_logger() ile bir logger bağlayın.

Yeniden bağlanma mantığı. Yeniden bağlanıp bağlanmamaya karar vermek için on_disconnect içinde rc tamsayılarını karşılaştırıyorsanız, bunu reason_code etrafında yeniden yazın. paho-mqtt yeniden bağlanma rehberi sağlam desenler gösterir; Python MQTT TLS rehberi ise üretimde kullanmanız gereken şifreli bağlantıyı ele alır.

Bunun Yerine aiomqtt'yi Düşünmeli misiniz?

Uygulamanız asyncio üzerine kuruluysa, callback'leri taşımak tamamen asenkron bir API'ye geçmek için iyi bir an olabilir. aiomqtt, paho'yu sarmalar ve callback'lerin yerine async for message in client.messages kullanır. aiomqtt ve asyncio eğitimimiz aynı publish/subscribe akışını bu şekilde yazılmış olarak gösterir. Python ve diğer dillerdeki istemcilerin daha geniş bir karşılaştırması için MQTT istemci kütüphanelerine genel bakış yazısına bakın.

Taşınan Kodunuzu ConnectMQ Üzerinde Test Edin

ConnectMQ, bir geçişi doğrulamak için ideal olan broker.connectmq.com adresinde ücretsiz bir herkese açık broker ve üretim için MQTT 3.1.1 ve 5.0, 8883 portunda TLS ve otomatik üretilen kimlik bilgileri sunan tam yönetilen bir MQTT hizmeti işletir. Portalında, taşınan istemcilerin hâlâ beklediğiniz şeyleri publish ettiğini doğrulayabileceğiniz canlı bir topic gezgini bulunur. Herkese açık broker'dan ayrılmaya hazır olduğunuzda istemcilerinizi özel bir bulut MQTT broker üzerinde çalıştırın: kredi kartı olmadan ücretsiz Serverless planına kaydolun.

Sık Sorulan Sorular

paho-mqtt'de callback_api_version nedir?

paho-mqtt 2.0'dan beri mqtt.Client() fonksiyonunun ilk argümanıdır. İstemcinin hangi callback imzalarını kullanacağını seçer: eski 1.x tarzı için VERSION1, yeni birleşik tarz için VERSION2.

VERSION1 mi yoksa VERSION2 mi kullanmalıyım?

VERSION2 kullanın. VERSION1 yalnızca eski kodun çalışmaya devam etmesi için vardır ve bir kullanımdan kaldırma uyarısı yazdırır; dolayısıyla eninde sonunda kaldırılacaktır.

Bir client ID geçtiğimde neden "Unsupported callback API version" hatası alıyorum?

Client ID'yi, artık callback API sürümüne ayrılmış olan ilk konumsal argüman olarak geçtiniz. Önce mqtt.CallbackAPIVersion.VERSION2 geçin, ID'yi ise client_id=... olarak verin.

Geçiş sırasında on_message'ı değiştirmem gerekir mi?

Hayır. on_message(client, userdata, message) her iki sürümde de aynı imzayı korur. Değişiklikler connect, disconnect, subscribe, unsubscribe ve publish callback'lerini etkiler.

İlgili yazılar

Test, Betik ve Hata Ayıklama için En İyi MQTT CLI Araçları

mosquitto_pub/sub, MQTTX CLI, HiveMQ MQTT CLI, MQTT.js CLI, curl ve mqttui'nin uygulamalı karşılaştırması; betik yazma ve hata ayıklama için doğru aracı seçebilmeniz için aynı test broker.connectmq.com üzerinde çalıştırıldı.

7 dk okuma

Python ile MQTT Verisini InfluxDB'ye Kaydetme

paho-mqtt ve influxdb-client ile bir broker'a abone olan, topic seviyelerini InfluxDB tag'lerine dönüştüren, sayısal JSON değerlerini field olarak toplu yazan ve hatalı payload'ları ile tip çakışmalarını yöneten bir Python köprüsü kurun.

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.