解鎖 MQTT Wildcards ( 通配符 )的力量 | 深入解析 + 和 #


在物聯網(IoT)領域中,MQTT(消息隊列遙測傳輸)作為一種輕量級的消息傳遞協議,廣泛應用於各種設備之間的通信。它基於 發布/訂閱模式,利用主題(Topic)來組織消息流。對開發者而言,主題的設計和訂閱模式至關重要,這裡的 MQTT Wildcards (通配符) 起到了極其重要的作用。

如果你曾經在 MQTT 中處理過主題訂閱,你就會知道,訂閱某一個特定主題可能會變得繁瑣,尤其當你的系統有很多變量和層級時。這時,通配符就成為了強大的工具,幫助你簡化主題訂閱,讓你的系統變得更加靈活且易於擴展。

MQTT Wildcards

什麼是 MQTT Wildcards (通配符)

在 MQTT 中,主題 是用來標識訊息流的“地址”。每個設備、感測器或應用程式都會根據特定的主題來發送或接收消息。然而,有時候你並不想訂閱某一個具體的主題,而是希望接收符合某些模式的多個主題。這時候,通配符就派上用場了。

MQTT Wildcards (通配符) 允許你在訂閱時匹配多個主題,這不僅能讓你減少訂閱的數量,還能增強系統的可擴展性和靈活性。MQTT 支援兩種常用的通配符:單層通配符(+多層通配符(#

通配符的詳細解析

+ 是一個單層 MQTT Wildcard (通配符),它能夠匹配主題中的任意一層,但只限於單層。如果主題結構中有多層,+ 只能匹配一層,不能跨層匹配。

假設你的主題結構如下:

  • home/livingroom/temperature
  • home/kitchen/temperature
  • home/livingroom/humidity

如果你訂閱 home/+/temperature,你會收到以下消息:

  • home/livingroom/temperature
  • home/kitchen/temperature

home/livingroom/humidity 不會匹配,因為 + 只會匹配 temperature 層級,並且無法跨越子層。

使用場景 :

  • 當你想要訂閱某一層級的所有子主題時,可以使用 + 來代替具體的層級。
  • 例如,在家庭自動化系統中,你可以訂閱 home/+/temperature,這樣你就能接收到每個房間的溫度數據,而不需要為每個房間分別訂閱。

# 是一個多層 MQTT Wildcard (通配符),能夠匹配任意層級的所有子層級。這是 MQTT 中最強大的通配符,尤其在有大量設備或多層級主題結構時,能夠顯著簡化訂閱過程。# 只能出現在主題的結尾,如果出現在其他位置,訂閱會失敗。

假設你的主題結構如下:

  • home/livingroom/temperature
  • home/kitchen/temperature
  • home/livingroom/temperature/room1
  • home/livingroom/humidity

如果你訂閱 home/#,你將會收到:

  • home/livingroom/temperature
  • home/kitchen/temperature
  • home/livingroom/temperature/room1
  • home/livingroom/humidity

這是因為 # 匹配了 home/ 後的所有子主題。

使用場景 :

  • 當你希望接收某個範圍內的所有消息時,# 是理想的選擇。比如你有很多房間,並希望接收所有房間的數據,可以訂閱 home/#,這樣不管有多少房間,所有以 home/ 開頭的數據都會自動進來。

表格說明 +# 的區別

特性單層 MQTT Wildcard (通配符) +多層 MQTT Wildcard (通配符) #
匹配範圍只能匹配一層匹配從指定層級開始的所有層級
位置限制可以出現在主題的任何層級只能出現在主題的末尾
典型用法當你只關心某一層級時當你需要訂閱多層級時

如何在 MQTT 中使用這些通配符

讓我們來看看如何使用 Python 客戶端來訂閱帶有通配符的主題。這裡我們使用 paho-mqtt 庫來實現。

首先,安裝 paho-mqtt 客戶端庫

pip install paho-mqtt

範例代碼

import paho.mqtt.client as mqtt
import warnings

# Disable DeprecationWarnings
warnings.filterwarnings("ignore", category=DeprecationWarning)

# Set the MQTT broker address (using HiveMQ broker)
broker = "broker.hivemq.com"

# Set the topic to subscribe to
topic = "home/+/temperature"

# Callback function that gets triggered when a message is received
def on_message(client, userdata, message):
    # Decode the payload (message content)
    payload = message.payload.decode()
    print(f"Received message: {payload}")
    
    # If the message contains 'Temperature', extract and print the temperature value
    if "Temperature" in payload:
        # Extract the numeric part of the temperature (e.g., "23°C")
        temperature = float(payload.split(":")[1].strip().replace("°C", ""))
        print(f"Temperature value: {temperature}°C")
    
    # If the message is a numeric value (e.g., 29.60), process it
    elif payload.replace(".", "", 1).isdigit():
        value = float(payload)  # Convert the string to a float
        print(f"Numeric value: {value}")
    
    # If the message does not match any expected pattern
    else:
        print("Received message in unexpected format")

# Create an MQTT client instance
client = mqtt.Client(client_id="pythonClient", protocol=mqtt.MQTTv5)
client.on_message = on_message  # Assign the callback function to handle incoming messages

# Connect to the MQTT broker
client.connect(broker)

# Subscribe to the topic with a wildcard to capture all temperature readings
client.subscribe(topic)

# Keep the client running to wait for messages
client.loop_forever()

程式碼說明

  • warnings.filterwarnings("ignore", category=DeprecationWarning):這一行用來忽略 DeprecationWarning 警告訊息,防止它在控制台中列印。
  • on_message 回呼函数:這個回呼函數會在接收到MQTT 訊息時觸發,它首先列印接收到的訊息內容,如果訊息包含Temperature 字串,它會提取出溫度資料(假設訊息格式為Temperature: 23°C),如果訊息是一個數字(如29.60),則將其作為浮動數值處理,並可以在else 中加入更多的邏輯來處理其他類型的訊息。
  • client.connect(broker):連接到指定的 MQTT 伺服器。
  • client.subscribe(topic):訂閱一個或多個主題。在這個範例中,使用了一個有萬用字元的主題 “home/+/temperature”,這表示訂閱所有 “home/裝置類型/temperature” 格式的主題。
  • client.loop_forever():啟動 MQTT 用戶端的迴圈,使其能夠持續接收並處理訊息。

輸出

假設 MQTT 伺服器發布瞭如下訊息:

  • "Temperature: 23°C"
  • "29.60"
  • "2"

運行時的輸出將類似於:

Received message: Temperature: 23°C
Temperature value: 23.0°C
Received message: 29.60
Numeric value: 29.6
Received message: 2
Numeric value: 2.0

為什麼使用通配符

  • 減少訂閱數量
    通配符讓你可以在不需要精確指定每個設備的情況下,簡化訂閱過程。你只需要訂閱更高層級的主題,就能接收到來自不同設備的消息。
  • 提高靈活性
    隨著系統的擴展,傳統的手動訂閱方法可能會變得冗長且難以管理。而使用通配符,你可以更輕鬆地處理不同層級的消息流,避免硬編碼每個設備的主題。
  • 提升可維護性
    通配符使得在需要添加新的設備或新的功能時,無需更改訂閱邏輯。只需確保新設備的主題結構符合已有的規範即可。

智能家居系統

假設你有一個智能家居系統,涉及多個房間,每個房間有不同的感測器,如溫度、濕度、光線等。傳統方法會讓你為每個房間的每個感測器分別訂閱主題,這會造成訂閱數量激增,並難以維護。使用 MQTT Wildcards (通配符) 後,你只需要訂閱:

  • home/+/temperature:接收所有房間的溫度數據。
  • home/#:接收所有房間的所有數據(溫度、濕度等)。

這樣,你的訂閱就變得更簡單,且能輕鬆應對新的房間或設備。

結論

MQTT 的 **通配符** 功能是開發者在構建物聯網系統時不可或缺的工具。無論是單層 MQTT Wildcard (通配符) + 還是多層 MQTT Wildcard (通配符) #,它們都能幫助你簡化訂閱邏輯,提升系統的靈活性和可擴展性。理解和合理使用這些 MQTT Wildcards (通配符),可以大大提高開發效率,並為未來的擴展和維護奠定堅實基礎。

希望這篇文章能夠幫助你更好地理解和使用 MQTT 的 MQTT Wildcards (通配符),並提升你在物聯網開發中的能力!