一、前言
1.1 项目开发背景
随着工业化进程不断推进以及城市建设规模持续扩大,河流、水库及其他自然水体面临着越来越复杂的污染问题。生活污水排放、工业废水排放、农业面源污染以及自然环境变化等因素,使水环境质量监测的重要性日益提升。河流水质变化不仅直接影响生态环境平衡,还关系到居民生活用水安全、农业灌溉质量以及区域可持续发展。因此,建立一套稳定、高效、可远程管理的水质监测系统,已成为当前智慧环保与智慧水务建设的重要研究方向。
传统河流水质监测通常采用人工采样后送实验室检测的方式完成,该方法虽然检测精度较高,但存在采样周期长、实时性差、人工成本高、监测范围有限等问题,难以满足长期连续监测和快速预警需求。特别是在户外河流、偏远区域以及多监测点场景下,传统方式无法实现全天候自动化采集与远程管理。因此,需要借助物联网、无线通信、嵌入式控制以及云平台技术,实现对水质参数的自动采集、远程传输和集中分析。
近年来,物联网技术与低功耗嵌入式设备快速发展,为水环境监测提供了新的技术路径。以ESP32系列芯片为代表的嵌入式控制平台,具备较强的数据处理能力、丰富的通信接口以及较低的开发成本,可满足现场数据采集与网络通信需求。同时,MQTT协议凭借轻量化、高可靠性特点,被广泛应用于物联网设备的数据传输场景,使监测终端能够稳定接入云端,实现远程数据管理和状态监控。结合云平台的数据存储与可视化能力,可以有效提升水质监测系统的实时性和智能化水平。
基于此,本项目设计了一种基于ESP32的河流水质检测装置,通过集成水温、PH、电导率以及浊度等关键水质参数检测模块,实现对河流水体状态的实时采集与分析。系统采用本地显示与远程通信相结合的方式,现场通过显示屏展示实时数据,同时利用WiFi与4G双网络链路将监测信息上传至华为云物联网平台,实现数据集中管理与远程访问。用户可通过微信小程序、Android移动端以及Windows上位机查看不同监测节点的数据状态,提高监测效率和信息获取便捷性。
考虑到河流监测场景通常处于长期无人值守环境,本系统进一步引入太阳能供电方案,提高设备在户外部署条件下的持续运行能力,降低维护频率与人工巡检成本。同时支持多节点设备协同监测,实现对不同区域水体状态的统一管理,为智慧环保、水资源保护及生态环境治理提供一种低成本、可扩展、智能化的技术方案。
1.2 设计实现的功能
(1)支持水温检测功能
系统采用防水型DS18B20温度传感器对河流水体温度进行实时采集。ESP32-S3周期性读取传感器数据,并完成温度值解析与处理,实现对当前水温状态的连续监测,为后续水质分析提供基础参数支持。
(2)支持PH值检测功能
系统集成PH检测模块,通过模拟量方式输出检测信号,由ESP32-S3内部ADC模块完成数据采集,并经过转换计算得到当前水体PH值,实现对河流水体酸碱度状态的实时监测。
(3)支持电导率检测功能
系统采用TDS电导率检测传感器获取水体导电能力参数,通过ADC进行模拟信号采样,结合换算算法得到电导率检测结果,用于反映水体中溶解性物质变化情况,实现对水质状态的辅助分析。
(4)支持浊度检测功能
系统采用浊度检测传感器对河流水体透明程度进行检测,通过采集模拟输出信号并进行数值转换,获得浊度数据,实现对水体悬浮颗粒变化情况的实时监测。
(5)支持本地显示功能
系统配置显示模块,对采集到的水温、PH、电导率以及浊度数据进行实时显示。用户可直接通过设备端查看当前监测结果,提高现场运维和状态查看效率。
(6)支持数据上云功能
系统具备远程通信能力,采集到的全部监测数据可通过WiFi网络和4G网络两种通信方式进行上传。设备基于MQTT协议与华为云物联网服务器建立连接,实现数据远程传输、云端存储及统一管理。
(7)支持微信小程序访问功能
系统提供微信小程序访问能力,用户可通过手机直接查看云端水质数据。小程序采用官方开发工具及TS模板开发,从华为云平台获取实时监测信息,实现不同设备用户快速访问和水质状态展示。
(8)支持太阳能供电功能
系统采用太阳能供电方案,通过太阳能采集与储能方式为设备持续供电,使设备能够长期部署于户外河流环境中,减少人工维护频率,提高系统运行连续性。
(9)支持多节点水质监测功能
系统支持多个河流水质监测节点同时运行,各节点可独立完成数据采集与上传。用户可通过微信小程序选择不同设备节点进行查看,实现多区域水质数据集中管理与远程监测。
1.3 项目硬件模块组成
(1)ESP32-S3主控模块
系统核心控制单元采用ESP32-S3作为主控制器,负责完成各类传感器数据采集、数据处理、显示控制、通信管理以及云平台交互等任务。ESP32-S3内部集成无线通信能力,并具备丰富的GPIO、ADC、UART、IIC等接口资源,可满足多传感器接入及系统扩展需求。
(2)水温检测模块
采用防水型DS18B20数字温度传感器完成河流水温采集。传感器通过单总线通信方式与ESP32-S3连接,实现实时获取水体温度数据,并作为水质状态分析的重要参考参数。
(3)PH检测模块
系统采用PH传感器完成河流水体酸碱度检测。传感器输出模拟电压信号,经ESP32-S3内部ADC模块采集后进行数据转换与计算,得到当前PH检测结果。
(4)电导率检测模块
采用TDS电导率检测传感器对水体导电能力进行测量。传感器输出模拟信号,通过ESP32-S3完成ADC采样和数据换算,实现电导率数据获取。
(5)浊度检测模块
系统采用浊度检测传感器实现水体浑浊程度检测。检测模块输出模拟量,经主控芯片采集处理后获得浊度结果,用于反映水体中悬浮颗粒变化情况。
(6)显示模块
显示部分采用0.96寸OLED显示屏,并通过IIC通信接口与ESP32-S3连接,用于本地显示水温、PH值、电导率、浊度以及设备运行状态等信息,实现现场数据查看。
(7)WiFi通信模块
系统利用ESP32-S3内部集成WiFi功能完成网络通信,实现监测数据上传至物联网平台,同时支持远程访问和数据同步。
(8)4G无线通信模块
系统采用Air780E模块实现蜂窝网络通信。当现场无法使用普通无线网络时,可通过4G网络完成监测数据上传,保证设备在户外环境下的远程联网能力。模块通过串口与ESP32-S3进行通信。
(9)蜂鸣器提示模块
系统采用高电平触发有源蜂鸣器,用于设备运行过程中的状态提示和报警提醒,通过主控输出控制信号实现蜂鸣器驱动。
(10)太阳能供电模块
系统采用太阳能供电方式,通过太阳能板及充放电管理电路为设备提供持续能源支持,实现户外长期独立运行,解决河流监测场景下供电困难问题。
1.4 系统框架图
1.5 运行流程图

二、部署华为云物联网平台
华为云官网: https://www.huaweicloud.com/
打开官网,搜索物联网,就能快速找到 设备接入IoTDA。
2.1 物联网平台介绍
华为云物联网平台(IoT 设备接入云服务)提供海量设备的接入和管理能力,将物理设备联接到云,支撑设备数据采集上云和云端下发命令给设备进行远程控制,配合华为云其他产品,帮助我们快速构筑物联网解决方案。
使用物联网平台构建一个完整的物联网解决方案主要包括3部分:物联网平台、业务应用和设备。
物联网平台作为连接业务应用和设备的中间层,屏蔽了各种复杂的设备接口,实现设备的快速接入;同时提供强大的开放能力,支撑行业用户构建各种物联网解决方案。
设备可以通过固网、2G/3G/4G/5G、NB-IoT、Wifi等多种网络接入物联网平台,并使用LWM2M/CoAP、MQTT、HTTPS协议将业务数据上报到平台,平台也可以将控制命令下发给设备。
业务应用通过调用物联网平台提供的API,实现设备数据采集、命令下发、设备管理等业务场景。

2.2 开通物联网服务
地址: https://www.huaweicloud.com/product/iothub.html
开通免费单元。
点击立即创建。
正在创建标准版实例,需要等待片刻。
创建完成之后,点击详情。 可以看到标准版实例的设备接入端口和地址。
下面框起来的就是端口号和域名
点击实例名称,可以查看当前免费单元的配置情况。
开通之后,点击接入信息,也能查看接入信息。 我们当前设备准备采用MQTT协议接入华为云平台,这里可以看到MQTT协议的地址和端口号等信息。
总结:
端口号: MQTT (1883)| MQTTS (8883)
接入地址: dab1a1f2c6.st1.iotda-device.cn-north-4.myhuaweicloud.com
根据域名地址得到IP地址信息:
打开Windows电脑的命令行控制台终端,使用ping 命令。ping一下即可。
Microsoft Windows [版本 10.0.19045.5011]
(c) Microsoft Corporation。保留所有权利。
C:UsersLenovo>ping dab1a1f2c6.st1.iotda-device.cn-north-4.myhuaweicloud.com
正在 Ping dab1a1f2c6.st1.iotda-device.cn-north-4.myhuaweicloud.com [117.78.5.125] 具有 32 字节的数据:
来自 117.78.5.125 的回复: 字节=32 时间=37ms TTL=44
来自 117.78.5.125 的回复: 字节=32 时间=37ms TTL=44
来自 117.78.5.125 的回复: 字节=32 时间=37ms TTL=44
来自 117.78.5.125 的回复: 字节=32 时间=37ms TTL=44
117.78.5.125 的 Ping 统计信息:
数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
最短 = 37ms,最长 = 37ms,平均 = 37ms
C:UsersLenovo>
MQTT协议接入端口号有两个,1883是非加密端口,8883是证书加密端口,单片机无法加载证书,所以使用1883端口合适。
2.3 创建产品
链接:https://console.huaweicloud.com/iotdm/?region=cn-north-4#/dm-dev/all-product?instanceId=03c5c68c-e588-458c-90c3-9e4c640be7af
(1)创建产品
(2)填写产品信息
根据自己产品名字填写,下面的设备类型选择自定义类型。
(3)产品创建成功
创建完成之后点击查看详情。
(4)添加自定义模型
产品创建完成之后,点击进入产品详情页面,翻到最下面可以看到模型定义。
模型简单来说: 就是存放设备上传到云平台的数据。
你可以根据自己的产品进行创建。
比如:
烟雾可以叫 MQ2
温度可以叫 Temperature
湿度可以叫 humidity
火焰可以叫 flame
其他的传感器自己用单词简写命名即可。 这就是你的单片机设备端上传到服务器的数据名字。
先点击自定义模型。
再创建一个服务ID。
接着点击新增属性。
2.4 添加设备
产品是属于上层的抽象模型,接下来在产品模型下添加实际的设备。添加的设备最终需要与真实的设备关联在一起,完成数据交互。
(1)注册设备
(2)根据自己的设备填写
(3)保存设备信息
创建完毕之后,点击保存并关闭,得到创建的设备密匙信息。该信息在后续生成MQTT三元组的时候需要使用。
(4)设备创建完成
(5)设备详情
2.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":{"你的字段名字1":30,"你的字段名字2":10,"你的字段名字3":1,"你的字段名字4":0}}]}
2.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
2.7 模拟设备登录测试
经过上面的步骤介绍,已经创建了产品,设备,数据模型,得到MQTT登录信息。 接下来就用MQTT客户端软件模拟真实的设备来登录平台。测试与服务器通信是否正常。
MQTT软件下载地址【免费】: https://download.csdn.net/download/xiaolong1126626497/89928772
(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":{"你的字段名字1":30,"你的字段名字2":10,"你的字段名字3":1,"你的字段名字4":0}}]}
2.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
2.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
三、上位机开发
3.1 Qt开发环境安装
Qt的中文官网: https://www.qt.io/zh-cn/
QT5.12.6的下载地址:https://download.qt.io/archive/qt/5.12/5.12.6
打开下载链接后选择下面的版本进行下载:
如果下载不了,可以在网盘里找到安装包下载: 飞书文档记录的网盘地址:https://ccnr8sukk85n.feishu.cn/wiki/QjY8weDYHibqRYkFP2qcA9aGnvb?from=from_copylink
软件安装时断网安装,否则会提示输入账户。
安装的时候,第一个复选框里的编译器可以全选,直接点击下一步继续安装。
选择编译器: (一定要看清楚了)
3.2 新建上位机工程
前面2讲解了需要用的API接口,接下来就使用Qt设计上位机,设计界面,完成整体上位机的逻辑设计。
【1】新建工程
【2】设置项目的名称。
【3】选择编译系统
【4】选择默认继承的类
【5】选择编译器
【6】点击完成
【7】工程创建完成
3.3 切换编译器
在左下角是可以切换编译器的。 可以选择用什么样的编译器编译程序。
目前新建工程的时候选择了2种编译器。 一种是mingw32这个编译Windows下运行的程序。 一种是Android编译器,可以生成Android手机APP。
不过要注意:Android的编译器需要配置一些环境才可以正常使用,这个大家可以网上找找教程配置一下就行了。
windows的编译器就没有这么麻烦,安装好Qt就可以编译使用。
下面我这里就选择的 mingw32这个编译器,编译Windows下运行的程序。
3.4 编译测试功能
创建完毕之后,编译测试一下功能是否OK。
点击左下角的绿色三角形按钮。
正常运行就可以看到弹出一个白色的框框。这就表示工程环境没有问题了。 接下来就可以放心的设计界面了。
3.5 设计UI界面与工程配置
【1】打开UI文件
打开默认的界面如下:
【2】开始设计界面
根据自己需求设计界面。
以下是完整的Qt UI文件(widget.ui),采用XML格式描述,与之前的widget.cpp代码配套使用。
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Widget</class>
<widget class="QWidget" name="Widget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>900</width>
<height>700</height>
</rect>
</property>
<property name="windowTitle">
<string>河流水质监测系统 - Qt上位机</string>
</property>
<property name="styleSheet">
<string notr="true">
QWidget {
background-color: #f5f5f5;
font-family: "Microsoft YaHei", "Segoe UI", Arial, sans-serif;
}
QGroupBox {
font-weight: bold;
border: 1px solid #cccccc;
border-radius: 6px;
margin-top: 1ex;
padding-top: 10px;
background-color: white;
}
QGroupBox::title {
subcontrol-origin: margin;
left: 10px;
padding: 0 5px 0 5px;
background-color: white;
}
QLabel {
color: #333333;
}
QLabel[valueLabel="true"] {
font-size: 18px;
font-weight: bold;
color: #2196F3;
background-color: #e3f2fd;
padding: 5px 10px;
border-radius: 4px;
}
QLabel[valueLabel="true"][unit="°C"] {
color: #f44336;
background-color: #ffebee;
}
QLabel[valueLabel="true"][unit="pH"] {
color: #4CAF50;
background-color: #e8f5e9;
}
QLabel[valueLabel="true"][unit="ppm"] {
color: #FF9800;
background-color: #fff3e0;
}
QLabel[valueLabel="true"][unit="NTU"] {
color: #9C27B0;
background-color: #f3e5f5;
}
QLabel[valueLabel="true"][unit="V"] {
color: #607D8B;
background-color: #eceff1;
}
QPushButton {
background-color: #2196F3;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
font-weight: bold;
font-size: 12px;
}
QPushButton:hover {
background-color: #1976D2;
}
QPushButton:pressed {
background-color: #0D47A1;
}
QPushButton#disconnectButton {
background-color: #f44336;
}
QPushButton#disconnectButton:hover {
background-color: #d32f2f;
}
QPushButton#exportButton {
background-color: #4CAF50;
}
QPushButton#exportButton:hover {
background-color: #388E3C;
}
QPushButton#clearButton {
background-color: #FF9800;
}
QPushButton#clearButton:hover {
background-color: #F57C00;
}
QLineEdit, QComboBox {
padding: 5px;
border: 1px solid #cccccc;
border-radius: 4px;
background-color: white;
}
QLineEdit:focus, QComboBox:focus {
border-color: #2196F3;
}
QComboBox {
min-width: 120px;
}
QTabWidget::pane {
border: 1px solid #cccccc;
border-radius: 4px;
background-color: white;
}
QTabBar::tab {
background-color: #e0e0e0;
padding: 8px 16px;
margin-right: 2px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
QTabBar::tab:selected {
background-color: #2196F3;
color: white;
}
QTabBar::tab:hover:!selected {
background-color: #bbdefb;
}
QStatusBar {
background-color: #eeeeee;
color: #333333;
}
</string>
</property>
<!-- 主布局 -->
<layout class="QVBoxLayout" name="mainLayout">
<property name="spacing">
<number>10</number>
</property>
<property name="leftMargin">
<number>10</number>
</property>
<property name="topMargin">
<number>10</number>
</property>
<property name="rightMargin">
<number>10</number>
</property>
<property name="bottomMargin">
<number>10</number>
</property>
<!-- 顶部:标题和状态栏 -->
<widget class="QWidget" name="topWidget" native="true">
<layout class="QHBoxLayout" name="topLayout">
<property name="spacing">
<number>10</number>
</property>
<item>
<widget class="QLabel" name="titleLabel">
<property name="font">
<font>
<pointsize>18</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>
171