你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
教程 - 在不使用设备 SDK 的情况下使用 MQTT 开发 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 添加到所有用户的系统路径”选项。
安装 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 中心内注册设备。 以下命令在名为 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。
克隆示例存储库
使用以下命令将示例存储库克隆到本地计算机上的合适位置:
git clone https://github.com/Azure-Samples/IoTMQTTSample.git
存储库还包括:
- 使用
paho-mqtt
库的 Python 示例。 - 有关使用
mosquitto_pub
CLI 与 IoT 中心交互的说明。
生成 C 示例
在生成示例之前,需要添加 IoT 中心和设备详细信息。 在克隆的 IoTMQTTSample 存储库中,打开 mosquitto/src/config.h 文件。 按如下所示添加 IoT 中心名称、设备 ID 和 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 文件。
要生成示例,请在 shell 中运行以下命令:
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"
来自 mosquito to_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
函数使用 mosquitto_message_callback_set
函数设置回调以处理从 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/#
主题。
以下代码片段展示了 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 中心通信,建议接下来查看: