<button id="ssm6u"><optgroup id="ssm6u"></optgroup></button>
  • 跳轉至

    Mqtt

    概要

    本節課講了MQTT協議的特性, MQTT網絡里面的組成部分,以及MQTT通信數據傳輸的流程講解。

    keywords mqtt tcp/ip qos publisher subscriber

    MQTT協議簡介

    ESP32是一款物聯網(IOT, internet of things)模塊. 所謂物聯就是機器與機器之間的通信, 互聯互通之后,設備之間就可以協同工作。 ESP32作為一個單片機,其網絡環境可能是不可靠的, 如果我們采用原始的socket通信,并不能保障信息可以到達接收方,數據的可靠性包括實時性都會有一定的影響, 所以這個時候就需要一種網絡通信協議Protocal 來保障信息的傳遞, 保障服務質量(Qos: Quality of Service)。

    互聯網的基礎網絡協議是 TCP/IP。MQTT(消息隊列遙測傳輸) 是基于 TCP/IP 協議棧而構建的,已成為 IoT 通信的標準。

    MQTT 是一種輕量級的, 靈活的網絡協議,致力于為 IoT 開發人員實現適當的平衡:

    • 這個輕量級協議可在嚴重受限的設備硬件和高延遲/帶寬有限的網絡上實現。

    • 它的靈活性使得為 IoT 設備和服務的多樣化應用場景提供支持成為可能。

    熟悉Web開發的同學,可能會有想法用Http協議來開發物聯網應用, 為什么要用MQTT而不是HTTP,可以參考IBM的這篇文章, 講的比較詳細:初識 MQTT-IBM 。

    總結下來MQTT有如下特性/優勢:

    • 異步消息協議

    • 面向長連接

    • 雙向數據傳輸

    • 協議輕量級

    • 被動數據獲取

    MQTT的發布和訂閱模型

    MQTT_DHT_02-400x258

    注: 圖片來自REF 4

    在基于MQTT協議的IOT網絡里面里面有這么幾個角色:

    a1

    • 發布者 Publisher 負責發布消息, 例如傳感器采集數據,然后發送當前傳感器的信息

    • 訂閱者 Subscriber 訂閱消息,根據獲得的傳感器數據做出對應的動作。

    • *服務器 Server * 信息的中轉站,負責將信息從發布者傳遞到訂閱者。

    其中發布者與訂閱者統稱為客戶端 Client 。

    MQTT_DHT_01-400x157

    注: 圖片來自REF 4

    注意, 這個劃分并不是說三個角色必須是不同的實體設備,這里只是根據功能劃分。有時候一個設備可以同時為發布者或訂閱者, 就連服務器自己也可以作為客戶端。

    注意MQTT是協議,基于TCP/IP, MQTT協議在客戶端的實現稱之為MQTT Client,

    MQTT客戶端的各種實現見: mqtt/libs

    MQTT協議在服務器端的實現稱之為MQTT Broker. MQTT Broker基于各種語言(JAVA, C/C++)的實現,比較流行的MQTT Broker列表見:mqtt server/brokers

    為什么MQTT會被廣泛用于IOT開發?主要還是歸功于它的發布者與訂閱者的設計思想。

    A3

    一個核心思想是,能力越大, 責任越大 .

    我們拿PC與單片機舉例子,從價格上還有硬件的操控能力,傳感器數據讀取方面, 單片機更合適, 如果一個地方需要采集100個位點的溫度信息,可能會選擇使用單片機來讀取,那這么多的單片機之間如何進行通信呢?

    單片機硬件資源有限(內存,帶寬), 就決定了單片機很難與多個客戶端進行通信,同時與多個客戶端建立長連接。 從內存占用,通信時延, 還有數據的穩定性上來講,顯然我們更相信PC在網絡吞吐方面的能力。 另外PC還可以對數據進行數據預處理,然后作為Client發布處理后的數據。

    所以根據各自能力的特點, 我們做如下職責劃分:

    A4

    每個單片機(Client)僅與PC(Server)保持一個長連接, 有什么數據就告訴Server, 如果有其他單片機或者PC跟這個單片機通信, 也只能通過這個Server來獲取, 同時也要注意,這個數據獲取的過程是被動的, 單片機沒有主動輪詢, 整個過程是異步的, 數據傳過來,自動調用回調函數, 所以Server就成了這個單片機與這個周邊設備通信的唯一的渠道,這個機制使得整個過程更加輕量級與高效 。

    有點像一個地下組織的老大帶領著一幫小弟的感覺, 小弟之間互不聯系, 直接向老大傳遞信息, 老大像小弟傳遞指令。

    dataframe

    通信所用的數據幀 Data Frame主要由主題編號 Topic ID 還有信息 Message 兩部分組成。

    發布者與訂閱者之間是沒辦法直接感知到對方的存在的, 訂閱者與發布者之間通過數據幀 Data Frame 里面的主題編號Topic ID 來獲取自己想要的數據。

    MQTT通信流程詳細描述

    舉一個遠程控制LED燈亮滅的實際例子, 我們這里梳理一下過程。

    ESP32與PC連入同一個局域網下, 獲取PC 的IP地址

    局域網

    PC開啟 MQTT Broker, 開啟Server模式

    mqtt broker

    ESP32傳入PC的IP地址還有端口號,創建一個MQTT_Client

    ESP32的MQTT_Client與PC上的MQTT_Server創建一個長連接

    ESP32的MQTT_Client 訂閱Topic LED_CONTROL

    6-4

    PC上創建一個CLIENT, Client里面傳入本地IP與MQTT Broker服務的端口號, 與PC上面的Server建立一個長連接

    img

    PC上的Client, 發送數據幀 Topic ID + 指令, Topic ID為LED Control

    數據幀: TOPIC_ID: LED_CONTROL, MESSAGE: LED_ON

    send dataframe

    數據發送給Server, Server發現ESP32開發板訂閱了LED_CONTROL 這個主題, 然后就通過ESP32與Server創建的連接發送該數據幀。

    ESP32接收到這個數據幀,發現TOPIC_ID: LED_CONTROL, 于是知道這個是跟LED控制相關的指令。

    讀取到MESSAGE是LED_ON, ESP32執行指令led.on() , LED打開。

    led on

    讀完這篇文章,相信你對MQTT已經躍躍欲試了,下一節課,阿凱帶你在局域網下用Python實現MQTT通信。見課程: MQTT入門之項目實戰

    MQTT實戰演練

    Mosquitto

    安裝Mosquitto

    在Ubuntu上面搭建MQTT的開發環境,可以選擇Mosquitto, Mosquitto是Eclipse開源的項目, 官網: mosquitto.org。

    其中mosquitto就是MQTT Broker的實現, mosquitto-clients是MQTT客戶端的實現。

    sudo apt-get install mosquitto mosquitto-clients 
    

    mosquitto_pub

    -t 代表指定topic

    -m 代表message信息

    mosquitto_pub -t 'pyespcar_basic_control' -m 'MOVE_FORWARD'
    

    在中端上執行上面的這條信息,等于在主題pyespcar_basic_control 下發布一條信息MOVE_FORWARD

    mosquitto_sub

    安裝成功之后, 你可以通過mosquitto_sub 指令, 在中端獲取特定Topic的數據。

    mosquitto_sub  -t 'pyespcar_basic_control'
    

    綜合實驗

    打開終端的兩個窗口, 首先開啟接收者的服務。

    mosquitto_sub  -t 'pyespcar_basic_control'
    

    然后嘗試在另外一個窗口發送信息:

    mosquitto_pub -t 'pyespcar_basic_control' -m 'MOVE_FORWARD'
    

    img

    注: 因為Server的默認IP就是localhost, IP默認就是1883,所以這里不需要指定。 更詳細的參數介紹見官方文檔:

    paho-mqtt

    安裝paho-mqtt

    另外我們還希望可以使用Python 進行基于MQTT的物聯網開發, 這就需要用使用pip3安裝另外一個庫 paho-mqtt , 官網https://www.eclipse.org/paho/.

    The Eclipse Paho project provides open-source client implementations of MQTT and MQTT-SN messaging protocols aimed at new, existing, and emerging applications for the Internet of Things (IoT).

    sudo pip3 install paho-mqtt
    

    使用paho-mqtt實現接收者

    pc/paho-mqtt-subsriber.py
    import paho.mqtt.client as mqtt
    
    def on_message(client, userdata, msg):
        '''處理message回調'''
        print('topic: {}'.format(msg.topic))
        print('message: {}'.format(str(msg.payload)))
    
    # 建立一個MQTT的客戶端
    client = mqtt.Client()
    # 綁定數據接收回調函數
    client.on_message = on_message
    
    HOST_IP = 'localhost' # Server的IP地址
    HOST_PORT = 1883 # mosquitto 默認打開端口
    TOPIC_ID = 'pyespcar_basic_control' # TOPIC的ID
    
    # 連接MQTT服務器
    client.connect(HOST_IP, HOST_PORT, 60)
    # 訂閱主題
    client.subscribe(TOPIC_ID)
    
    # 阻塞式, 循環往復,一直處理網絡數據,斷開重連
    client.loop_forever()
    

    使用paho-mqtt實現發布者

    pc/paho-mqtt-publisher.py
    import paho.mqtt.client as mqtt
    import time
    
    HOST_IP = 'localhost' # Server的IP地址
    HOST_PORT = 1883 # mosquitto 默認打開端口
    TOPIC_ID = 'pyespcar_basic_control' # TOPIC的ID
    
    # 創建一個客戶端
    client = mqtt.Client()
    # 連接到服務器(本機)
    client.connect(HOST_IP, HOST_PORT, 60)
    
    count = 0
    while True:
        count += 1
        # 待發送的數據
        message = 'MOVE FRORWORD,{}'.format(count)   
        # 通過mqtt協議發布數據給server
        client.publish(TOPIC_ID, message)
        # 打印日志
        print('SEND: {}'.format(message))
        # 延時1s
        time.sleep(1)
    

    綜合實驗

    可以在本地的終端打開兩個串口,分別輸入指令:

    # 運行訂閱者
    python3 paho-mqtt-subsriber.py
    # 運行發布者
    python3 paho-mqtt-subsriber.py
    

    功能其實跟上文的Mosquitto例程差不多。

    paho-mqtt_pub_sub

    左邊是接收者的進程, 右邊是發送者的進程, 這里大家留意一下,接收者在接收的時候數據打印出來是這樣的:

    topic: pyespcar_basic_control
    message: b'MOVE FRORWORD,175'
    

    這里的b'MOVE FRORWORD,175' 是字節bytes類型的數據, 在Http通信的過程中數據以utf-8 編碼的方式,傳遞字節數據。

    通過decode方法, 可以把bytes類型的數據轉換為字符串。

    In [1]: bdata = b'MOVE FRORWORD,175'
    In [2]: bdata.decode('utf-8')
    Out[2]: 'MOVE FRORWORD,175'
    

    MQTT與ESP32-MicroPython

    之前的歷程都是在Ubuntu的本機上測試的, 真正的物聯網怎么少的了單片機呢, 我們這里把單片機(MicroPython-ESP32)結合進來。

    在ESP32上安裝MQTT庫

    首先,我們需要在ESP32上面安裝mqtt的庫。(MQTT客戶端在ESP32上面的實現)

    首先確認ESP32-MicroPython已經連接上了熱點?。?!, 通過REPL控制ESP32。

    引入upip包管理器

    >>> import upip
    >>> upip.install('micropython-umqtt.simple')
    Installing to: /lib/
    Installing micropython-umqtt.simple 1.3.4 from https://files.pythonhosted.org/packages/bd/cf/697e3418b2f44222b3e848078b1e33ee76aedca9b6c2430ca1b1aec1ce1d/micropython-umqtt.simple-1.3.4.tar.gz
    

    這樣umqtt.simple這個包就安裝好了。

    查看Server的IP地址

    查看PC當前的IP, 在Ubuntu(作為Server)的命令行里面執行指令:

    ifconfig
    ?  下載 ifconfig 
    enp3s0    Link encap:以太網  硬件地址 5c:f9:dd:49:4b:ad  
              UP BROADCAST MULTICAST  MTU:1500  躍點數:1
              接收數據包:0 錯誤:0 丟棄:0 過載:0 幀數:0
              發送數據包:0 錯誤:0 丟棄:0 過載:0 載波:0
              碰撞:0 發送隊列長度:1000 
              接收字節:0 (0.0 B)  發送字節:0 (0.0 B)
              中斷:16 
    
    lo        Link encap:本地環回  
              inet 地址:127.0.0.1  掩碼:255.0.0.0
              inet6 地址: ::1/128 Scope:Host
              UP LOOPBACK RUNNING  MTU:65536  躍點數:1
              接收數據包:256668 錯誤:0 丟棄:0 過載:0 幀數:0
              發送數據包:256668 錯誤:0 丟棄:0 過載:0 載波:0
              碰撞:0 發送隊列長度:1000 
              接收字節:138568580 (138.5 MB)  發送字節:138568580 (138.5 MB)
    
    wlp2s0    Link encap:以太網  硬件地址 68:5d:43:ec:d3:58  
              inet 地址:192.168.43.16  廣播:192.168.43.255  掩碼:255.255.255.0
              inet6 地址: fe80::47ef:2ce1:f8e9:b0c2/64 Scope:Link
              UP BROADCAST RUNNING MULTICAST  MTU:1500  躍點數:1
              接收數據包:146459 錯誤:0 丟棄:0 過載:0 幀數:0
              發送數據包:137348 錯誤:0 丟棄:0 過載:0 載波:0
              碰撞:0 發送隊列長度:1000 
              接收字節:147948142 (147.9 MB)  發送字節:20083083 (20.0 MB)
    

    192.168.43.16 當前PC在局域網的IP地址為

    使用umqtt實現接收者

    esp32/subscriber.py
    from umqtt.simple import MQTTClient
    import time
    
    SERVER = '192.168.43.16'
    CLIENT_ID = 'PYESPCAR_A0'
    TOPIC = b'pyespcar_basic_control'
    
    def mqtt_callback(topic, msg):
        print('topic: {}'.format(topic))
        print('msg: {}'.format(msg))
    
    
    client = MQTTClient(CLIENT_ID, SERVER)
    client.set_callback(mqtt_callback)
    client.connect()
    
    client.subscribe(TOPIC)
    
    
    while True:
        # 查看是否有數據傳入
        # 有的話就執行 mqtt_callback
        client.check_msg()
        time.sleep(1)
    

    使用umqtt實現發送者

    esp32/publisher.py
    from umqtt.simple import MQTTClient
    import time
    
    SERVER = '192.168.43.16'
    CLIENT_ID = 'PYESPCAR_A0' # 客戶端的ID
    TOPIC = b'pyespcar_basic_control' # TOPIC的ID
    
    client = MQTTClient(CLIENT_ID, SERVER)
    client.connect()
    
    
    while True:
        client.publish(TOPIC, 'helloworld')
        time.sleep(1)
    

    注意在Esp32里面TOPIC需要是bytes類型。

    綜合實驗

    你可以結合paho-mqtt里面的發送者與esp32里面的接收者進行測試。

    也可以使用paho-mqtt里面的接收者與esp32里面的發送者進行測試。

    作業

    在PC上封裝一個庫,可以通過MQTT遠程控制ESP32上面的LED亮滅。

    上文MQTT入門之概念解析,已經把程序的整個流程列給你了。


    韩国精品无码一区二区三区,精品无码一区二区三区AV,欧洲丰满美熟女乱又伦AV,亚洲午夜久久久影院伊人