簡體   English   中英

在 mqtt paho 回調函數中運行 self 對象的問題

[英]Issue running self objects in mqtt paho callback function

我正在嘗試編寫一個腳本來保存 mqtt 數據並將其發送到 influxDB。 我遇到的問題是 mqtt-paho 模塊的回調函數不斷給出錯誤: AttributeError: 'Client' object has no attribute 'write_api' 我想,這是因為的self內部“客戶”類MQTT -泛美衛生組織。 我的完整腳本可以在下面找到:

# Imported modules 
# standard time module
from datetime import datetime
import time
# InfluxDB specific modules 
from influxdb_client import InfluxDBClient, Point, WritePrecision
from influxdb_client.client.write_api import SYNCHRONOUS

#MQTT paho specific modules
import paho.mqtt.client as mqtt



class data_handler(): # Default namespaces are just for all the ESPs.


    def __init__(self, namespace_list=["ESP01","ESP02","ESP03","ESP04","ESP05","ESP06","ESP07","ESP08"]):
        
        # initialize influxdb client and define access token and data bucket
        token = "XXXXXXXXXX" # robotlab's token
        self.org = "Home"   
        self.bucket = "HomeSensors"
        self.flux_client = InfluxDBClient(url="http://localhost:8086", token=token)
        self.write_api = self.flux_client.write_api(write_options=SYNCHRONOUS)
        
        # Initialize and establish connection to MQTT broker 
        broker_address="XXX.XXX.XXX.XXX"
        self.mqtt_client = mqtt.Client("influx_client") #create new instance
        self.mqtt_client.on_message=data_handler.mqtt_message #attach function to callback
        self.mqtt_client.connect(broker_address) #connect to broker

        # Define list of namespaces
        self.namespace_list = namespace_list
        print(self.namespace_list)


    def mqtt_message(self, client, message):
        print("message received " ,str(message.payload.decode("utf-8")))
        print("message topic=",message.topic)
        print("message qos=",message.qos)
        print("message retain flag=",message.retain)
        
        sequence = [message.topic, message.payload.decode("utf-8")]
        self.write_api.write(self.bucket, self.org, sequence)

    def mqtt_listener(self):

        for namespace in self.namespace_list:
            self.mqtt_client.loop_start() #start the loop
            print("Subscribing to topics!")
            message = namespace+"/#"
            self.mqtt_client.subscribe(message, 0)
            time.sleep(4) # wait
            self.mqtt_client.loop_stop() #stop the loop


def main():
    influxHandler = data_handler(["ESP07"])
    influxHandler.mqtt_listener()

if  __name__ == '__main__':
    main()

代碼工作正常,直到我在回調函數中添加self.someVariable 什么是解決這個問題的好方法? 我真的不想創建全局變量,因此我選擇使用一個類。

提前致謝!

當涉及多個類時處理self可能會令人困惑。 paho 庫調用on_message 如下

on_message(self, self._userdata, message)

所以傳遞的第一個參數是Client的實例,所以你看到的是預期的(在沒有任何類的情況下)。

如果回調是一個 方法對象(這似乎是你的目標)“實例對象作為函數的第一個參數傳遞”。 這意味着您的函數將采用四個參數,定義為:

mqtt_message(self, client, userdata, msg)

基於此,您可能希望您的應用程序比它更早失敗,但讓我們看看您如何設置回調:

self.mqtt_client.on_message=data_handler.mqtt_message

datahandler是類本身,而不是類的實例。 這意味着您有效地將回調設置為靜態函數(沒有綁定到類的任何實例 -這個答案可能會有所幫助)。 您需要將其更改為:

self.mqtt_client.on_message=self.mqtt_message

但是,這不起作用,因為該方法目前只需要三個參數; 將定義更新為:

def mqtt_message(self, client, userdata, msg)

有了這些改變,我相信這會奏效(或者至少你會發現另一個問題:-))。

一個例子可能是解釋這一點的更好方法:

class mqtt_sim():
  def __init__(self):
    self._on_message = None
    
  @property
  def on_message(self):
     return self._on_message
      
  @on_message.setter
  def on_message(self, func):
    self._on_message = func

# This is what you are doing    
class data_handler1(): # Default namespaces are just for all the ESPs.
   def __init__(self):
      self.mqtt = mqtt_sim()      
      self.mqtt.on_message = data_handler1.mqtt_message    # xxxxx         
   def mqtt_message(self, client, message):        
      print("mqtt_message1", self, client, message) 

# This is what you should be doing      
class data_handler2(): # Default namespaces are just for all the ESPs.
   def __init__(self):
      self.mqtt = mqtt_sim()      
      self.mqtt.on_message = self.mqtt_message #attach function to callback             
   def mqtt_message(self, mqttself, client, message):        
      print("mqtt_message2", self, mqttself, client, message)    

# Lets try using both of the above      
d = data_handler1()
d.mqtt._on_message("self", "userdata", "message")

d = data_handler2()
d.mqtt._on_message("self", "userdata", "message")

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM