您應該盡可能使用其中一個 Azure IoT 裝置 SDK 來建置 IoT 裝置用戶端。 不過,在使用記憶體限制裝置等案例中,您可能需要使用 MQTT 連結庫來與 IoT 中樞通訊。
本教學課程中的範例會使用 Eclipse Mosquitto MQTT 連結庫。
在本教學課程中,您將瞭解如何:
- 建置 C 語言裝置用戶端範例應用程式。
- 執行使用 MQTT 連結庫來傳送遙測的範例。
- 執行使用 MQTT 連結庫來處理從 IoT 中樞傳送的雲端到裝置訊息的範例。
- 執行使用 MQTT 程式庫在裝置上管理裝置對應項的範例。
您可以使用 Windows 或 Linux 開發電腦來完成本教學課程中的步驟。
如尚未擁有 Azure 訂用帳戶,請在開始之前先建立免費帳戶。
先決條件
開發電腦必要條件
安裝 Visual Studio (Community、Professional 或 Enterprise)。 請務必啟用使用 C++ 的桌面開發工作負載。
安裝 CMake。 啟用 [ 將 CMake 新增至所有用戶的系統 PATH ] 選項。
安裝 x64 版 的 Mosquitto。
備妥環境以使用 Azure CLI
在 Azure Cloud Shell 中使用 Bash 環境。 如需詳細資訊,請參閱開始使用 Azure Cloud Shell。
若要在本地執行 CLI 參考命令,請安裝 Azure CLI。 如果您正在 Windows 或 macOS 上執行,請考慮在 Docker 容器中執行 Azure CLI。 如需詳細資訊,請參閱〈如何在 Docker 容器中執行 Azure CLI〉。
如果您使用的是本機安裝,請使用 az login 命令,透過 Azure CLI 來登入。 若要完成驗證程式,請遵循終端機中顯示的步驟。 如需其他登入選項,請參閱 使用 Azure CLI 向 Azure 進行驗證。
出現提示時,請在第一次使用時安裝 Azure CLI 延伸模組。 如需擴充功能的詳細資訊,請參閱 使用和管理 Azure CLI 的擴充功能。
執行 az version 以尋找已安裝的版本和相依程式庫。 若要升級至最新版本,請執行 az upgrade。
設定您的環境
如果您還沒有IoT中樞,請執行下列命令,在名為 mqtt-sample-rg
的資源群組中建立免費層IoT中樞。 命令會使用名稱 my-hub
作為要建立之IoT中樞名稱的範例。 為您的 IoT 中樞選擇唯一名稱,以取代 my-hub
:
az group create --name mqtt-sample-rg --location eastus
az iot hub create --name my-hub --resource-group mqtt-sample-rg --sku F1
記下 IoT 中樞的名稱,您稍後需要它。
在您的 IoT 中樞中註冊裝置。 下列命令會在名為 my-hub
的 IoT 中樞中註冊一個名為 mqtt-dev-01
的裝置。 請確保使用您 IoT 中樞的名稱:
az iot hub device-identity create --hub-name my-hub --device-id mqtt-dev-01
使用下列命令來建立 SAS 令牌,以授與裝置對 IoT 中樞的存取權。 請務必使用您的 IoT 中樞的名稱:
az iot hub generate-sas-token --device-id mqtt-dev-01 --hub-name my-hub --du 7200
請記下命令所輸出的 SAS 令牌,因為稍後會需要用到。 SAS 權杖看起來像 SharedAccessSignature sr=my-hub.azure-devices.net%2Fdevices%2Fmqtt-dev-01&sig=%2FnM...sNwtnnY%3D&se=1677855761
小提示
根據預設,SAS 令牌的有效期限為 60 分鐘。 在前一個命令中的 --du 7200
選項會將令牌持續時間延長至兩小時。 如果在準備好使用之前到期,請產生一個新的權杖。 您也可以建立持續時間較長的令牌。 若要深入瞭解,請參閱 az iot hub generate-sas-token。
這很重要
本文包含使用共用存取簽章 (也稱為對稱金鑰驗證) 連線裝置的步驟。 此驗證方法方便進行測試和評估,但使用 X.509 憑證來驗證裝置是更安全的方法。 若要深入瞭解,請參閱 IoT解決方案 > 連線安全性的安全性最佳做法。
複製範例存放庫
使用下列命令,將範例存放庫複製到本機電腦上的適當位置:
git clone https://github.com/Azure-Samples/IoTMQTTSample.git
存放庫也包含:
- 使用
paho-mqtt
函式庫的 Python 範例。 - 使用
mosquitto_pub
CLI 與 IoT 中樞互動的指示。
建置 C 範例
在建置範例之前,您需要新增IoT中樞和裝置詳細數據。 在複製的IoTMQTTSample存放庫中,開啟 mosquitto/src/config.h 檔案。 新增IoT中樞名稱、裝置標識碼和SAS令牌,如下所示。 請務必使用 IoT 中樞的名稱:
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#define IOTHUBNAME "my-hub"
#define DEVICEID "mqtt-dev-01"
#define SAS_TOKEN "SharedAccessSignature sr=my-hub.azure-devices.net%2Fdevices%2Fmqtt-dev-01&sig=%2FnM...sNwtnnY%3D&se=1677855761"
#define CERTIFICATEFILE CERT_PATH "IoTHubRootCA.crt.pem"
備註
IoTHubRootCA.crt.pem 檔案包含 TLS 連線的 CA 根證書。
將變更儲存至 mosquitto/src/config.h 檔案。
若要建置範例,請在指令提示符中執行下列命令:
cd mosquitto
cmake -Bbuild
cmake --build build
在 Linux 中,二進位檔位於 mosquitto 資料夾下的 ./build 資料夾中。
在 Windows 中,二進位檔位於 mosquitto 資料夾下方的 .\build\Debug 資料夾中。
發送遙測數據
mosquitto_telemetry範例示範如何使用 MQTT 連結庫將裝置到雲端遙測訊息傳送至 IoT 中樞。
執行範例應用程式之前,請執行下列命令來啟動IoT中樞的事件監視器。 請務必使用 IoT 中心的名稱:
az iot hub monitor-events --hub-name my-hub
執行 mosquitto_telemetry 範例。 例如,在Linux上:
./build/mosquitto_telemetry
az iot hub monitor-events
會產生下列輸出,顯示裝置所傳送的承載:
Starting event monitor, use ctrl-c to stop...
{
"event": {
"origin": "mqtt-dev-01",
"module": "",
"interface": "",
"component": "",
"payload": "Bonjour MQTT from Mosquitto"
}
}
您現在可以停止事件監視器。
檢閱程式碼
下列代碼段取自 mosquitto/src/mosquitto_telemetry.cpp 檔案。
下列語句會定義您用來傳送遙測訊息之 MQTT 主題的連接資訊和名稱:
#define HOST IOTHUBNAME ".azure-devices.net"
#define PORT 8883
#define USERNAME HOST "/" DEVICEID "/?api-version=2020-09-30"
#define TOPIC "devices/" DEVICEID "/messages/events/"
函式 main
設定使用者名稱和密碼以進行物聯網中樞的身份驗證。 密碼是您為裝置建立的 SAS 令牌:
mosquitto_username_pw_set(mosq, USERNAME, SAS_TOKEN);
此範例會使用 MQTT 主題將遙測訊息傳送至 IoT 中樞:
int msgId = 42;
char msg[] = "Bonjour MQTT from Mosquitto";
// once connected, we can publish a Telemetry message
printf("Publishing....\r\n");
rc = mosquitto_publish(mosq, &msgId, TOPIC, sizeof(msg) - 1, msg, 1, true);
if (rc != MOSQ_ERR_SUCCESS)
{
return mosquitto_error(rc);
}
printf("Publish returned OK\r\n");
若要深入瞭解,請參閱 傳送裝置到雲端訊息。
接收由雲端傳遞到裝置的訊息
mosquitto_subscribe範例示範如何使用 MQTT 連結庫來訂閱 MQTT 主題,並從 IoT 中樞接收雲端到裝置訊息。
執行 mosquitto_subscribe 範例。 例如,在Linux上:
./build/mosquitto_subscribe
執行下列命令,從IoT中樞傳送雲端到裝置訊息。 請務必使用您的物聯網中心的名稱:
az iot device c2d-message send --hub-name my-hub --device-id mqtt-dev-01 --data "hello world"
來自mosquitto_subscribe的輸出看起來像下列範例:
Waiting for C2D messages...
C2D message 'hello world' for topic 'devices/mqtt-dev-01/messages/devicebound/%24.mid=d411e727-...f98f&%24.to=%2Fdevices%2Fmqtt-dev-01%2Fmessages%2Fdevicebound&%24.ce=utf-8&iothub-ack=none'
Got message for devices/mqtt-dev-01/messages/# topic
檢閱程式碼
下列代碼段取自 mosquitto/src/mosquitto_subscribe.cpp 檔案。
下列語句會定義裝置用來接收雲端到裝置訊息的主題篩選。 #
是多層級通配符:
#define DEVICEMESSAGE "devices/" DEVICEID "/messages/#"
函式使用main
函式來設定回呼以處理從IoT中樞傳送的訊息,並使用mosquitto_subscribe
函式來訂閱所有訊息。 下列代碼段顯示回呼函式:
void message_callback(struct mosquitto* mosq, void* obj, const struct mosquitto_message* message)
{
printf("C2D message '%.*s' for topic '%s'\r\n", message->payloadlen, (char*)message->payload, message->topic);
bool match = 0;
mosquitto_topic_matches_sub(DEVICEMESSAGE, message->topic, &match);
if (match)
{
printf("Got message for " DEVICEMESSAGE " topic\r\n");
}
}
若要深入瞭解,請參閱 使用 MQTT 接收雲端到裝置訊息。
更新裝置對應項
mosquitto_device_twin 範例示範如何在裝置對應項中設定報告屬性,然後回讀屬性。
執行 mosquitto_device_twin 範例。 例如,在Linux上:
./build/mosquitto_device_twin
mosquitto_device_twin的輸出看起來會像下列範例:
Setting device twin reported properties....
Device twin message '' for topic '$iothub/twin/res/204/?$rid=0&$version=2'
Setting device twin properties SUCCEEDED.
Getting device twin properties....
Device twin message '{"desired":{"$version":1},"reported":{"temperature":32,"$version":2}}' for topic '$iothub/twin/res/200/?$rid=1'
Getting device twin properties SUCCEEDED.
檢閱程式碼
下列代碼段取自 mosquitto/src/mosquitto_device_twin.cpp 檔案。
下列陳述式會定義裝置用來訂閱裝置對應項更新、讀取裝置對應項以及更新裝置對應項的主題:
#define DEVICETWIN_SUBSCRIPTION "$iothub/twin/res/#"
#define DEVICETWIN_MESSAGE_GET "$iothub/twin/GET/?$rid=%d"
#define DEVICETWIN_MESSAGE_PATCH "$iothub/twin/PATCH/properties/reported/?$rid=%d"
main
函式會使用 mosquitto_connect_callback_set
函式來設定回呼,以處理從 IoT 中樞傳送的訊息,並使用 mosquitto_subscribe
函式來訂閱 $iothub/twin/res/#
主題。
下列程式碼片段顯示使用 mosquitto_publish
在裝置對應項中設定報告屬性的 connect_callback
函式。 裝置會將訊息發佈至 $iothub/twin/PATCH/properties/reported/?$rid=%d
主題。 每次裝置將訊息發佈至主題時,值 %d
都會遞增:
void connect_callback(struct mosquitto* mosq, void* obj, int result)
{
// ... other code ...
printf("\r\nSetting device twin reported properties....\r\n");
char msg[] = "{\"temperature\": 32}";
char mqtt_publish_topic[64];
snprintf(mqtt_publish_topic, sizeof(mqtt_publish_topic), DEVICETWIN_MESSAGE_PATCH, device_twin_request_id++);
int rc = mosquitto_publish(mosq, NULL, mqtt_publish_topic, sizeof(msg) - 1, msg, 1, true);
if (rc != MOSQ_ERR_SUCCESS)
// ... other code ...
}
裝置會訂閱 $iothub/twin/res/#
主題,並在收到來自IoT中樞的訊息時,函數 message_callback
會處理它。 當您執行範例時,函 message_callback
式會呼叫兩次。 裝置第一次收到來自IoT中樞對報告屬性更新的回應。 接著,裝置會要求裝置對應項。 第二次,裝置會收到要求的裝置對應項。 下列代碼段顯示 函式 message_callback
:
void message_callback(struct mosquitto* mosq, void* obj, const struct mosquitto_message* message)
{
printf("Device twin message '%.*s' for topic '%s'\r\n", message->payloadlen, (char*)message->payload, message->topic);
const char patchTwinTopic[] = "$iothub/twin/res/204/?$rid=0";
const char getTwinTopic[] = "$iothub/twin/res/200/?$rid=1";
if (strncmp(message->topic, patchTwinTopic, sizeof(patchTwinTopic) - 1) == 0)
{
// Process the reported property response and request the device twin
printf("Setting device twin properties SUCCEEDED.\r\n\r\n");
printf("Getting device twin properties....\r\n");
char msg[] = "{}";
char mqtt_publish_topic[64];
snprintf(mqtt_publish_topic, sizeof(mqtt_publish_topic), DEVICETWIN_MESSAGE_GET, device_twin_request_id++);
int rc = mosquitto_publish(mosq, NULL, mqtt_publish_topic, sizeof(msg) - 1, msg, 1, true);
if (rc != MOSQ_ERR_SUCCESS)
{
printf("Error: %s\r\n", mosquitto_strerror(rc));
}
}
else if (strncmp(message->topic, getTwinTopic, sizeof(getTwinTopic) - 1) == 0)
{
// Process the device twin response and stop the client
printf("Getting device twin properties SUCCEEDED.\r\n\r\n");
mosquitto_loop_stop(mosq, false);
mosquitto_disconnect(mosq); // finished, exit program
}
}
若要深入瞭解,請參閱 使用 MQTT 更新裝置對應項報告屬性 和使用 MQTT 來擷取裝置對應項屬性。
清理資源
如果您打算繼續閱讀更多裝置開發人員文章,您可以保留並重複使用本文中所用的資源。 否則,您可以刪除在此文章中建立的資源,以避免產生更多費用。
您可以藉由使用下列 Azure CLI 命令刪除整個資源群組,同時刪除中樞和已註冊的裝置。 如果這些資源與您想要保留的其他資源共用同一個資源群組,請不要使用此命令。
az group delete --name <YourResourceGroupName>
若只要刪除 IoT 中樞,請使用 Azure CLI 執行下列命令:
az iot hub delete --name <YourIoTHubName>
若只要刪除您向 IoT 中樞註冊的裝置身分識別,請使用 Azure CLI 執行下列命令:
az iot hub device-identity delete --hub-name <YourIoTHubName> --device-id <YourDeviceID>
您也可以從開發電腦移除複製的範例檔案。
後續步驟
既然您已瞭解如何使用 Mosquitto MQTT 連結庫與 IoT 中樞通訊,建議的下一個步驟是檢閱 GitHub 上的 MQTT 應用程式範例 。