ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

把植物迁移到云端:从公共 MQTT Broker 到 Azure IoT Hub 的完整实战指南(IoT-For-Beginners 第 8 课)

把植物迁移到云端:从公共 MQTT Broker 到 Azure IoT Hub 的完整实战指南(IoT-For-Beginners 第 8 课) 把植物迁移到云端从公共 MQTT Broker 到 Azure IoT Hub 的完整实战指南IoT-For-Beginners 第 8 课【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners本文以 IoT-For-Beginners 课程「Migrate your plant to the cloud」为主体完整覆盖该课的核心内容什么是云、如何创建 Azure 订阅、云 IoT 服务相比公共 MQTT Broker 的优势、通过 Azure CLI 创建 IoT Hub 与注册设备、IoT Hub 的四类通信机制D2C/C2D/Direct Method/Device Twin以及如何把土壤湿度传感器从公共 MQTT Broker 迁移到 Azure IoT Hub 上。结合仓库中 Wio Terminal 设备代码、Python 设备代码 和 PlatformIO 配置读完你能独立把一套联网自动灌溉系统从「教学级」公共 broker 升级到「生产级」云端 IoT 服务。前置回顾为什么公共 MQTT Broker 不够用在上一课自动浇花中设备已经能通过公共 MQTT Broker 收发遥测与指令用本地运行的服务端代码控制继电器。这套系统构成了「从家庭单株植物到商业农场」通用联网自动灌溉的核心。但公共 broker 只用于演示原理作为商业工具它存在四个明确缺陷缺陷说明可靠性免费服务、无保障随时可能停止服务安全性完全公开任何人都能监听你的遥测数据或发送指令控制你的硬件性能只设计用于少量测试消息无法承受大量消息发现没有任何途径知道当前有哪些设备在线云 IoT 服务正是针对这些问题由大型云服务商运维在可靠性上大量投入内建安全机制防止黑客读取数据或发送恶意指令借助云的弹性扩缩能力可处理每天数百万条消息。虽然需要按月付费但几乎所有云服务商都提供免费的 IoT 服务版本限制每日消息数或可连接设备数足以支撑开发者学习——本课正是使用免费版本。什么是云别人的计算机在云出现之前企业要为员工如数据库、文件存储或公众如网站提供服务就得自建并运营数据中心——可能是一间放几台计算机的房间也可能是一栋装满计算机的大楼。企业需要自己管理一切购买计算机硬件维护电力与制冷网络安全包括楼宇安全与计算机上软件的安全软件安装与更新这非常昂贵、需要大量各类技能员工、且扩缩非常缓慢。比如电商要为旺季做准备必须提前数月购买、配置硬件并安装销售系统旺季结束后这些计算机只能闲置到下一个旺季。可以想见如果一家服装店因某明星带货突然爆火它根本来不及扩容来承接订单激增。云常被戏称为「别人的计算机」。核心思路很简单不买计算机而是租用别人的。云服务商运营庞大的数据中心负责硬件采购安装、电力制冷、网络、楼宇安全、软硬件更新等所有事情。作为客户你按需租用计算机需求激增时多租、需求回落时少租。这些数据中心可以横跨数平方公里。上面这张照片拍摄于微软的一个云数据中心展示了初始规模以及一片规划中的扩建区——仅为扩建就清理出了超过 5 平方公里的地块。这类中心耗电巨大部分甚至配备自有电站但得益于规模与投入它们通常相当环保比大量小型数据中心更高效、主要使用可再生能源云服务商还会通过减少浪费、降低用水、补种森林来抵消为建设数据中心而砍伐的森林。使用云降低了企业成本让企业能聚焦自身最擅长的事把云计算的专业性交给服务商不再需要租用/购买机房、向不同供应商支付连通与电力费用、自聘专家只需按月向云服务商支付一笔账单。而云服务商则利用规模经济压低成本——批量采购硬件、投资自动化工具降低运维负担甚至自研自建设备来优化云产品。本系列课程使用的云是微软的Azure。创建云资源前需要先拥有一个云订阅。任务创建云订阅本课程的实操基于 Microsoft Azure。如果你已有 Azure 订阅可以跳过本节注意订阅条款以撰写时为准可能随时间变化如果是通过学校接触本课程学校可能已提供订阅。Azure 有两种免费订阅可以注册Azure for Students——面向 18 岁及以上学生注册无需信用卡用学校邮箱验证学生身份。注册即获得 100 美元云资源额度外加一系列免费服务包括免费版的 IoT 服务。有效期 12 个月在校期间可逐年续订。Azure Free 订阅——面向非学生用户。注册需要信用卡但不会扣款仅用于验证你是真人而非机器人。前 30 天可获 200 美元任意服务额度并附赠各 Azure 服务的免费层。额度用尽后除非你主动转为按量付费否则不会扣款。提示微软为 18 岁以下学生提供 Azure for Students Starter 订阅但撰写本文档时该订阅尚不支持任何 IoT 服务。学生18的注册路径有两条通过 GitHub 学生开发者套件Student Developer Pack注册其中包含 GitHub 与 Microsoft Azure 等工具与优惠注册后即可激活 Azure for Students 权益直接在 Azure 官网的免费学生页注册 Azure for Students 账户。如果你的学校邮箱未被识别可以到本课程仓库提交 issue维护者会尝试将其加入 Azure for Students 的白名单。非学生或没有可用学校邮箱的读者则直接注册 Azure Free 订阅即可。云 IoT 服务的连接与安全模型IoT 设备接入云服务有两条路使用设备 SDK提供与服务各功能交互代码的库或直接用 MQTT/HTTP 等通信协议对接。实践中设备 SDK 是最省事的路线——它会替你处理诸如「该发布/订阅什么主题」「安全如何握手」等一切细节。连接建立后设备就通过该服务与应用的其他部分通信——与之前用 MQTT 发遥测、收指令的模式类似。消息从设备到达服务后应用的其他组件可以读取服务也能把消息回传给设备。应用的其他组件还可以连接该 IoT 服务查询所有已连接或已注册的设备并对它们逐个或批量下发通信。安全是这样实现的服务预先知道哪些设备可以连接和发送数据——要么设备提前在服务端注册要么设备持有密钥/证书首次连接时用于向服务自助注册。未知设备无法连接若强行尝试服务会拒绝连接并忽略其发送的所有消息。此外IoT 服务还提供附加能力云服务商也有可对接该服务的其他服务与应用。例如想把所有设备发送的遥测消息存入数据库通常只需在云服务商的配置工具里点几下即可把服务与数据库打通、把数据流式写入。任务在云端创建 IoT 服务Azure IoT Hub微软的 IoT 服务名为Azure IoT Hub。Azure 上的云资源既可以通过 Web 门户配置也可以通过命令行CLI配置——本节任务全部使用 CLI因为后续每一步都需要可复制的确定命令。安装并登录 Azure CLI按 Azure CLI 官方文档在 PC/Mac 上安装 CLI文档在 Microsoft Learn 上可按操作系统选择安装包。Azure CLI 通过扩展extension扩展对各类 Azure 服务的管理能力。安装 IoT 扩展az extension add --name azure-iot用 CLI 登录你的 Azure 订阅az login默认浏览器会打开登录页用注册 Azure 订阅的账号登录即可登录完成后关闭浏览器标签页。如果你拥有多个订阅比如学校提供的 自己的 Azure for Students需要选定要使用的那一个。列出所有可访问的订阅az account list --output table输出中每个订阅的名字旁边都有SubscriptionId➜ ~ az account list --output table Name CloudName SubscriptionId State IsDefault ---------------------- ----------- ------------------------------------ ------- ----------- School-subscription AzureCloud cb30cde9-814a-42f0-a111-754cb788e4e1 Enabled True Azure for Students AzureCloud fa51c31b-162c-4599-add6-781def2e1fbf Enabled False选中目标订阅az account set --subscription SubscriptionId把SubscriptionId换成你要用的订阅 ID。执行后再跑一次az account list --output table会看到刚设置的订阅IsDefault列变为True。创建资源组Resource GroupAzure 上的服务——IoT Hub 实例、虚拟机、数据库、AI 服务等——统称为资源resource。每个资源都必须归属于一个资源组Resource Group即一个或多个资源的逻辑集合。资源组的好处是可以批量管理多个服务比如学完整个课程后删除该资源组其中所有资源会被自动一并删除避免残留计费资源。Azure 数据中心遍布全球划分为若干区域region。创建资源或资源组时必须指定创建位置。列出所有可选位置az account list-locations --output table列表很长撰写时约有 65 个可部署位置例如➜ ~ az account list-locations --output table DisplayName Name RegionalDisplayName ------------------------ ------------------- ------------------------------------- East US eastus (US) East US East US 2 eastus2 (US) East US 2 South Central US southcentralus (US) South Central US ...记下离你最近区域的Name列取值如eastus。创建名为soil-moisture-sensor的资源组资源组名在订阅内必须唯一az group create --name soil-moisture-sensor \ --location locationlocation替换为上一步选定的区域。创建 IoT Hub现在可以在资源组内创建 IoT Hub 资源az iot hub create --resource-group soil-moisture-sensor \ --sku F1 \ --partition-count 2 \ --name hub_name各参数含义hub_nameIoT Hub 的名字必须全球唯一任何人都不能创建同名的 IoT Hub因为它会出现在指向该 Hub 的 URL 中。建议用soil-moisture-sensor-作为前缀末尾加随机词或你的名字来保证唯一。--sku F1使用免费层free tier。免费层支持每天 8,000 条消息并保留付费层的大部分功能。Azure 服务的不同定价级别称为「层tier」各层价格不同、提供的功能或数据量不同。--partition-count 2定义 IoT Hub 支持的数据流数量分区越多多个读写方并发时对数据的阻塞越小。分区机制超出本系列课程范围但创建免费层 IoT Hub 时必须指定该值。注意每个订阅只能拥有一个免费层 IoT Hub。Hub 创建大约需要一两分钟完成。理解与 IoT Hub 的通信四种机制前一课用 MQTT 时靠不同 topic 区分消息用途。IoT Hub 不采用自由 topic而是定义了四种明确的通信方式机制方向用途设备到云D2C消息设备 → Hub如遥测数据可被应用代码从 Hub 读取云ToDeviceC2D消息应用 → Hub → 设备应用代码经 Hub 发给设备Direct Method直接方法请求应用 → Hub → 设备请求设备执行某操作如控制执行器要求设备响应以便应用知道是否处理成功设备孪生Device Twin设备 ↔ Hub在设备与 Hub 间保持同步的 JSON 文档存储设备上报的属性或 Hub 希望设备上设置的属性desired补充要点底层上IoT Hub 与设备之间的通信可以走MQTT、HTTPS 或 AMQP协议D2C 消息底层由 Azure 的Event Hubs服务支撑因此这类消息也常被称为「事件events」IoT Hub 可缓存消息和 Direct Method 请求一段可配置时长默认 1 天设备或应用掉线期间发送的消息重连后仍可取回设备孪生则在 Hub 中永久保存设备任何时刻重连都能拿到最新孪生。任务把设备注册到 IoT 服务并获取连接字符串Hub 创建好之后只有已注册设备才能连接。注册后即可获取连接字符串connection string它专属于该设备包含 IoT Hub 信息、设备信息以及允许该设备连接的密钥。知识扩展连接字符串是一个通用术语指包含连接细节的文本广泛用于 IoT Hub、数据库等众多服务。通常由服务标识如 URL 安全信息如密钥组成交给 SDK 用于建立连接。⚠️连接字符串必须保密课程后续会有专门章节详讲安全。用 Azure CLI 注册设备az iot hub device-identity create --device-id soil-moisture-sensor \ --hub-name hub_name这会创建一个 ID 为soil-moisture-sensor的设备。设备通过 SDK 连接 Hub 时需要包含 Hub URL 与密钥的连接字符串az iot hub device-identity connection-string show --device-id soil-moisture-sensor \ --output table \ --hub-name hub_name保存好输出的连接字符串设备代码马上要用。任务把设备代码从 MQTT 迁移到 IoT Hub仓库提供了两条设备端的迁移路径对应两种硬件Wio TerminalArduino/PlatformIO见 wio-terminal-connect-hub.mdRaspberry Pi / 虚拟 IoT 设备Python见 single-board-computer-connect-hub.md完整代码位于本课的code目录下面结合源码把两条路径的关键点讲透。Wio TerminalC/Arduino SDK设备端依赖在 platformio.ini 中声明[env:seeed_wio_terminal] platform atmelsam board seeed_wio_terminal framework arduino lib_deps bblanchon/ArduinoJson 6.17.3 seeed-studio/Seeed Arduino rpcWiFi 1.0.5 seeed-studio/Seeed Arduino FS 2.1.1 seeed-studio/Seeed Arduino SFUD 2.0.2 seeed-studio/Seeed Arduino rpcUnified 2.1.3 seeed-studio/Seeed_Arduino_mbedtls 3.0.1 seeed-studio/Seeed Arduino RTC 2.0.0 arduino-libraries/AzureIoTHub 1.6.0 azure/AzureIoTUtility 1.6.1 azure/AzureIoTProtocol_MQTT 1.6.0 azure/AzureIoTProtocol_HTTP 1.6.0 azure/AzureIoTSocket_WiFi 1.0.2 build_flags -DDONT_USE_UPLOADTOBLOB从源码结构看arduino-libraries/AzureIoTHub加上azure/AzureIoTUtility、AzureIoTProtocol_MQTT、AzureIoTProtocol_HTTP、AzureIoTSocket_WiFi这组库就是 Arduino 版 IoT Hub 设备 SDKSeeed Arduino RTC用于操作 Wio Terminal 上的实时时钟后面解释为什么需要时钟。原先连接公共 broker 用的knolleary/PubSubClient依赖被移除。build_flags里的-DDONT_USE_UPLOADTOBLOB是编译 Arduino IoT Hub 代码所需的编译器标志。设备凭据集中在 config.h 中#pragma once #include string using namespace std; // WiFi credentials const char *SSID SSID; const char *PASSWORD PASSWORD; // IoT Hub settings const char *CONNECTION_STRING CONNECTION STRING;CONNECTION_STRING就是上一步 CLI 输出的设备连接字符串。为什么需要 NTP 时钟IoT Hub 连接使用基于时间的 tokenSAS 令牌设备必须知道当前时间。与 Windows/macOS/Linux 不同微控制器不会自动从网络同步时间。因此仓库新增了 ntp.h 提供initTime()函数通过NTPClientAz从0.pool.ntp.org获取 Unix 纪元时间失败则每 2 秒重试再用settimeofday写入系统时钟Wio Terminal 的 RTC 会把时间保存下来掉电前重启时无需重新获取。设备主程序 main.cpp 展示了 C 侧完整的连接—遥测—指令处理链路声明客户端句柄IOTHUB_DEVICE_CLIENT_LL_HANDLE _device_ll_handle;是到 IoT Hub 连接的句柄。连接状态回调connectionStatusCallback连接状态变化如认证成功IOTHUB_CLIENT_CONNECTION_AUTHENTICATED时打印到串口便于排障。建立连接connectIoTHub()先调IoTHub_Init()初始化库再IoTHubDeviceClient_LL_CreateFromConnectionString(CONNECTION_STRING, MQTT_Protocol)基于连接字符串创建MQTT 协议的连接若句柄为NULL说明连接字符串有误最后注册连接状态回调与 Direct Method 回调。发送遥测sendTelemetry()void sendTelemetry(const char *telemetry) { IOTHUB_MESSAGE_HANDLE message_handle IoTHubMessage_CreateFromString(telemetry); IoTHubDeviceClient_LL_SendEventAsync(_device_ll_handle, message_handle, NULL, NULL); IoTHubMessage_Destroy(message_handle); }把字符串包装成 IoT Hub 消息、异步发送到 Hub即 D2C 事件、然后释放消息对象。处理 Direct MethoddirectMethodCallback根据method_name是否为relay_on/relay_off来digitalWrite继电器引脚方法必须有响应代码把{Result:}写入*response并返回IOTHUB_CLIENT_OK告知调用方处理成功。事件循环Arduino 是单线程的IoTHubDeviceClient_LL_DoWork(_device_ll_handle)负责处理 Hub 收发方向的消息。注意一个工程细节——loop()里原本每 10 秒调用一次DoWork意味着 Direct Method 最多 10 秒才被处理一次仓库用work_delay(10000)把长延迟拆成每 100ms 调用一次DoWork的循环将指令响应延迟压缩到最多 100msvoid work_delay(int delay_time) { int current 0; do { IoTHubDeviceClient_LL_DoWork(_device_ll_handle); delay(100); current 100; } while (current delay_time); }loop()每轮读取 A0 模拟值analogRead(A0)、用 ArduinoJson 序列化为{soil_moisture: 值}、串口打印并sendTelemetry然后work_delay(10000)。烧录后串口监视器应看到类似输出NTP 获取的时间、设备连接成功、遥测发送Connecting to WiFi.. Connected! Fetched NTP epoch time is: 1619983687 Sending telemetry {soil_moisture:391} The device client is connected to iothubRaspberry Pi / 虚拟 IoT 设备Python SDKPython 侧的完整代码见 app.py。迁移步骤安装设备 SDKpip3 install azure-iot-device引入 SDK 并删除原 MQTT 相关代码topic、mqtt_client全部用法、handle_command保留while True主循环from azure.iot.device import IoTHubDeviceClient, Message, MethodResponse配置连接字符串并建立连接connection_string connection string device_client IoTHubDeviceClient.create_from_connection_string(connection_string) print(Connecting) device_client.connect() print(Connected)课程明确提示把连接字符串硬编码进源码并非最佳实践它会被提交进版本库、被人看到这里仅为简洁更理想的做法是使用环境变量配合python-dotenv之类的工具后续课程会深入讲解。主循环中发送遥测D2C 消息while True: soil_moisture adc.read(0) print(Soil moisture:, soil_moisture) message Message(json.dumps({ soil_moisture: soil_moisture })) device_client.send_message(message) time.sleep(10)Message携带 JSON 字符串化的土壤湿度值send_message将其作为设备到云消息发到 Hub。处理 Direct Methoddef handle_method_request(request): print(Direct method received - , request.name) if request.name relay_on: relay.on() elif request.name relay_off: relay.off() method_response MethodResponse.create_from_method_request(request, 200) device_client.send_method_response(method_response) device_client.on_method_request_received handle_method_request直接方法要求响应这里以 HTTP 200 状态码回包把函数赋给on_method_request_received即完成回调接线。运行后看到Connecting/Connected与Soil moisture: 读数输出说明设备已连上 Hub。任务监控事件与远程操控设备在更新服务端代码之前可以直接用 Azure CLI 观察设备到 Hub 的事件并远程调用 Direct Method。监控 D2C 事件先确保设备正在运行并发送土壤湿度遥测然后az iot hub monitor-events --hub-name hub_name设备每发一条消息终端就会打印一条事件Starting event monitor, use ctrl-c to stop... { event: { origin: soil-moisture-sensor, module: , interface: , component: , payload: {\soil_moisture\: 376} } }, { event: { origin: soil-moisture-sensor, module: , interface: , component: , payload: {\soil_moisture\: 381} } }payload的内容与设备端发出的消息完全一致对比上面app.py/main.cpp中构造的{soil_moisture: ...}即可印证。已知限制撰写时az iot扩展在 Apple Silicon 上未完全可用此类设备可改用 Visual Studio Code 的 Azure IoT Toolkit 等途径监控消息。每条消息还附带若干自动生成的属性时间戳等称为annotations标注。加--properties anno查看完整标注az iot hub monitor-events --properties anno --hub-name hub_nameStarting event monitor, use ctrl-c to stop... { event: { origin: soil-moisture-sensor, module: , interface: , component: , properties: {}, annotations: { iothub-connection-device-id: soil-moisture-sensor, iothub-connection-auth-method: {\scope\:\device\,\type\:\sas\,\issuer\:\iothub\,\acceptingIpFilterRule\:null}, iothub-connection-auth-generation-id: 637553997165220462, iothub-enqueuedtime: 1619976150288, iothub-message-source: Telemetry, x-opt-sequence-number: 1379, x-opt-offset: 550576, x-opt-enqueued-time: 1619976150277 }, payload: {\soil_moisture\: 381} } }标注里的时间值采用UNIX 时间——自 1970 年 1 月 1 日午夜以来的秒数。iothub-connection-auth-method里的type:sas也印证了前面说的设备基于 SAS基于时间的共享访问签名令牌认证。调用 Direct Method 控制继电器az iot hub invoke-device-method --device-id soil-moisture-sensor \ --method-name relay_on \ --method-payload {} \ --hub-name hub_name该命令向设备发送名为relay_on的 Direct Method 请求Direct Method 可携带 JSON 数据负载由--method-payload指定。执行后会看到继电器吸合同时设备端打印Direct method received - relay_on把--method-name换成relay_off再执行一次继电器断开设备端同样打印对应输出。这一闭环正好对应设备代码里relay_on/relay_off两个方法名的分支逻辑。 挑战8,000 条/天够用吗免费层 IoT Hub 允许每天 8,000 条消息而本课代码每 10 秒发一条遥测。每 10 秒一条一天是多少条提示一天 86,400 秒86,400 ÷ 10 8,640 条——已经超出免费额度。土壤湿度测量真的需要每 10 秒上报一次吗如何改代码让上报频率「按需但不过度」、稳稳落在免费层内例如按土壤湿度变化幅度触发、拉长上报间隔、仅在灌溉窗口期加密采样等思路都值得考虑。如果想再加一台设备消息量翻倍又该如何设计这个挑战是理解免费层配额与实际业务采样需求之间权衡的良好入口。扩展学习设备端 SDK 的示例仓库与课后作业IoT Hub 的 SDK 在 Arduino 和 Python 上都是开源的代码仓库内有覆盖各项功能的示例。使用 Wio Terminal 的读者可参考 Arduino 版 SDKazure-iot-pal-arduino的pal/samples示例目录使用 Raspberry Pi 或虚拟设备的读者可参考 Python 版 SDKazure-iot-sdk-python中azure-iot-hub/samples示例目录。课后作业见 assignment.md要求学习并区分云服务的四种主要交付模式并说明哪些对 IoT 开发者有意义IaaSInfrastructure as a Service基础设施即服务PaaSPlatform as a Service平台即服务Serverless无服务器SaaSSoftware as a Service软件即服务评分标准能清晰解释全部四种模式为优秀能解释 3 种为合格、1~2 种需改进同时需要说明哪几类对 IoT 开发者相关、以及为什么例如本课的 IoT Hub 属于 PaaS你不用管理底层计算与存储直接消费「设备身份、消息路由、孪生」等能力后续课程把遥测存入 Azure Storage、用 Azure Functions 做服务端处理则分别涉及 PaaS 存储与 Serverless。小结本课完成了联网自动灌溉系统的关键一步升级从「任何人可连的公共 MQTT Broker」迁移到「按设备注册 连接字符串鉴权的 Azure IoT Hub」。核心路径可以概括为注册 Azure 订阅 →az group create建资源组 →az iot hub create --sku F1建免费层 Hub →az iot hub device-identity create注册设备并取连接字符串 → 设备端改用 IoT Hub SDKArduino 的 AzureIoTHub 库或 Python 的 azure-iot-device发送 D2C 遥测、响应 Direct Method → 用az iot hub monitor-events和invoke-device-method验证全链路。仓库内 Wio Terminal 完整工程 与 Python 完整工程 提供了可直接对照的参考实现。下一课将把整个植物含采集、连接与数据处理进一步迁移上云并继续深入服务端侧的云能力。【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表