跳至主要内容

將您的設備連接到互聯網

本課程的手繪筆記概述

手繪筆記由 Nitya Narasimhan 提供。點擊圖片查看大圖。

本課程是 Hello IoT 系列 的一部分,由 Microsoft Reactor 教授。課程分為兩個視頻 - 一個小時的課程和一個小時的辦公時間,深入探討課程的部分內容並回答問題。

課程 4:將您的設備連接到互聯網

課程 4:將您的設備連接到互聯網 - 辦公時間

🎥 點擊上方圖片觀看視頻

課前測驗

課前測驗

介紹

IoT 中的 I 代表 Internet(互聯網) - 雲端連接和服務使 IoT 設備的許多功能成為可能,從收集連接到設備的傳感器的測量數據,到發送消息控制執行器。IoT 設備通常使用標準通信協議連接到單個雲端 IoT 服務,該服務連接到您的 IoT 應用程序的其餘部分,從 AI 服務到根據您的數據做出智能決策,到用於控制或報告的 Web 應用程序。

🎓 從傳感器收集並發送到雲端的數據稱為遙測數據。

IoT 設備可以接收來自雲端的消息。這些消息通常包含命令 - 即執行某個動作的指令,無論是內部操作(如重啟或更新固件),還是使用執行器(如打開燈)。

本課程介紹了 IoT 設備用於連接到雲端的一些通信協議,以及它們可能發送或接收的數據類型。您還將親自操作它們,將互聯網控制添加到您的夜燈中,將 LED 控制邏輯移動到本地運行的“服務器”代碼中。

在本課程中,我們將涵蓋:

通信協議

有許多流行的通信協議可供 IoT 設備用來與互聯網通信。最流行的是基於某種代理的發布/訂閱消息傳遞。IoT 設備連接到代理並發布遙測數據並訂閱命令。雲端服務也連接到代理並訂閱所有遙測消息,並發布命令給特定設備或設備組。

IoT 設備連接到代理並發布遙測數據並訂閱命令。雲端服務連接到代理並訂閱所有遙測數據並向特定設備發送命令。

MQTT 是 IoT 設備最流行的通信協議,本課程將介紹它。其他協議包括 AMQP 和 HTTP/HTTPS。

消息隊列遙測傳輸 (MQTT)

MQTT 是一種輕量級的開放標準消息傳遞協議,可以在設備之間發送消息。它於 1999 年設計用於監控石油管道,15 年後由 IBM 發布為開放標準。

MQTT 有一個單一的代理和多個客戶端。所有客戶端都連接到代理,代理將消息路由到相關的客戶端。消息通過命名主題進行路由,而不是直接發送到單個客戶端。客戶端可以發布到一個主題,任何訂閱該主題的客戶端都會收到消息。

IoT 設備在 /telemetry 主題上發布遙測數據,雲端服務訂閱該主題

✅ 做一些研究。如果您有很多 IoT 設備,如何確保您的 MQTT 代理能夠處理所有消息?

將您的 IoT 設備連接到 MQTT

將互聯網控制添加到您的夜燈的第一步是將其連接到 MQTT 代理。

任務

將您的設備連接到 MQTT 代理。

在本課程的這一部分,您將把您的 IoT 夜燈連接到互聯網,以便遠程控制。稍後在本課程中,您的 IoT 設備將通過 MQTT 向公共 MQTT 代理發送光照水平的遙測消息,這些消息將由您編寫的一些服務器代碼接收。該代碼將檢查光照水平並發送命令消息回設備,告訴它打開或關閉 LED。

這種設置的現實世界用例可能是從多個光傳感器收集數據,然後決定是否打開燈光,例如在有很多燈光的地方,如體育場。如果只有一個傳感器被雲或鳥遮擋,但其他傳感器檢測到足夠的光線,這可以防止燈光被打開。

✅ 還有哪些情況需要在發送命令之前評估多個傳感器的數據?

為了避免在本次作業中設置 MQTT 代理的複雜性,您可以使用運行 Eclipse Mosquitto 的公共測試服務器,這是一個開源的 MQTT 代理。此測試代理可在 test.mosquitto.org 公開使用,無需設置帳戶,是測試 MQTT 客戶端和服務器的絕佳工具。

💁 此測試代理是公開的且不安全。任何人都可以收聽您發布的內容,因此不應使用任何需要保密的數據

作業流程圖顯示光照水平被讀取和檢查,並控制 LED

按照以下相關步驟將您的設備連接到 MQTT 代理:

深入了解 MQTT

主題可以有層次結構,客戶端可以使用通配符訂閱層次結構的不同級別。例如,您可以將溫度遙測消息發送到 /telemetry/temperature 主題,將濕度消息發送到 /telemetry/humidity 主題,然後在您的雲應用程序中訂閱 /telemetry/* 主題以接收溫度和濕度遙測消息。

消息可以以服務質量 (QoS) 發送,這決定了消息被接收的保證。

  • 最多一次 - 消息僅發送一次,客戶端和代理不採取額外步驟確認交付(發送即忘)。
  • 至少一次 - 發送方多次重試消息,直到收到確認(確認交付)。
  • 僅一次 - 發送方和接收方進行兩級握手以確保僅接收一份消息(保證交付)。

✅ 在什麼情況下需要保證交付消息而不是發送即忘消息?

儘管名稱是消息隊列(MQTT 的首字母縮寫),但它實際上不支持消息隊列。這意味著如果客戶端斷開連接,然後重新連接,它不會收到斷開連接期間發送的消息,除了那些它已經開始處理的消息,使用 QoS 過程。消息可以設置保留標誌。如果設置了此標誌,MQTT 代理將存儲在該主題上發送的最後一條消息,並將其發送給後來訂閱該主題的任何客戶端。這樣,客戶端將始終獲取最新消息。

MQTT 還支持保持活動功能,在消息之間的長時間間隔期間檢查連接是否仍然存在。

🦟 Eclipse Foundation 的 Mosquitto 提供了一個免費的 MQTT 代理,您可以自行運行以實驗 MQTT,還提供了一個公共 MQTT 代理,您可以用來測試您的代碼,託管在 test.mosquitto.org

MQTT 連接可以是公開和開放的,也可以使用用戶名和密碼或證書進行加密和保護。

💁 MQTT 通過 TCP/IP 進行通信,與 HTTP 使用相同的底層網絡協議,但在不同的端口上。您還可以使用 Websockets 通過瀏覽器中運行的 Web 應用程序進行通信,或在防火牆或其他網絡規則阻止標準 MQTT 連接的情況下進行通信。

遙測數據

遙測這個詞源自希臘語,意思是遠程測量。遙測是從傳感器收集數據並將其發送到雲端的行為。

💁 最早的遙測設備之一於 1874 年在法國發明,實時發送來自勃朗峰的天氣和積雪深度數據到巴黎。當時使用的是物理電線,因為當時無線技術尚未出現。

讓我們回顧一下第 1 課中的智能恆溫器示例。

使用多個房間傳感器的互聯網連接恆溫器

恆溫器具有溫度傳感器來收集遙測數據。它很可能內置一個溫度傳感器,並且可能通過無線協議(如 藍牙低功耗 (BLE))連接到多個外部溫度傳感器。

它將發送的遙測數據示例如下:

名稱描述
thermostat_temperature18°C由恆溫器內置溫度傳感器測量的溫度
livingroom_temperature19°C由遠程溫度傳感器測量的溫度,該傳感器已命名為 livingroom 以識別其所在的房間
bedroom_temperature21°C由遠程溫度傳感器測量的溫度,該傳感器已命名為 bedroom 以識別其所在的房間

雲端服務可以使用這些遙測數據來決定發送哪些命令來控制加熱。

從您的 IoT 設備發送遙測數據

將互聯網控制添加到您的夜燈的下一步是將光照水平遙測數據發送到 MQTT 代理的遙測主題。

任務 - 從您的 IoT 設備發送遙測數據

將光照水平遙測數據發送到 MQTT 代理。

數據以 JSON 編碼 - JSON 是 JavaScript Object Notation 的縮寫,是一種使用鍵/值對在文本中編碼數據的標準。

✅ 如果您之前沒有接觸過 JSON,可以在 JSON.org 文檔 上了解更多信息。

按照以下相關步驟將您的設備的遙測數據發送到 MQTT 代理:

從 MQTT 代理接收遙測數據

如果沒有另一端的接收器,發送遙測數據是沒有意義的。光照水平遙測數據需要有東西來接收並處理數據。這個“服務器”代碼是您將作為更大 IoT 應用程序的一部分部署到雲端服務的代碼,但在這裡,您將在本地計算機上運行此代碼(或在您的 Pi 上,如果您直接在那裡編碼)。服務器代碼由一個 Python 應用程序組成,該應用程序通過 MQTT 接收光照水平的遙測消息。稍後在本課程中,您將使其回復一條命令消息,指示打開或關閉 LED。

✅ 做一些研究:如果沒有接收器,MQTT 消息會發生什麼?

安裝 Python 和 VS Code

如果您本地沒有安裝 Python 和 VS Code,您需要安裝它們來編寫服務器代碼。如果您使用虛擬 IoT 設備或在 Raspberry Pi 上工作,則可以跳過此步驟,因為您應該已經安裝並配置了它們。

任務 - 安裝 Python 和 VS Code

安裝 Python 和 VS Code。

  1. 安裝 Python。請參閱 Python 下載頁面 以獲取安裝最新版本 Python 的說明。

  2. 安裝 Visual Studio Code (VS Code)。這是您將用來編寫 Python 虛擬設備代碼的編輯器。請參閱 VS Code 文檔 以獲取安裝 VS Code 的說明。

    💁 如果您有首選的工具,可以自由使用任何 Python IDE 或編輯器來完成這些課程,但課程將基於使用 VS Code 提供說明。

  3. 安裝 VS Code Pylance 擴展。這是 VS Code 的一個擴展,提供 Python 語言支持。請參閱 Pylance 擴展文檔 以獲取在 VS Code 中安裝此擴展的說明。

配置 Python 虛擬環境

Python 的一個強大功能是能夠安裝 pip 包 - 這些是其他人編寫並發布到互聯網上的代碼包。您可以使用一個命令將 pip 包安裝到您的計算機上,然後在您的代碼中使用該包。您將使用 pip 安裝一個用於通過 MQTT 進行通信的包。

默認情況下,當您安裝一個包時,它在您的計算機上隨處可用,這可能會導致包版本問題 - 例如一個應用程序依賴於一個包的版本,而當您為另一個應用程序安裝新版本時會出現問題。為了解決這個問題,您可以使用 Python 虛擬環境,本質上是 Python 的副本在一個專用文件夾中,當您安裝 pip 包時,它們只會安裝到該文件夾中。

任務 - 配置 Python 虛擬環境

配置 Python 虛擬環境並安裝 MQTT pip 包。

  1. 從您的終端或命令行,在您選擇的位置運行以下命令以創建並導航到新目錄:

    mkdir nightlight-server
    cd nightlight-server
  2. 現在運行以下命令在 .venv 文件夾中創建虛擬環境

    python3 -m venv .venv

    💁 您需要顯式調用 python3 來創建虛擬環境,以防您同時安裝了 Python 2 和 Python 3(最新版本)。如果您安裝了 Python 2,則調用 python 將使用 Python 2 而不是 Python 3

  3. 激活虛擬環境:

    • 在 Windows 上:

      • 如果您使用命令提示符或通過 Windows 終端使用命令提示符,請運行:

        .venv\Scripts\activate.bat
      • 如果您使用 PowerShell,請運行:

        .\.venv\Scripts\Activate.ps1
    • 在 macOS 或 Linux 上,請運行:

      source ./.venv/bin/activate

    💁 這些命令應在您創建虛擬環境時運行的相同位置運行。您永遠不需要導航到 .venv 文件夾,您應該始終從創建虛擬環境時所在的文件夾運行激活命令和任何安裝包或運行代碼的命令。

  4. 一旦虛擬環境被激活,默認的 python 命令將運行用於創建虛擬環境的 Python 版本。運行以下命令以獲取版本:

    python --version

    輸出將類似於以下內容:

    (.venv) ➜  nightlight-server python --version
    Python 3.9.1

    💁 您的 Python 版本可能不同 - 只要是 3.6 或更高版本即可。如果不是,請刪除此文件夾,安裝更新版本的 Python 並重試。

  5. 運行以下命令以安裝 Paho-MQTT 的 pip 包,這是一個流行的 MQTT 庫。

    pip install paho-mqtt

    此 pip 包僅安裝在虛擬環境中,並且在此之外不可用。

編寫服務器代碼

現在可以用 Python 編寫服務器代碼。

任務 - 編寫服務器代碼

編寫服務器代碼。

  1. 從您的終端或命令行,在虛擬環境中運行以下命令以創建一個名為 app.py 的 Python 文件:

    • 在 Windows 上運行:

      type nul > app.py
    • 在 macOS 或 Linux 上運行:

      touch app.py
  2. 在 VS Code 中打開當前文件夾:

    code .
  3. 當 VS Code 啟動時,它將激活 Python 虛擬環境。這將在底部狀態欄中報告:

    VS Code 顯示選擇的虛擬環境

  4. 如果 VS Code 終端在 VS Code 啟動時已經運行,則它不會在其中激活虛擬環境。最簡單的方法是使用 Kill the active terminal instance 按鈕終止終端:

    VS Code 終止活動終端實例按鈕

  5. 通過選擇 終端 -> 新終端 或按 CTRL+` 啟動新的 VS Code 終端。新終端將加載虛擬環境,並在終端中顯示激活此環境的調用。提示符中還會顯示虛擬環境的名稱 (.venv):

    ➜  nightlight-server source .venv/bin/activate
    (.venv) ➜ nightlight
  6. 從 VS Code 資源管理器中打開 app.py 文件並添加以下代碼:

    import json
    import time

    import paho.mqtt.client as mqtt

    id = '<ID>'

    client_telemetry_topic = id + '/telemetry'
    client_name = id + 'nightlight_server'

    mqtt_client = mqtt.Client(client_name)
    mqtt_client.connect('test.mosquitto.org')

    mqtt_client.loop_start()

    def handle_telemetry(client, userdata, message):
    payload = json.loads(message.payload.decode())
    print("Message received:", payload)

    mqtt_client.subscribe(client_telemetry_topic)
    mqtt_client.on_message = handle_telemetry

    while True:
    time.sleep(2)

    將第 6 行的 <ID> 替換為您創建設備代碼時使用的唯一 ID。

    ⚠️ 這 必須 是您在設備上使用的相同 ID,否則服務器代碼將無法訂閱或發布到正確的主題。

    此代碼創建一個具有唯一名稱的 MQTT 客戶端,並連接到 test.mosquitto.org 代理。然後它啟動一個處理循環,在後台線程中運行,監聽任何訂閱主題的消息。

    然後客戶端訂閱遙測主題上的消息,並定義一個在接收到消息時調用的函數。當接收到遙測消息時,handle_telemetry 函數被調用,將接收到的消息打印到控制台。

    最後,一個無限循環保持應用程序運行。MQTT 客戶端在後台線程中監聽消息,並在主應用程序運行時一直運行。

  7. 從 VS Code 終端運行以下命令以運行您的 Python 應用程序:

    python app.py

    該應用程序將開始接收來自 IoT 設備的消息。

  8. 確保您的設備正在運行並發送遙測消息。調整您的物理或虛擬設備檢測到的光照水平。接收到的消息將打印到終端。

    (.venv) ➜  nightlight-server python app.py
    Message received: {'light': 0}
    Message received: {'light': 400}

    nightlight 虛擬環境中的 app.py 文件必須運行,nightlight-server 虛擬環境中的 app.py 文件才能接收發送的消息。

💁 您可以在 code-server/server 文件夾中找到此代碼。

應該多頻繁發送遙測數據?

遙測數據應該多頻繁測量和發送?答案是 - 視情況而定。如果您經常測量,您可以更快地響應測量變化,但您會消耗更多的電力、更多的帶寬、生成更多的數據,並需要更多的雲端資源來處理。您需要經常測量,但不要過於頻繁。

對於恆溫器,每幾分鐘測量一次可能已經足夠,因為溫度不會經常變化。如果您一天只測量一次,那麼您可能會在陽光明媚的白天因夜間溫度而加熱您的房子,而如果您每秒測量一次,您將有數千個不必要的重複溫度測量,這會消耗用戶的網速和帶寬(對於有限帶寬計劃的用戶來說是一個問題),消耗更多的電力,這對於像遠程傳感器這樣的電池供電設備來說是一個問題,並增加提供者處理和存儲它們的雲計算資源的成本。

如果您在監控工廠中的機器設備,如果它故障可能會造成災難性損壞和數百萬美元的損失,那麼每秒多次測量可能是必要的。最好浪費帶寬也不要錯過表明機器需要停止和修理的遙測數據。

💁 在這種情況下,您可能會考慮使用邊緣設備來首先處理遙測數據,以減少對互聯網的依賴。

連接中斷

互聯網連接可能不可靠,停機是常見的。IoT 設備在這種情況下應該怎麼做 - 應該丟失數據還是應該存儲數據直到連接恢復?答案是視情況而定。

對於恆溫器,數據可能會在新溫度測量完成後丟失。加熱系統不關心 20 分鐘前的溫度是 20.5°C 還是現在的溫度是 19°C,現在的溫度決定了加熱是否應該開啟或關閉。

對於機器設備,您可能希望保留數據,特別是如果它用於查找趨勢。有機器學習模型可以通過查看一段時間內的數據(例如過去一小時)並發現異常數據來檢測數據流中的異常。這通常用於預測性維護,尋找可能表明某些東西即將損壞的跡象,以便在損壞之前進行修理或更換。您可能希望發送機器的每一個遙測數據,以便它可以用於異常檢測,因此一旦 IoT 設備可以重新連接,它將發送在互聯網中斷期間生成的所有遙測數據。

IoT 設備設計者還應考慮 IoT 設備在互聯網中斷或由於位置原因信號丟失時是否可以使用。智能恆溫器應該能夠在無法將遙測數據發送到雲端的情況下做出一些有限的決策來控制加熱。

這輛法拉利因為有人在地下沒有手機信號的地方嘗試升級而變磚了

為了讓 MQTT 處理連接中斷,設備和服務器代碼需要負責確保消息交付,如果需要,例如通過要求所有發送的消息都由回復主題上的附加消息回復,如果沒有,它們將手動排隊以便稍後重播。

命令

命令是雲端發送給設備的消息,指示它執行某些操作。大多數情況下,這涉及通過執行器進行某種輸出,但也可以是設備本身的指令,例如重啟或收集額外的遙測數據並作為命令的回應返回。

接收到打開加熱命令的互聯網連接恆溫器

恆溫器可以接收到來自雲端的命令,打開加熱。根據所有傳感器的遙測數據,如果雲端服務決定應該打開加熱,則會發送相關命令。

向 MQTT 代理發送命令

我們的互聯網控制夜燈的下一步是讓服務器代碼根據檢測到的光照水平向 IoT 設備發送命令以控制燈光。

  1. 在 VS Code 中打開服務器代碼

  2. client_telemetry_topic 聲明後添加以下行以定義發送命令的主題:

    server_command_topic = id + '/commands'
  3. handle_telemetry 函數的末尾添加以下代碼:

    command = { 'led_on' : payload['light'] < 300 }
    print("Sending message:", command)

    client.publish(server_command_topic, json.dumps(command))

    這會向命令主題發送一條 JSON 消息,其中 led_on 的值根據光照是否小於 300 設置為 true 或 false。如果光照小於 300,則發送 true 以指示設備打開 LED。

  4. 像之前一樣運行代碼

  5. 調整您的物理或虛擬設備檢測到的光照水平。接收到的消息和發送的命令將寫入終端:

    (.venv) ➜  nightlight-server python app.py
    Message received: {'light': 0}
    Sending message: {'led_on': True}
    Message received: {'light': 400}
    Sending message: {'led_on': False}

💁 遙測數據和命令在單個主題上發送。這意味著來自多個設備的遙測數據將出現在相同的遙測主題上,發送給多個設備的命令將出現在相同的命令主題上。如果您想向特定設備發送命令,可以使用多個主題,以唯一設備 ID 命名,例如 /commands/device1/commands/device2。這樣設備可以只接收針對該設備的消息。

💁 您可以在 code-commands/server 文件夾中找到此代碼。

在 IoT 設備上處理命令

現在服務器正在發送命令,您可以添加代碼到 IoT 設備來處理它們並控制 LED。

按照以下相關步驟從 MQTT 代理接收命令:

一旦這些代碼編寫並運行,請嘗試更改光照水平。觀察服務器和設備的輸出,並在更改光照水平時觀察 LED。

連接中斷

如果需要向離線的 IoT 設備發送命令,雲端服務應該怎麼做?答案是視情況而定。

如果最新命令覆蓋了早期的命令,那麼早期的命令可能可以忽略。如果雲端服務發送了一個打開加熱的命令,然後發送了一個關閉加熱的命令,那麼可以忽略打開命令並不重新發送。

如果命令需要按順序處理,例如移動機器臂向上,然後關閉抓手,那麼它們需要在連接恢復後按順序發送。

✅ 如何確保設備或服務器代碼在需要時通過 MQTT 始終按順序發送和處理命令?


🚀 挑戰

在過去三節課的挑戰是列出您家中、學校或工作場所中的盡可能多的 IoT 設備,並決定它們是基於微控制器還是單板計算機,甚至是兩者的混合體,並思考它們使用了哪些傳感器和執行器。

對於這些設備,思考它們可能發送或接收哪些消息。它們發送哪些遙測數據?它們可能接收哪些消息或命令?您認為它們是安全的嗎?

課後測驗

課後測驗

複習與自學

MQTT 維基百科頁面 上閱讀更多關於 MQTT 的信息。

嘗試使用 Mosquitto 自行運行 MQTT 代理,並從您的 IoT 設備和服務器代碼連接到它。

💁 提示 - 默認情況下,Mosquitto 不允許匿名連接(即無需用戶名和密碼的連接),也不允許來自運行它的計算機外部的連接。 您可以使用 mosquitto.conf 配置文件 修復此問題,內容如下:

listener 1883 0.0.0.0
allow_anonymous true

作業

比較和對比 MQTT 與其他通信協議