paho-mqtt 2.0, istemcinin nasıl oluşturulduğunu ve callback'lerinizin ne aldığını değiştirdi. Betiğiniz bir pip install --upgrade sonrasında bozulduysa çözüm neredeyse her zaman aynıdır: mqtt.Client()'a ilk argüman olarak mqtt.CallbackAPIVersion.VERSION2 geçin ve callback imzalarını güncelleyin. Bu rehber tam hata mesajlarını, nelerin değiştiğini ve eksiksiz bir önce/sonra örneğini gösteriyor.
Muhtemelen gördüğünüz hatalar
| Hata | Neden | Çözüm |
|---|---|---|
ValueError: Unsupported callback API version: version 2.0 added a callback_api_version, see docs/migrations.rst for details | Client ID ilk konumsal argüman olarak geçilmiş: mqtt.Client("my-id") | mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="my-id") |
DeprecationWarning: Callback API version 1 is deprecated, update to latest version | Sürüm verilmeden mqtt.Client() ya da VERSION1 ile oluşturma | VERSION2 geçin ve callback'leri güncelleyin |
TypeError: on_connect() takes 4 positional arguments but 5 were given | 1.x tarzı on_connect(client, userdata, flags, rc) ile VERSION2 kullanımı | properties parametresini ekleyin (aşağıya bakın) |
TypeError: on_disconnect() takes 3 positional arguments but 5 were given | Aynı durum on_disconnect(client, userdata, rc) için | disconnect_flags, reason_code, properties içeren yeni imza |
AttributeError: module 'paho.mqtt.client' has no attribute 'CallbackAPIVersion' | Kodunuz 2.x için yazılmış ama ortamda hâlâ 1.x var | pip install "paho-mqtt>=2.0" çalıştırın ve betiği hangi yorumlayıcının çalıştırdığını kontrol edin |
Önce kurulu sürümü kontrol edin — sanal ortamlar ile sistem Python'u çoğu zaman farklıdır:
python -c "import paho.mqtt; print(paho.mqtt.__version__)"
pip show paho-mqtt2.0'da neler değişti
1.x sürümünde argümanları protokol sürümüne göre değişen tek bir callback stili vardı: MQTT 3.1.1 callback'leri tamsayı bir rc, MQTT 5 callback'leri ise reason_code ve properties alıyordu. Bu da bir protokolde çalışıp diğerinde çöken kod yazmayı kolaylaştırıyordu.
2.0 callback API sürümlerini getirir. CallbackAPIVersion.VERSION2 ile her callback MQTT 3.1.1 ve MQTT 5'te aynı imzaya sahiptir, reason code'lar her zaman ReasonCode nesnesidir ve properties her zaman geçilir (protokolde yoksa None olarak). Constructor artık şöyle görünür:
mqtt.Client(
callback_api_version, # yeni, ilk konumsal argüman
client_id="",
clean_session=None,
userdata=None,
protocol=mqtt.MQTTv311,
transport="tcp",
reconnect_on_failure=True,
manual_ack=False,
)Bilinmesi gereken diğer noktalar: 2.x, Python 3.7 veya üstünü gerektirir; publish.single() / subscribe.simple() yardımcıları sürümü sizin yerinize yönetir, bu yüzden yalnızca bunları kullanan kod genellikle çalışmaya devam eder.
Callback imzaları: 1.x ve VERSION2
| Callback | 1.x (MQTT 3.1.1) | VERSION2 ile 2.x |
|---|---|---|
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 |
Pratikte üç ayrıntı önemlidir:
flagsartık bir dict değil.on_connectiçinde birConnectFlagsnesnesidir:flags["session present"]yerineflags.session_presentkullanın.disconnect_flags.is_disconnect_packet_from_server, broker'ın bir DISCONNECT gönderip göndermediğini (MQTT 5) ya da bağlantı kaybını kütüphanenin kendisinin mi tespit ettiğini söyler.on_subscribedüz QoS tamsayıları değil, reason code'lar alır. QoS 1 ile kabul edilen bir abonelikte reason code'unvaluedeğeri1'dir; reddedilen bir aboneliğin değeri0x80veya üzeridir, dolayısıylarc.is_failuretrue olur.
Reason code'lar artık nesne
VERSION2 ile reason_code bir ReasonCode nesnesidir. Hem bir tamsayıya hem de kendi adına eşit kabul edilir, yazdırıldığında adını gösterir ve bir is_failure özelliğine sahiptir:
def on_connect(client, userdata, flags, reason_code, properties):
if reason_code.is_failure:
print(f"bağlantı başarısız: {reason_code} ({reason_code.value})")
return
print("bağlandı, oturum mevcut:", flags.session_present)Başarı durumu için reason_code == 0 ve reason_code == "Success" hâlâ çalışır; yani en yaygın kontrol güncellemeden değişmeden çıkar.
Eksiksiz bir önce/sonra örneği
Bu, tipik 1.x kodudur — 2.x'te yukarıdaki ValueError ile bozulur:
import paho.mqtt.client as mqtt
def on_connect(client, userdata, flags, rc):
if rc == 0:
client.subscribe("testmqtt/paho2/#", qos=1)
else:
print("connect failed, rc =", rc)
def on_disconnect(client, userdata, rc):
print("disconnected, rc =", rc)
def on_message(client, userdata, msg):
print(msg.topic, msg.payload.decode())
client = mqtt.Client("testmqtt-paho2-demo")
client.on_connect = on_connect
client.on_disconnect = on_disconnect
client.on_message = on_message
client.connect("broker.connectmq.com", 1883, 60)
client.loop_forever()Aynı istemcinin VERSION2'ye taşınmış hali:
import os
import paho.mqtt.client as mqtt
def on_connect(client, userdata, flags, reason_code, properties):
if reason_code.is_failure:
print(f"bağlantı başarısız: {reason_code}")
return
print("bağlandı, oturum mevcut:", flags.session_present)
client.subscribe("testmqtt/paho2/#", qos=1)
def on_subscribe(client, userdata, mid, reason_code_list, properties):
for rc in reason_code_list:
print("abonelik:", "reddedildi" if rc.is_failure else f"QoS {rc.value} verildi")
def on_disconnect(client, userdata, disconnect_flags, reason_code, properties):
print(f"bağlantı kesildi: {reason_code} (sunucudan: {disconnect_flags.is_disconnect_packet_from_server})")
def on_message(client, userdata, msg):
print(msg.topic, msg.payload.decode())
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="testmqtt-paho2-demo")
if os.environ.get("MQTT_USER"):
client.username_pw_set(os.environ["MQTT_USER"], os.environ.get("MQTT_PASS"))
client.on_connect = on_connect
client.on_subscribe = on_subscribe
client.on_disconnect = on_disconnect
client.on_message = on_message
client.connect("broker.connectmq.com", 1883, keepalive=60)
client.loop_forever()Aynı callback'ler protocol=mqtt.MQTTv5 ile de değişmeden çalışır — VERSION2'nin asıl faydası budur. Yalnızca constructor argümanları farklıdır: MQTT 5 clean_session kabul etmez (ValueError: Clean session is not used for MQTT 5.0 fırlatır); bunun yerine connect() içinde clean_start ve session expiry kullanın. MQTT 3.1.1'den MQTT 5'e geçiş rehberi bu seçenekleri anlatıyor.
Geçiş kontrol listesi
- Geçtiğiniz sürümü sabitleyin; örneğin
requirements.txtiçindepaho-mqtt>=2.1,<3kullanın ki bir sonraki major sürüm sizi şaşırtmasın. - Kod tabanında
mqtt.Client(araması yapın ve öncemqtt.CallbackAPIVersion.VERSION2'yi,client_id='yi de isimli argüman olarak geçin. - Diğer modüllerde veya kütüphanelerde atananlar dahil tüm callback'leri yeni imzaya güncelleyin.
rcüzerindeki tamsayı karşılaştırmalarınıreason_code.is_failureveya ad karşılaştırmalarıyla değiştirin.flags["session present"]ifadesiniflags.session_presentile değiştirin.- Hâlâ VERSION1 kullanan istemcileri yakalamak için uyarılar görünür halde çalıştırın (
python -W error::DeprecationWarning app.py).
Zaten çok kod yeniden yazacaksanız asenkron bir istemcinin daha uygun olup olmadığını düşünün — asyncio için aiomqtt paho-mqtt 2.x üzerine kuruludur. Diğer paho istisnaları için paho-mqtt Python hataları yazısına bakın.
Taşınan istemciyi test edin
client_v2.py'yi çalıştırın, ardından tarayıcınızda online MQTT istemcisini açın, broker.connectmq.com adresine bağlanın ve testmqtt/paho2/hello topic'ine publish edin. Betiğiniz topic'i ve payload'ı yazdırmalıdır. Hata yollarını denemek için kendi broker'ınıza yanlış bir parolayla bağlanın ve on_connect'in çıplak bir sayı yerine Bad user name or password gibi okunabilir bir neden yazdırdığını kontrol edin.
Taşınan istemcinize test mesajı gönderin
paho-mqtt 2.0'a geçiş büyük ölçüde mekaniktir: yeni bir constructor argümanı, beş callback imzası ve reason code kontrollerine dönüşen birkaç tamsayı kontrolü. VERSION2 ile bir kez yapın, major sürümü sabitleyin; callback'leriniz MQTT 3.1.1 ve MQTT 5'te aynı şekilde davranır. Kütüphanenin tamamını adım adım görmek için Python ile MQTT rehberine göz atın.
Sıkça sorulan sorular
paho-mqtt'deki 'Unsupported callback API version' hatası ne anlama gelir?
paho-mqtt 2.0'dan itibaren mqtt.Client()'ın ilk argümanı callback API sürümüdür. 1.x için yazılmış ve client ID'yi ilk konumsal argüman olarak geçen kod artık bu ValueError'ı fırlatır. Önce mqtt.CallbackAPIVersion.VERSION2'yi, client ID'yi ise client_id= ile geçin.
paho-mqtt 2.x ile eski callback'lerimi kullanmaya devam edebilir miyim?
Evet, geçici olarak. mqtt.CallbackAPIVersion.VERSION1 geçerseniz 1.x callback imzaları çalışmaya devam eder; ancak kütüphane bir DeprecationWarning verir ve sürüm 1'in gelecekteki bir major sürümde kaldırılması planlanmaktadır. Fırsat bulduğunuzda VERSION2'ye geçin.
Güncellemeden sonra 'if rc == 5' kontrolüm neden artık çalışmıyor?
VERSION2 ile on_connect, MQTT 3.1.1'de bile bir ReasonCode nesnesi alır ve 3.1.1 dönüş kodları MQTT 5 reason code'larına çevrilir. 'Not authorized' artık 5 değil, 135'tir (0x87). reason_code.is_failure kullanın ya da ada göre karşılaştırın; örneğin reason_code == 'Not authorized'.

