教學課程 - 使用 MQTT 在不使用裝置 SDK 的情況下開發 IoT 裝置用戶端
您應該盡可能使用其中一個 Azure IoT 裝置 SDK 來建置 IoT 裝置用戶端。 不過,在使用記憶體限制裝置等案例中,您可能需要使用 MQTT 連結庫來與 IoT 中樞通訊。
本教學課程中的範例會使用 Eclipse Mosquitto MQTT 連結庫。
在本教學課程中,您會了解如何:
- 建置 C 語言裝置用戶端範例應用程式。
- 執行使用 MQTT 連結庫來傳送遙測的範例。
- 執行使用 MQTT 連結庫來處理從 IoT 中樞傳送的雲端到裝置訊息的範例。
- 執行使用 MQTT 連結庫來管理裝置對應項的範例。
您可以使用 Windows 或 Linux 開發電腦來完成本教學課程中的步驟。
如果您沒有 Azure 訂用帳戶,請在開始前建立免費帳戶。
必要條件
備妥環境以使用 Azure CLI
在 Azure Cloud Shell 中使用 Bash 環境。 如需詳細資訊,請參閱 Azure Cloud Shell 中的 Bash 快速入門。
若要在本地執行 CLI 參考命令,請安裝 Azure CLI。 若您在 Windows 或 macOS 上執行,請考慮在 Docker 容器中執行 Azure CLI。 如需詳細資訊,請參閱〈如何在 Docker 容器中執行 Azure CLI〉。
如果您使用的是本機安裝,請使用 az login 命令,透過 Azure CLI 來登入。 請遵循您終端機上顯示的步驟,完成驗證程序。 如需其他登入選項,請參閱使用 Azure CLI 登入。
出現提示時,請在第一次使用時安裝 Azure CLI 延伸模組。 如需擴充功能詳細資訊,請參閱使用 Azure CLI 擴充功能。
執行 az version 以尋找已安裝的版本和相依程式庫。 若要升級至最新版本,請執行 az upgrade。
開發電腦必要條件
如果您使用 Windows:
安裝 Visual Studio (Community、Professional 或 Enterprise)。 請務必使用 C++ 工作負載啟用桌面開發。
安裝 CMake。 啟用 [ 將 CMake 新增至所有用戶 的系統 PATH] 選項。
安裝 x64 版的 Mosquitto。
如果您使用 Linux:
執行下列命令以安裝建置工具:
sudo apt install cmake g++
執行下列命令以安裝 Mosquitto 用戶端連結庫:
sudo apt install libmosquitto-dev
設定您的環境
如果您還沒有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 中樞註冊裝置。 下列命令會在名為的IoT中樞註冊名為 mqtt-dev-01
my-hub
的裝置。 請務必使用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。
複製範例存放庫
使用下列命令,將範例存放庫複製到本機電腦上的適當位置:
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
設定使用者名稱和密碼,以向IoT中樞進行驗證。 密碼是您為裝置建立的 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中樞傳送雲端到裝置訊息。 請務必使用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/#"
函式會mosquitto_message_callback_set
使用函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
式來設定回呼來處理從IoT中樞傳送的訊息,並使用函mosquitto_subscribe
式來$iothub/twin/res/#
訂閱mosquitto_connect_callback_set
主題。
下列代碼段顯示 connect_callback
用來 mosquitto_publish
在裝置對應項中設定報告屬性的函式。 裝置會將訊息發佈至 $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 中樞 通訊,建議的下一個步驟是檢閱: