利用开发者云主机快速开发MQTT客户端实现硬件仿真上云华为云IOT【华为开发者空间】
一、前言
1.1 开发背景
随着物联网技术的不断发展,越来越多的设备和应用依赖于实时数据交换和远程控制。在物联网生态系统中,设备与云平台之间的通信是核心环节之一,然而对于许多开发者来说,进行这种设备与云平台之间的通信往往涉及到硬件的配置与调试,这对于一些不熟悉硬件的开发者,尤其是那些处于软件开发领域的人员,可能是一大挑战。传统的物联网开发往往需要开发者拥有一定的硬件基础,或者至少具备与硬件设备进行调试和交互的能力,这使得一些开发者在没有硬件设备的情况下,难以快速上手和测试物联网应用。
为了解决这一问题,开发者迫切需要一种能够模拟硬件设备并与云平台进行交互的工具。通过软件仿真硬件的方式,开发者可以不依赖于实际硬件设备,就能够快速学习、理解和验证物联网应用中设备与云平台的通信过程。这种仿真方法不仅能够降低开发门槛,还能够帮助开发者更好地理解物联网系统的工作原理,并有效加速物联网项目的开发周期。
本项目正是在这样的背景下应运而生。通过开发一款基于MQTT协议的客户端调试助手,项目旨在为开发者提供一个简单易用的工具,模拟硬件设备与云平台的通信交互。这款工具通过软件模拟了物联网设备的行为,支持主题的订阅与发布,能够与华为云物联网平台(IoTDA)进行实时通信。对于不熟悉硬件的开发者,或者暂时没有硬件设备的开发者而言,这款调试助手可以让他们在没有物理硬件的前提下,体验完整的物联网设备上云过程。开发者可以通过该工具快速了解设备如何连接云平台,如何进行数据传输,并学习MQTT协议的基本操作。
此外,物联网技术本身发展迅速,而MQTT作为一种轻量级、高效的消息传输协议,已成为物联网设备与云平台之间通信的首选协议。利用MQTT,设备可以以低带宽、高可靠性的方式与云平台进行实时数据交换。为了帮助开发者熟悉和掌握这一协议,本项目采用了paho-mqtt库,它是一个开源的Python库,能够简化MQTT协议的实现,使得开发者能够专注于业务逻辑,而无需过多担心底层通信细节。
本项目的目标不仅仅是为开发者提供一个调试工具,更重要的是通过仿真硬件的方式,使得开发者能够从软件层面全面体验物联网设备上云的全过程。这不仅有助于他们更好地理解物联网的通信机制,还能够为未来的硬件开发和云平台集成打下基础。通过本项目,开发者能够在一个完全虚拟的环境中学习和掌握物联网开发的基本技能,为日后的实际硬件开发做好准备。
本项目的实现将有助于推广物联网技术的普及和应用,让更多的开发者能够在没有硬件的情况下,通过软件模拟快速掌握物联网设备的云端通信技术,为物联网应用的发展提供更加广泛的人才支持和技术储备。
代码设计界面:
运行效果:
填入信息:
最终设计完成的界面如下:
1.2 云主机
这里使用的华为云开发者空间云主机,是华为云为全球开发者打造的一个云端开发环境,简化开发流程、提高开发效率,并促进技术创新。这个平台提供了一个无需成本即可探索和使用华为云服务的机会,每位注册的开发者在年度内都能享有数百小时的云主机使用权。云主机预装了CodeArts IDE(华为云的集成开发环境)、代码仓库以及JDK、Python等关键运行时插件,从而避免了本地环境配置的复杂性,让开发者能够快速上手并立即开始工作。
除了云主机外,华为云还提供了5GB的云存储容量及定制化的场景模拟沙箱,这些资源帮助开发者在安全隔离的环境中进行实验和测试。华为云开发者空间提供了丰富的技术培训课程和专业认证资料,助力开发者提升技能,并通过认证来证明自己的能力。该空间特别注重于应用全周期管理,涵盖从应用构建到运维的全过程,确保开发者可以高效地完成云端应用搭建。
华为云开发者空间云主机围绕CodeArts IDE打造了一个全面的开发工具生态系统,整合了鲲鹏、昇腾、鸿蒙等核心生态的开发资源,提供广泛的开源软件库和实用开发插件,支持从代码托管到应用运维的各个阶段。这不仅提升了开发效率,也方便了开发者与华为先进技术和全球开发者社区互动,共同推动技术进步和应用创新。
华为云开发者空间云主机的操作系统版本为Ubuntu 22.04.4 LTS,并且内置了一些常用的应用程序如Gitcode等,为开发者提供了一个稳定而高效的开发环境。
1.3 开发环境
本项目的开发环境采用了华为开发者空间的云主机,这一环境为全球开发者提供了一个功能强大且易于访问的云端开发平台。开发者可以通过这一平台进行快速的应用开发、调试和部署,省去了本地环境配置和硬件限制等问题。整个开发环境包括了操作系统、开发语言、开发框架、工具链以及云端资源等多个方面。
(1)云主机平台:华为开发者空间
华为开发者空间是华为云为开发者提供的一个云端开发环境,能够帮助开发者无需复杂的本地环境配置即可开展工作。该平台提供了强大的计算资源和开发工具,能够满足大规模开发和调试的需求。在本项目中,云主机提供了一个统一的、稳定的开发环境,开发者只需要通过浏览器即可访问,不需要担心操作系统的配置、版本兼容性等问题。这种云端开发方式特别适合开发与云服务紧密集成的物联网应用,能够高效地进行实时测试和调试。
(2)操作系统:Ubuntu 22.04.4
整个开发环境基于Ubuntu 22.04.4操作系统运行,Ubuntu作为一种流行的Linux发行版,因其稳定性、开源性和丰富的软件支持而被广泛应用于开发领域。Ubuntu 22.04.4是该系统的LTS(长期支持)版本,提供了长期的安全更新和稳定性支持,适合进行生产环境中的应用开发。对于Python开发者而言,Ubuntu提供了优良的包管理工具和开发工具,能够方便地安装各种开发所需的库和工具。
(3)开发语言:Python
项目采用Python作为主要开发语言,Python因其简洁的语法、强大的库支持和广泛的应用场景,成为了开发者常用的语言。Python的跨平台特性使得应用能够在不同的操作系统上无缝运行,而其庞大的第三方库(如paho-mqtt)则为开发者提供了许多现成的解决方案。本项目中,Python用于实现MQTT协议的客户端功能,包括消息的订阅、发布和连接管理等核心操作。
(4) 界面开发框架:PyQt5
为了提升用户体验并提供便捷的图形化界面,本项目采用了PyQt5作为界面开发框架。PyQt5是Python的Qt库绑定,提供了一套丰富的用户界面组件,开发者可以用它来快速构建高效、美观且跨平台的桌面应用程序。通过PyQt5,开发者可以设计直观的界面,帮助用户通过图形化操作进行MQTT主题的订阅、消息的发布和设备状态的监控。PyQt5的信号与槽机制也使得界面的事件响应和后台逻辑处理更加简洁高效。
(5)MQTT客户端库:paho-mqtt
项目中的MQTT协议操作主要通过paho-mqtt
库来实现。paho-mqtt
是由Eclipse基金会提供的一个广泛使用的Python MQTT客户端库,它支持MQTT协议的各种操作,如客户端连接、消息的发布和订阅、消息的接收等。paho-mqtt
库在本项目中承担着与华为云物联网平台进行通信的核心功能,能够保证数据的实时传输和可靠性。
(6)开发工具:CodeArts IDE
CodeArts IDE是华为开发者空间提供的集成开发环境,它为开发者提供了丰富的开发工具和调试功能。该IDE内置了代码编辑、版本控制、调试等多种功能,并且预先配置好了开发环境,开发者可以直接进入开发状态。通过CodeArts IDE,开发者可以在云端编写代码、执行调试、管理版本等,而不需要担心本地环境配置的问题。此外,CodeArts IDE的云端特性也使得开发者能够随时随地进行开发,无论是在不同的设备还是不同的地理位置,都能够保持一致的开发体验。
1.4 功能说明
本项目主要解决以下几个问题:
-
模拟硬件设备:通过软件模拟物联网设备,允许开发者在没有实际硬件的情况下体验设备与云平台的通信过程。
-
简化调试流程:提供图形化界面和简易操作,降低了调试和测试的门槛,尤其适合没有硬件设备的开发者进行学习和验证。
-
实现MQTT协议的基本功能:通过paho-mqtt库,支持MQTT协议中的主题订阅、消息发布等功能,让开发者能够快速掌握物联网通信的核心技术。
本项目主要实现了以下几项核心功能:
(1)主题订阅功能
在物联网通信中,设备通常需要订阅云平台上的特定主题(Topic),以便接收实时消息或指令。通过主题订阅功能,开发者可以模拟设备通过MQTT协议与云平台进行通信,获取云平台推送的消息。此功能支持以下操作:
-
输入主题名称:用户可以手动输入MQTT主题名称。
-
订阅主题:模拟硬件设备订阅云平台的指定主题,等待云平台推送消息。
-
查看消息:订阅成功后,客户端能够实时显示从云平台接收到的消息,帮助开发者了解订阅是否成功以及接收到的内容。
(2)主题发布功能
在物联网应用中,设备通常会将采集到的数据或状态信息推送到云平台。这一过程通过主题发布实现。在本项目中,开发者可以模拟设备向云平台发布消息,操作步骤包括:
-
选择主题:用户可以选择一个已有的主题或创建新的主题。
-
发布消息:通过输入消息内容,模拟设备将数据发布到指定的MQTT主题。
-
消息传递确认:客户端会向用户显示消息是否成功发布,以及云平台是否已经成功接收。
(3)MQTT连接管理
为了确保与华为云物联网平台的通信稳定,项目提供了MQTT连接管理功能,允许开发者:
-
连接到华为云IoTDA平台:通过设置MQTT代理地址和认证信息,开发者能够轻松连接到华为云物联网平台。
-
自动重连:当连接出现问题或网络中断时,客户端可以自动尝试重新连接,确保设备与平台的稳定通信。
-
查看连接状态:客户端实时显示连接状态,帮助开发者了解当前的网络连接情况及连接稳定性。
(4)图形化用户界面(GUI)
本项目使用PyQt5构建了一个直观、易操作的图形化界面,具体包括:
-
用户友好的界面:通过清晰的按钮、文本框和消息显示框,使得开发者可以直观地进行操作,例如输入主题、发布消息、查看订阅的消息等。
-
操作日志:界面中展示了连接、订阅、发布等操作的日志信息,帮助开发者实时查看操作状态和通信结果。
-
事件驱动机制:通过PyQt5的信号与槽机制,客户端能够快速响应用户的操作,执行相应的MQTT协议功能,确保交互过程流畅且无延迟。
(5)实时消息显示和调试
为了方便开发者进行调试,项目提供了实时的消息显示功能。每当有新的消息被发布或接收时,客户端界面会立即更新,开发者可以:
-
查看接收到的消息内容:帮助开发者验证主题订阅和消息发布的有效性。
-
调试信息输出:在操作过程中,客户端会显示详细的调试信息,帮助开发者跟踪操作步骤,查找并解决潜在的问题。
(6)支持多平台运行
通过使用PyQt5框架,项目能够实现跨平台运行,开发者可以在不同的操作系统(如Windows、Linux、macOS)上运行调试助手。这使得该工具不仅限于某一操作系统,开发者可以在任何操作系统上进行测试和学习。
(7)MQTT协议的学习和测试工具
本项目不仅仅是一个调试工具,还是一个学习和测试平台。开发者可以通过该工具快速掌握MQTT协议的基本概念,包括如何建立连接、如何订阅和发布消息、如何管理MQTT会话等。通过模拟硬件设备与云平台的交互,开发者能够更清楚地理解物联网通信的工作原理,为实际的硬件开发奠定基础。
二、华为云开发者空间
这一个章节介绍华为云主机的配置与使用。
2.1 进入开发者空间
链接地址:
登录华为云账号,进去之后看到的页面如下:
2.2 配置云主机
在左上角可以看到云主机的配置提醒,目前默认是基础版。
点击配置云主机
,会弹出对话框,让你选择云主机的配置,进行安装系统。我这里选择ubuntu 22.04
.
2.3 安装系统
点击安装
后,会进行安装系统。需要等等一段时间。
2.4 启动云主机
安装完毕之后,直接可以在浏览器里启动云主机。
启动需要一段时间初始环境。
进去之后会有引导界面,提示云主机的使用技巧。
进入桌面后的默认效果如下。
2.5 全屏切换
在桌面页面上有个按钮可以全屏切换,切换全屏后,可视化空间更大,开发更加方便。
2.6 共享桌面
云主机还有共享桌面功能,如果需要远程演示项目,共享开发过程,对方还可以远程操作,这个功能非常的方便。 直接双击666
。
2.5 测试Python开发环境
点击左下角的所有应用程序
,可以看到开发
菜单里,有安装好的Python环境,可以直接使用。
启动之后的效果如下。
进去之后,点击左上角,新建一个文件。
然后保存文件,名字叫:test.py
然后编写一段简单的python
代码,测试当前的开发环境是否正常。
代码如下:
import socket
def get_local_ip():
"""
获取本地 IP 地址
"""
try:
# 创建一个 socket 对象,并连接到一个公共地址
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
local_ip = s.getsockname()[0]
s.close()
return local_ip
except Exception as e:
return f"无法获取本地 IP 地址: {e}"
if __name__ == '__main__':
print("本地 IP 地址是:", get_local_ip())
点击左上角运行。
结果如下:
2.6 安装requests库
接下来需要使用Python代码的requests库,发起HTTP请求。先提前安装环境。
2.7 安装Pillow库
Pillow
是 PIL
(Python Imaging Library)的一个分支,提供了图片处理功能。
pip3 install Pillow
2.8 安装paho-mqtt库
安装命令:
pip install paho-mqtt
到此,云主机的开发环境已经测试OK。
三、配置华为云物联网平台IOTDA
华为云官网: https://www.huaweicloud.com/
打开官网,搜索物联网,就能快速找到 设备接入IoTDA
。
3.1 物联网平台介绍
华为云物联网平台(IoT 设备接入云服务)提供海量设备的接入和管理能力,将物理设备联接到云,支撑设备数据采集上云和云端下发命令给设备进行远程控制,配合华为云其他产品,帮助我们快速构筑物联网解决方案。
使用物联网平台构建一个完整的物联网解决方案主要包括3部分:物联网平台、业务应用和设备。
物联网平台作为连接业务应用和设备的中间层,屏蔽了各种复杂的设备接口,实现设备的快速接入;同时提供强大的开放能力,支撑行业用户构建各种物联网解决方案。
设备可以通过固网、2G/3G/4G/5G、NB-IoT、Wifi等多种网络接入物联网平台,并使用LWM2M/CoAP、MQTT、HTTPS协议将业务数据上报到平台,平台也可以将控制命令下发给设备。
业务应用通过调用物联网平台提供的API,实现设备数据采集、命令下发、设备管理等业务场景。
3.2 开通物联网服务
地址: https://www.huaweicloud.com/product/iothub.html
点击立即创建
。
正在创建标准版实例,需要等待片刻。
创建完成之后,点击实例名称。 可以看到标准版实例的设备接入端口和地址。
在上面也能看到 免费单元的限制。
开通之后,点击总览
,也能查看接入信息。 我们当前设备准备采用MQTT协议接入华为云平台,这里可以看到MQTT协议的地址和端口号等信息。
总结:
端口号: MQTT (1883)| MQTTS (8883)
接入地址:ad635970a1.st1.iotda-device.cn-north-4.myhuaweicloud.com
根据域名地址得到IP地址信息:
打开Windows电脑的命令行控制台终端,使用ping
命令。ping
一下即可。
Microsoft Windows [版本 10.0.19045.4170]
(c) Microsoft Corporation。保留所有权利。
C:\Users\11266>ping ad635970a1.st1.iotda-device.cn-north-4.myhuaweicloud.com
正在 Ping ad635970a1.st1.iotda-device.cn-north-4.myhuaweicloud.com [117.78.5.125] 具有 32 字节的数据:
来自 117.78.5.125 的回复: 字节=32 时间=35ms TTL=93
来自 117.78.5.125 的回复: 字节=32 时间=36ms TTL=93
来自 117.78.5.125 的回复: 字节=32 时间=36ms TTL=93
来自 117.78.5.125 的回复: 字节=32 时间=39ms TTL=93
117.78.5.125 的 Ping 统计信息:
数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
最短 = 35ms,最长 = 39ms,平均 = 36ms
C:\Users\11266>
MQTT协议接入端口号有两个,1883是非加密端口,8883是证书加密端口,单片机无法加载证书,所以使用1883端口比较合适。 接下来的ESP8266就采用1883端口连接华为云物联网平台。
3.3 创建产品
(1)创建产品
(2)填写产品信息
根据自己产品名字填写,下面的设备类型选择自定义类型。
(3)产品创建成功
创建完成之后点击查看详情。
(4)添加自定义模型
产品创建完成之后,点击进入产品详情页面,翻到最下面可以看到模型定义。
模型简单来说: 就是存放设备上传到云平台的数据。
你可以根据自己的产品进行创建。
比如:
烟雾可以叫 MQ2
温度可以叫 Temperature
湿度可以叫 humidity
火焰可以叫 flame
其他的传感器自己用单词简写命名即可。 这就是你的单片机设备端上传到服务器的数据名字。
先点击自定义模型。
再创建一个服务ID。
接着点击新增属性。
3.4 添加设备
产品是属于上层的抽象模型,接下来在产品模型下添加实际的设备。添加的设备最终需要与真实的设备关联在一起,完成数据交互。
(1)注册设备
(2)根据自己的设备填写
(3)保存设备信息
创建完毕之后,点击保存并关闭,得到创建的设备密匙信息。该信息在后续生成MQTT三元组的时候需要使用。
(4)设备创建完成
(5)设备详情
3.5 MQTT协议主题订阅与发布
(1)MQTT协议介绍
当前的设备是采用MQTT协议与华为云平台进行通信。
MQTT是一个物联网传输协议,它被设计用于轻量级的发布/订阅式消息传输,旨在为低带宽和不稳定的网络环境中的物联网设备提供可靠的网络服务。MQTT是专门针对物联网开发的轻量级传输协议。MQTT协议针对低带宽网络,低计算能力的设备,做了特殊的优化,使得其能适应各种物联网应用场景。目前MQTT拥有各种平台和设备上的客户端,已经形成了初步的生态系统。
MQTT是一种消息队列协议,使用发布/订阅消息模式,提供一对多的消息发布,解除应用程序耦合,相对于其他协议,开发更简单;MQTT协议是工作在TCP/IP协议上;由TCP/IP协议提供稳定的网络连接;所以,只要具备TCP协议栈的网络设备都可以使用MQTT协议。 本次设备采用的ESP8266就具备TCP协议栈,能够建立TCP连接,所以,配合STM32代码里封装的MQTT协议,就可以与华为云平台完成通信。
华为云的MQTT协议接入帮助文档在这里: https://support.huaweicloud.com/devg-iothub/iot_02_2200.html
业务流程:
(2)华为云平台MQTT协议使用限制
描述 | 限制 |
---|---|
支持的MQTT协议版本 | 3.1.1 |
与标准MQTT协议的区别 | 支持Qos 0和Qos 1支持Topic自定义不支持QoS2不支持will、retain msg |
MQTTS支持的安全等级 | 采用TCP通道基础 + TLS协议(最高TLSv1.3版本) |
单帐号每秒最大MQTT连接请求数 | 无限制 |
单个设备每分钟支持的最大MQTT连接数 | 1 |
单个MQTT连接每秒的吞吐量,即带宽,包含直连设备和网关 | 3KB/s |
MQTT单个发布消息最大长度,超过此大小的发布请求将被直接拒绝 | 1MB |
MQTT连接心跳时间建议值 | 心跳时间限定为30至1200秒,推荐设置为120秒 |
产品是否支持自定义Topic | 支持 |
消息发布与订阅 | 设备只能对自己的Topic进行消息发布与订阅 |
每个订阅请求的最大订阅数 | 无限制 |
(3)主题订阅格式
帮助文档地址:https://support.huaweicloud.com/devg-iothub/iot_02_2200.html
对于设备而言,一般会订阅平台下发消息给设备 这个主题。
设备想接收平台下发的消息,就需要订阅平台下发消息给设备 的主题,订阅后,平台下发消息给设备,设备就会收到消息。
如果设备想要知道平台下发的消息,需要订阅上面图片里标注的主题。
以当前设备为例,最终订阅主题的格式如下:
$oc/devices/{device_id}/sys/messages/down
最终的格式:
$oc/devices/663cb18871d845632a0912e7_dev1/sys/messages/down
(4)主题发布格式
对于设备来说,主题发布表示向云平台上传数据,将最新的传感器数据,设备状态上传到云平台。
这个操作称为:属性上报。
帮助文档地址:https://support.huaweicloud.com/usermanual-iothub/iot_06_v5_3010.html
根据帮助文档的介绍, 当前设备发布主题,上报属性的格式总结如下:
发布的主题格式:
$oc/devices/{device_id}/sys/properties/report
最终的格式:
$oc/devices/663cb18871d845632a0912e7_dev1/sys/properties/report
发布主题时,需要上传数据,这个数据格式是JSON格式。
上传的JSON数据格式如下:
{
"services": [
{
"service_id": <填服务ID>,
"properties": {
"<填属性名称1>": <填属性值>,
"<填属性名称2>": <填属性值>,
..........
}
}
]
}
根据JSON格式,一次可以上传多个属性字段。 这个JSON格式里的,服务ID,属性字段名称,属性值类型,在前面创建产品的时候就已经介绍了,不记得可以翻到前面去查看。
根据这个格式,组合一次上传的属性数据:
{"services": [{"service_id": "stm32","properties":{"DHT11_T":30,"DHT11_H":10,"BH1750":1,"MQ135":0}}]}
3.6 MQTT三元组
MQTT协议登录需要填用户ID,设备ID,设备密码等信息,就像我们平时登录QQ,微信一样要输入账号密码才能登录。MQTT协议登录的这3个参数,一般称为MQTT三元组。
接下来介绍,华为云平台的MQTT三元组参数如何得到。
(1)MQTT服务器地址
要登录MQTT服务器,首先记得先知道服务器的地址是多少,端口是多少。
帮助文档地址:https://console.huaweicloud.com/iotdm/?region=cn-north-4#/dm-portal/home
MQTT协议的端口支持1883和8883,它们的区别是:8883 是加密端口更加安全。但是单片机上使用比较困难,所以当前的设备是采用1883端口进连接的。
根据上面的域名和端口号,得到下面的IP地址和端口号信息: 如果设备支持填写域名可以直接填域名,不支持就直接填写IP地址。 (IP地址就是域名解析得到的)
华为云的MQTT服务器地址:117.78.5.125
华为云的MQTT端口号:1883
如何得到IP地址?如何域名转IP? 打开Windows的命令行输入以下命令。
ping ad635970a1.st1.iotda-device.cn-north-4.myhuaweicloud.com
(2)生成MQTT三元组
华为云提供了一个在线工具,用来生成MQTT鉴权三元组: https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com/
打开这个工具,填入设备的信息(也就是刚才创建完设备之后保存的信息),点击生成,就可以得到MQTT的登录信息了。
下面是打开的页面:
填入设备的信息: (上面两行就是设备创建完成之后保存得到的)
直接得到三元组信息。
得到三元组之后,设备端通过MQTT协议登录鉴权的时候,填入参数即可。
ClientId 663cb18871d845632a0912e7_dev1_0_0_2024050911
Username 663cb18871d845632a0912e7_dev1
Password 71b82deae83e80f04c4269b5bbce3b2fc7c13f610948fe210ce18650909ac237
3.7 模拟设备登录测试
经过上面的步骤介绍,已经创建了产品,设备,数据模型,得到MQTT登录信息。 接下来就用MQTT客户端软件模拟真实的设备来登录平台。测试与服务器通信是否正常。
(1)填入登录信息
打开MQTT客户端软件,对号填入相关信息(就是上面的文本介绍)。然后,点击登录,订阅主题,发布主题。
(2)打开网页查看
完成上面的操作之后,打开华为云网页后台,可以看到设备已经在线了。
点击详情页面,可以看到上传的数据:
到此,云平台的部署已经完成,设备已经可以正常上传数据了。
(3)MQTT登录测试参数总结
MQTT服务器: 117.78.5.125
MQTT端口号: 183
//物联网服务器的设备信息
#define MQTT_ClientID "663cb18871d845632a0912e7_dev1_0_0_2024050911"
#define MQTT_UserName "663cb18871d845632a0912e7_dev1"
#define MQTT_PassWord "71b82deae83e80f04c4269b5bbce3b2fc7c13f610948fe210ce18650909ac237"
//订阅与发布的主题
#define SET_TOPIC "$oc/devices/663cb18871d845632a0912e7_dev1/sys/messages/down" //订阅
#define POST_TOPIC "$oc/devices/663cb18871d845632a0912e7_dev1/sys/properties/report" //发布
发布的数据:
{"services": [{"service_id": "stm32","properties":{"DHT11_T":30,"DHT11_H":10,"BH1750":1,"MQ135":0}}]}
3.8 创建IAM账户
创建一个IAM账户,因为接下来开发上位机,需要使用云平台的API接口,这些接口都需要token进行鉴权。简单来说,就是身份的认证。 调用接口获取Token时,就需要填写IAM账号信息。所以,接下来演示一下过程。
地址: https://console.huaweicloud.com/iam/?region=cn-north-4#/iam/users
【1】获取项目凭证 点击左上角用户名,选择下拉菜单里的我的凭证
项目凭证:
28add376c01e4a61ac8b621c714bf459
【2】创建IAM用户
鼠标放在左上角头像上,在下拉菜单里选择统一身份认证
。
点击左上角创建用户
。
创建成功:
【3】创建完成
用户信息如下:
主用户名 l19504562721
IAM用户 ds_abc
密码 DS12345678
3.9 获取影子数据
帮助文档:https://support.huaweicloud.com/api-iothub/iot_06_v5_0079.html
设备影子介绍:
设备影子是一个用于存储和检索设备当前状态信息的JSON文档。
每个设备有且只有一个设备影子,由设备ID唯一标识
设备影子仅保存最近一次设备的上报数据和预期数据
无论该设备是否在线,都可以通过该影子获取和设置设备的属性
简单来说:设备影子就是保存,设备最新上传的一次数据。
我们设计的软件里,如果想要获取设备的最新状态信息,就采用设备影子接口。
如果对接口不熟悉,可以先进行在线调试:https://apiexplorer.developer.huaweicloud.com/apiexplorer/doc?product=IoTDA&api=ShowDeviceShadow
在线调试接口,可以请求影子接口,了解请求,与返回的数据格式。
调试完成看右下角的响应体,就是返回的影子数据。
设备影子接口返回的数据如下:
{
"device_id": "663cb18871d845632a0912e7_dev1",
"shadow": [
{
"service_id": "stm32",
"desired": {
"properties": null,
"event_time": null
},
"reported": {
"properties": {
"DHT11_T": 18,
"DHT11_H": 90,
"BH1750": 38,
"MQ135": 70
},
"event_time": "20240509T113448Z"
},
"version": 3
}
]
}
调试成功之后,可以得到访问影子数据的真实链接,接下来的代码开发中,就采用Qt写代码访问此链接,获取影子数据,完成上位机开发。
链接如下:
https://ad635970a1.st1.iotda-app.cn-north-4.myhuaweicloud.com:443/v5/iot/28add376c01e4a61ac8b621c714bf459/devices/663cb18871d845632a0912e7_dev1/shadow
四、图形化界面开发
4.1 安装PyQt5
为了方便能直观的展示项目的整体功能,接下来安装PyQt,完成MQTT调试助手的设计。
在Python中安装PyQt库非常简单,可以使用pip
这个包管理工具来完成。PyQt有两个主要版本:PyQt5(基于Qt 5)和PyQt6(基于Qt 6)。
我这里安装Qt5,以Qt5为例进行开发。
要安装PyQt5,打开命令行界面,然后运行以下命令:
pip install PyQt5
安装过程中:
安装完毕。
4.2 安装QtDesigner
如果想使用PyQt5的设计工具(Qt Designer),用图形方式设计界面,可以安装pyqt5-tools
:
pip install pyqt5-tools
安装过程如下:
安装过程中
安装完毕。
4.3 测试Qt环境
安装完成后,先写一份测试代码,创建一个窗口,运行测试Qt环境是否正常。
新建一个文件:hello_pyqt.py
编写代码如下:
import sys
from PyQt5.QtWidgets import QApplication, QWidget # 如果使用PyQt6,这里改为 from PyQt6.QtWidgets import QApplication, QWidget
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle('Hello PyQt')
window.show()
sys.exit(app.exec_())
在终端命令行中运行:
python3 hello_pyqt.py
如果一切正常,应该能看到一个标题为Hello PyQt
的空白窗口。这表明PyQt已经成功安装并且可以正常使用了。
运行效果如下:
4.4 编写MQTT调试助手【设计界面】
下面是基于PyQt5 的设计的MQTT调试助手,当前只是设计了界面,没有设计功能。
import sys
from PyQt5.QtCore import Qt # 导入Qt核心模块,包含Qt的基础功能
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QFormLayout, QLabel, QLineEdit, QSpinBox, QPushButton, QGridLayout, QGroupBox, QPlainTextEdit, QSpacerItem, QSizePolicy, QMenuBar, QStatusBar # 导入PyQt5组件
class MainWindow(QMainWindow): # 创建主窗口类,继承自QMainWindow
def __init__(self):
super().__init__()
self.setWindowTitle("MainWindow") # 设置窗口标题
self.setGeometry(100, 100, 1019, 772) # 设置窗口位置和大小
self.centralWidget = QWidget(self) # 创建一个中央控件
self.setCentralWidget(self.centralWidget) # 设置中央控件为上面创建的控件
# 主布局
self.mainLayout = QVBoxLayout(self.centralWidget) # 创建一个垂直布局
# 连接设置布局
self.connectionLayout = QHBoxLayout() # 创建水平布局,用于连接设置
# 创建表单布局,添加各个输入框
self.formLayout = QFormLayout()
self.hostLineEdit = QLineEdit() # 创建一个文本框
self.hostLineEdit.setText("117.78.5.125") # 设置默认服务器IP地址
self.formLayout.addRow(QLabel("服务器域名或者IP地址:"), self.hostLineEdit) # 添加一个标签和文本框
# 端口号使用QSpinBox
self.spinBoxPort = QSpinBox() # 创建一个整数框
self.spinBoxPort.setMaximum(99999) # 设置最大值为99999
self.spinBoxPort.setValue(1883) # 设置默认端口号为1883
self.formLayout.addRow(QLabel("服务器端口:"), self.spinBoxPort) # 添加端口号输入框
# 客户端ID输入框
self.clientIdLineEdit = QLineEdit()
self.clientIdLineEdit.setText("6746c32eef99673c8ad0812e_dev1_0_0_2024112707") # 预设客户端ID
self.formLayout.addRow(QLabel("ClientId"), self.clientIdLineEdit) # 添加客户端ID输入框
# 用户名输入框
self.usernameLineEdit = QLineEdit()
self.usernameLineEdit.setText("6746c32eef99673c8ad0812e_dev1") # 预设用户名
self.formLayout.addRow(QLabel("Username"), self.usernameLineEdit) # 添加用户名输入框
# 密码输入框
self.passwordLineEdit = QLineEdit()
self.passwordLineEdit.setText("b69234ba506cf2c1c579c4fd407a0a801479a672032fcf5ab9ea126abcf2a8b1") # 预设密码
self.formLayout.addRow(QLabel("Password"), self.passwordLineEdit) # 添加密码输入框
self.connectionLayout.addLayout(self.formLayout) # 将表单布局添加到连接设置布局中
# 连接按钮
self.connectButton = QPushButton("Connect") # 创建连接按钮
self.connectionLayout.addWidget(self.connectButton) # 将按钮添加到连接设置布局中
# 将连接设置布局添加到主布局中
self.mainLayout.addLayout(self.connectionLayout)
# MQTT 主题和消息布局
self.gridLayout = QGridLayout() # 创建网格布局
self.gridLayout.addWidget(QLabel("订阅主题:"), 0, 0) # 添加订阅主题标签
self.subscribeTopicLineEdit = QLineEdit("$oc/devices/6746c32eef99673c8ad0812e_dev1/sys/messages/down") # 设置默认订阅主题
self.gridLayout.addWidget(self.subscribeTopicLineEdit, 0, 1) # 添加订阅主题文本框
self.gridLayout.addWidget(QPushButton("订阅"), 0, 2) # 添加订阅按钮
self.gridLayout.addWidget(QLabel("发布主题:"), 1, 0) # 添加发布主题标签
self.publishTopicLineEdit = QLineEdit("$oc/devices/6746c32eef99673c8ad0812e_dev1/sys/properties/report") # 设置默认发布主题
self.gridLayout.addWidget(self.publishTopicLineEdit, 1, 1) # 添加发布主题文本框
self.gridLayout.addWidget(QLabel("主题消息:"), 2, 0) # 添加主题消息标签
self.messageLineEdit = QLineEdit() # 创建主题消息输入框
self.gridLayout.addWidget(self.messageLineEdit, 2, 1) # 添加主题消息文本框
self.gridLayout.addWidget(QPushButton("发布"), 2, 2) # 添加发布按钮
self.gridLayout.addWidget(QPushButton("点击发送心跳包"), 3, 2) # 添加心跳包按钮
self.mainLayout.addLayout(self.gridLayout) # 将网格布局添加到主布局中
# 日志显示区域
self.logGroupBox = QGroupBox("日志消息:") # 创建一个日志组框
self.logLayout = QHBoxLayout() # 创建水平布局
self.logTextEdit = QPlainTextEdit() # 创建一个只读文本框用于显示日志
self.logTextEdit.setReadOnly(True) # 设置文本框为只读模式
self.logLayout.addWidget(self.logTextEdit) # 将文本框添加到布局中
self.logGroupBox.setLayout(self.logLayout) # 设置组框布局
self.mainLayout.addWidget(self.logGroupBox) # 将日志组框添加到主布局中
# 底部按钮布局
self.bottomLayout = QHBoxLayout() # 创建水平布局用于底部按钮
# 创建底部按钮
self.testButton = QPushButton("测试按钮(一键填充MQTT信息)")
self.clearButton = QPushButton("一键清除MQTT信息")
self.clearLogButton = QPushButton("清除日志消息")
self.viewTutorialButton = QPushButton("【查看物联网项目开发教程】")
self.quitButton = QPushButton("退出软件")
self.testButton.clicked.connect(self.fillMQTTInfo) # 连接填充按钮点击事件
self.clearButton.clicked.connect(self.clearMQTTInfo) # 连接清除按钮点击事件
self.bottomLayout.addWidget(self.testButton) # 将测试按钮添加到底部布局
self.bottomLayout.addWidget(self.clearButton) # 将清除按钮添加到底部布局
self.bottomLayout.addWidget(self.clearLogButton) # 将清除日志按钮添加到底部布局
self.bottomLayout.addWidget(self.viewTutorialButton) # 将查看教程按钮添加到底部布局
self.bottomLayout.addWidget(self.quitButton) # 将退出按钮添加到底部布局
self.mainLayout.addLayout(self.bottomLayout) # 将底部按钮布局添加到主布局中
# 菜单栏
self.menuBar = self.menuBar() # 创建菜单栏
self.fileMenu = self.menuBar.addMenu("File") # 添加“File”菜单
quitAction = self.fileMenu.addAction("Quit") # 创建退出菜单项
quitAction.triggered.connect(self.close) # 连接退出菜单项的点击事件
# 状态栏
self.statusBar = QStatusBar() # 创建状态栏
self.setStatusBar(self.statusBar) # 设置窗口的状态栏
# 填充MQTT信息的函数
def fillMQTTInfo(self):
"""填充MQTT服务器信息到表单字段中"""
self.hostLineEdit.setText("117.78.5.125") # 设置服务器IP地址
self.spinBoxPort.setValue(1883) # 设置端口号
self.clientIdLineEdit.setText("6746c32eef99673c8ad0812e_dev1_0_0_2024112707") # 设置客户端ID
self.usernameLineEdit.setText("6746c32eef99673c8ad0812e_dev1") # 设置用户名
self.passwordLineEdit.setText("b69234ba506cf2c1c579c4fd407a0a801479a672032fcf5ab9ea126abcf2a8b1") # 设置密码
self.subscribeTopicLineEdit.setText("$oc/devices/6746c32eef99673c8ad0812e_dev1/sys/messages/down") # 设置订阅主题
self.publishTopicLineEdit.setText("$oc/devices/6746c32eef99673c8ad0812e_dev1/sys/properties/report") # 设置发布主题
# 清除MQTT信息的函数
def clearMQTTInfo(self):
"""清除MQTT服务器信息从表单字段中"""
self.hostLineEdit.clear() # 清空IP地址输入框
self.spinBoxPort.clear() # 清空端口号输入框
self.clientIdLineEdit.clear() # 清空客户端ID输入框
self.usernameLineEdit.clear() # 清空用户名输入框
self.passwordLineEdit.clear() # 清空密码输入框
self.subscribeTopicLineEdit.clear() # 清空订阅主题输入框
self.publishTopicLineEdit.clear() # 清空发布主题输入框
if __name__ == '__main__':
app = QApplication(sys.argv) # 创建应用实例
mainWin = MainWindow() # 创建主窗口实例
mainWin.show() # 显示主窗口
sys.exit(app.exec_()) # 启动应用并等待退出
4.5 运行结果
运行效果:
五、MQTT客户端开发
完成 MQTT 客户端调试助手整体开发,基于 paho-mqtt
库来实现以下功能:
-
连接到 MQTT 服务器:通过提供的 IP、端口、客户端 ID、用户名和密码连接到 MQTT 服务器。
-
订阅主题:从用户输入的订阅主题中接收消息。
-
发布消息:发布主题消息到指定的发布主题。
-
心跳包功能:通过发送保活消息来保持与服务器的连接。
每个按钮添加相应的功能:Connect
、订阅
、发布
和 心跳包
。在此基础上,日志框将显示与 MQTT 连接和消息传输相关的调试信息。
import sys
import json
import paho.mqtt.client as mqtt # 导入 paho-mqtt 库
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QFormLayout, QLabel, QLineEdit, QSpinBox, QPushButton, QGridLayout, QGroupBox, QPlainTextEdit, QSpacerItem, QSizePolicy, QMenuBar, QStatusBar
class MQTTClientDebugger(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("MQTT 客户端调试助手")
self.setGeometry(100, 100, 1019, 772) # 设置窗口大小
self.centralWidget = QWidget(self)
self.setCentralWidget(self.centralWidget)
self.client = None # MQTT 客户端实例
# 主布局
self.mainLayout = QVBoxLayout(self.centralWidget)
# 连接设置布局
self.connectionLayout = QHBoxLayout()
self.formLayout = QFormLayout()
self.hostLineEdit = QLineEdit()
self.hostLineEdit.setText("117.78.5.125") # 默认服务器IP地址
self.formLayout.addRow(QLabel("服务器域名或者IP地址:"), self.hostLineEdit)
# 端口号
self.spinBoxPort = QSpinBox()
self.spinBoxPort.setMaximum(99999)
self.spinBoxPort.setValue(1883) # 默认端口号
self.formLayout.addRow(QLabel("服务器端口:"), self.spinBoxPort)
self.clientIdLineEdit = QLineEdit()
self.clientIdLineEdit.setText("6746c32eef99673c8ad0812e_dev1_0_0_2024112707") # 默认客户端ID
self.formLayout.addRow(QLabel("ClientId"), self.clientIdLineEdit)
self.usernameLineEdit = QLineEdit()
self.usernameLineEdit.setText("6746c32eef99673c8ad0812e_dev1") # 默认用户名
self.formLayout.addRow(QLabel("Username"), self.usernameLineEdit)
self.passwordLineEdit = QLineEdit()
self.passwordLineEdit.setText("b69234ba506cf2c1c579c4fd407a0a801479a672032fcf5ab9ea126abcf2a8b1") # 默认密码
self.formLayout.addRow(QLabel("Password"), self.passwordLineEdit)
self.connectionLayout.addLayout(self.formLayout)
# 连接按钮
self.connectButton = QPushButton("Connect")
self.connectButton.clicked.connect(self.connect_to_server)
self.connectionLayout.addWidget(self.connectButton)
self.mainLayout.addLayout(self.connectionLayout)
# MQTT 主题和消息布局
self.gridLayout = QGridLayout()
self.gridLayout.addWidget(QLabel("订阅主题:"), 0, 0)
self.subscribeTopicLineEdit = QLineEdit("$oc/devices/6746c32eef99673c8ad0812e_dev1/sys/messages/down")
self.gridLayout.addWidget(self.subscribeTopicLineEdit, 0, 1)
self.gridLayout.addWidget(QPushButton("订阅"), 0, 2)
self.gridLayout.addWidget(QLabel("发布主题:"), 1, 0)
self.publishTopicLineEdit = QLineEdit("$oc/devices/6746c32eef99673c8ad0812e_dev1/sys/properties/report")
self.gridLayout.addWidget(self.publishTopicLineEdit, 1, 1)
self.gridLayout.addWidget(QLabel("主题消息:"), 2, 0)
self.messageLineEdit = QLineEdit()
self.gridLayout.addWidget(self.messageLineEdit, 2, 1)
self.gridLayout.addWidget(QPushButton("发布"), 2, 2)
self.gridLayout.addWidget(QPushButton("点击发送心跳包"), 3, 2)
self.mainLayout.addLayout(self.gridLayout)
# 日志区域
self.logGroupBox = QGroupBox("日志消息:")
self.logLayout = QHBoxLayout()
self.logTextEdit = QPlainTextEdit()
self.logTextEdit.setReadOnly(True)
self.logLayout.addWidget(self.logTextEdit)
self.logGroupBox.setLayout(self.logLayout)
self.mainLayout.addWidget(self.logGroupBox)
# 底部按钮布局
self.bottomLayout = QHBoxLayout()
self.testButton = QPushButton("测试按钮(一键填充MQTT信息)")
self.clearButton = QPushButton("一键清除MQTT信息")
self.clearLogButton = QPushButton("清除日志消息")
self.viewTutorialButton = QPushButton("【查看物联网项目开发教程】")
self.quitButton = QPushButton("退出软件")
self.testButton.clicked.connect(self.fillMQTTInfo)
self.clearButton.clicked.connect(self.clearMQTTInfo)
self.clearLogButton.clicked.connect(self.clear_logs)
self.bottomLayout.addWidget(self.testButton)
self.bottomLayout.addWidget(self.clearButton)
self.bottomLayout.addWidget(self.clearLogButton)
self.bottomLayout.addWidget(self.viewTutorialButton)
self.bottomLayout.addWidget(self.quitButton)
self.mainLayout.addLayout(self.bottomLayout)
# 菜单栏
self.menuBar = self.menuBar()
self.fileMenu = self.menuBar.addMenu("File")
quitAction = self.fileMenu.addAction("Quit")
quitAction.triggered.connect(self.close)
# 状态栏
self.statusBar = QStatusBar()
self.setStatusBar(self.statusBar)
# 连接到MQTT服务器
def connect_to_server(self):
host = self.hostLineEdit.text()
port = self.spinBoxPort.value()
client_id = self.clientIdLineEdit.text()
username = self.usernameLineEdit.text()
password = self.passwordLineEdit.text()
self.client = mqtt.Client(client_id)
self.client.username_pw_set(username, password) # 设置用户名和密码
# 设置连接成功、消息接收、连接丢失等回调函数
self.client.on_connect = self.on_connect
self.client.on_message = self.on_message
self.client.on_disconnect = self.on_disconnect
# 连接到服务器
self.client.connect(host, port, 60)
# 启动 MQTT 客户端
self.client.loop_start()
def on_connect(self, client, userdata, flags, rc):
"""当连接到MQTT服务器时调用"""
self.log(f"连接成功,返回码:{rc}")
# 连接成功后订阅主题
subscribe_topic = self.subscribeTopicLineEdit.text()
client.subscribe(subscribe_topic)
def on_message(self, client, userdata, msg):
"""当接收到MQTT消息时调用"""
self.log(f"接收到消息:{msg.topic} {msg.payload.decode()}")
def on_disconnect(self, client, userdata, rc):
"""当断开连接时调用"""
self.log(f"MQTT服务器断开连接,返回码:{rc}")
# 发布消息
def publish_message(self):
topic = self.publishTopicLineEdit.text()
message = self.messageLineEdit.text()
if self.client:
self.client.publish(topic, message)
self.log(f"发布消息:{topic} {message}")
# 发送心跳包
def send_heartbeat(self):
if self.client:
self.client.ping()
self.log("发送心跳包")
# 日志输出
def log(self, message):
"""向日志框输出信息"""
self.logTextEdit.appendPlainText(message)
# 填充MQTT信息
def fillMQTTInfo(self):
self.hostLineEdit.setText("117.78.5.125")
self.spinBoxPort.setValue(1883)
self.clientIdLineEdit.setText("6746c32eef99673c8ad0812e_dev1_0_0_2024112707")
self.usernameLineEdit.setText("6746c32eef99673c8ad0812e_dev1")
self.passwordLineEdit.setText("b69234ba506cf2c1c579c4fd407a0a801479a672032fcf5ab9ea126abcf2a8b1")
self.subscribeTopicLineEdit.setText("$oc/devices/6746c32eef99673c8ad0812e_dev1/sys/messages/down")
self.publishTopicLineEdit.setText("$oc/devices/6746c32eef99673c8ad0812e_dev1/sys/properties/report")
self.messageLineEdit.setText('{"services": [{"service_id": "stm32","properties":{"DHT11_T":18.1,"DHT11_H":16.2,"SOIL":12.4,"BH1750":124.5,"MOTOR_SW":1,"SOIL_MAX":30,"run_mode":1}}]}')
# 清除MQTT信息
def clearMQTTInfo(self):
self.hostLineEdit.clear()
self.spinBoxPort.clear()
self.clientIdLineEdit.clear()
self.usernameLineEdit.clear()
self.passwordLineEdit.clear()
self.subscribeTopicLineEdit.clear()
self.publishTopicLineEdit.clear()
# 清除日志信息
def clear_logs(self):
self.logTextEdit.clear()
if __name__ == '__main__':
app = QApplication(sys.argv)
mainWin = MQTTClientDebugger()
mainWin.show()
sys.exit(app.exec_())
六、总结
利用华为开发者空间的云主机,本项目充分发挥了云端开发环境的优势,降低了本地开发环境搭建的复杂性,使得开发者能够专注于应用的开发和调试,而无需关心底层环境配置问题。通过集成的CodeArts IDE,开发者可以在统一的开发环境中高效地编写、调试和运行代码,提升了开发效率。
项目采用的MQTT协议是物联网通信中的核心技术,通过paho-mqtt库实现了与华为云物联网平台的快速对接和可靠通信。该库为开发者提供了易于使用的API,支持灵活的消息发布与订阅操作,并通过连接管理、自动重连等功能,确保了客户端与云平台的稳定通信。
在界面设计上,PyQt5为项目提供了直观、易操作的图形化界面,用户可以通过简单的操作实现复杂的MQTT通信功能,极大地提升了用户体验。借助这种图形化界面,开发者不仅能够方便地调试物联网应用,还能够在没有实际硬件的情况下,模拟设备与云平台的通信过程,从而加速了物联网应用的学习和开发。
本项目不仅为开发者提供了一个功能完备的调试工具,也为物联网应用的学习和开发提供了宝贵的实践机会。无论是在测试调试阶段,还是在实际应用中,开发者都能够通过该工具深入理解MQTT协议、物联网通信机制和云平台集成的基本流程,为未来的物联网项目开发打下坚实的基础。同时,本项目的实现也展示了云端开发和虚拟化硬件仿真技术在物联网领域中的巨大潜力,推动了物联网开发者社区的普及和技术创新。
我正在参加【有奖征集 第34期】华为开发者空间一行代码快速上云,参与视频、文章投稿赢2000元开发者礼包
链接:https://bbs.huaweicloud.com/blogs/438987
- 点赞
- 收藏
- 关注作者
评论(0)