[feat] add mqtt for hfc

This commit is contained in:
zhji 2025-12-21 17:14:49 +08:00
parent 74f9ac43ab
commit d223574333

View File

@ -17,6 +17,9 @@ import subprocess
import platform
import logging
import paho.mqtt.client as mqtt
import json
class ModbusGasAnalyzer:
def __init__(self, root):
self.root = root
@ -65,6 +68,16 @@ class ModbusGasAnalyzer:
"送样单位": "",
}
# 服务器MQTT信息 - 初始化值
self.mqtt_info = {
"服务器地址": "122.112.229.121",
"端口号": "1883",
"主题": "xiaofang/sensor/data",
"用户名": "xiaofang",
"密码": "xiaofang@qwer",
}
self.mqtt_client = None
# 创建页面
self.create_page1()
@ -310,12 +323,95 @@ class ModbusGasAnalyzer:
tk.Button(button_frame, text="保存报告", font=('Arial', 12),
command=self.save_report, bg='blue', fg='white').pack(side='left', padx=20)
tk.Button(button_frame, text="上传到云", font=('Arial', 12),
command=self.upload_mqtt, bg='green', fg='white').pack(side='left', padx=20)
tk.Button(button_frame, text="退出", font=('Arial', 12),
command=self.root.quit, bg='red', fg='white').pack(side='right', padx=20)
# 自动保存报告
self.save_report()
def create_page4(self):
"""创建第四个页面"""
self.clear_window()
# 创建一个主容器,包含顶部内容区和底部按钮区
container = tk.Frame(self.root, bg=self.custom_blue)
container.pack(fill='both', expand=True, padx=20, pady=20)
# 顶部内容框架
content_frame = tk.Frame(container, bg=self.custom_blue)
content_frame.pack(fill='both', expand=True)
# 左侧区域
left_frame = tk.Frame(content_frame, bg=self.custom_blue)
left_frame.pack(side='left', fill='both', expand=True, padx=(0, 10), pady=(50, 0))
# 右侧区域
right_frame = tk.Frame(content_frame, bg=self.custom_blue)
right_frame.pack(side='right', fill='both', expand=True, padx=(10, 0))
# 左侧内容
# 服务器地址
tk.Label(left_frame, text="服务器地址:", font=('Arial', 12), bg=self.custom_blue).grid(row=0, column=0, sticky='w', pady=15, padx=(30, 20))
self.ip_entry = tk.Entry(left_frame, font=('Arial', 12), width=20)
self.ip_entry.grid(row=0, column=1, sticky='ew', pady=10)
# 保留之前填写的信息
if self.mqtt_info["服务器地址"]:
self.ip_entry.insert(0, self.mqtt_info["服务器地址"])
# 端口号
tk.Label(left_frame, text="端口号:", font=('Arial', 12), bg=self.custom_blue).grid(row=1, column=0, sticky='w', pady=15, padx=(30, 20))
self.port_entry = tk.Entry(left_frame, font=('Arial', 12), width=20)
self.port_entry.grid(row=1, column=1, sticky='ew', pady=10)
# 自动填入当前时间,但如果已有信息则保留
if self.mqtt_info["端口号"]:
self.port_entry.insert(0, self.mqtt_info["端口号"])
# 主题
tk.Label(left_frame, text="主题:", font=('Arial', 12), bg=self.custom_blue).grid(row=2, column=0, sticky='w', pady=15, padx=(30, 20))
self.topic_entry = tk.Entry(left_frame, font=('Arial', 12), width=20)
self.topic_entry.grid(row=2, column=1, sticky='ew', pady=10)
if self.mqtt_info["主题"]:
self.topic_entry.insert(0, self.mqtt_info["主题"])
# 用户名
tk.Label(left_frame, text="用户名:", font=('Arial', 12), bg=self.custom_blue).grid(row=3, column=0, sticky='w', pady=15, padx=(30, 20))
self.user_name_entry = tk.Entry(left_frame, font=('Arial', 12), width=20)
self.user_name_entry.grid(row=3, column=1, sticky='ew', pady=10)
if self.mqtt_info["用户名"]:
self.user_name_entry.insert(0, self.mqtt_info["用户名"])
# 密码
tk.Label(left_frame, text="密码:", font=('Arial', 12), bg=self.custom_blue).grid(row=4, column=0, sticky='w', pady=15, padx=(30, 20))
self.user_password_entry = tk.Entry(left_frame, font=('Arial', 12), show="*", width=20)
self.user_password_entry.grid(row=4, column=1, sticky='ew', pady=10)
if self.mqtt_info["密码"]:
self.user_password_entry.insert(0, self.mqtt_info["密码"])
# 右侧内容 - 标题
title_label = tk.Label(right_frame, text="HFC-RapidScan多通道\n灭火剂气体快检仪",
font=('Arial', 18, 'bold'), bg=self.custom_blue,
justify='center')
title_label.pack(pady=40)
# 开始上传按钮
self.upload_mqtt_start_button = tk.Button(right_frame, text="开始上传", font=('Arial', 16, 'bold'),
bg='green', fg='white', width=15, height=2,
command=self.upload_mqtt_start)
self.upload_mqtt_start_button.pack(pady=40)
# 底部按钮框架 - 放在容器的最下方
button_frame = tk.Frame(container, bg=self.custom_blue)
button_frame.pack(side='bottom', fill='x', pady=(20, 10))
tk.Button(button_frame, text="重新测试", font=('Arial', 12),
command=self.back_to_page1, bg='green', fg='white').pack(side='left', padx=50)
tk.Button(button_frame, text="退出", font=('Arial', 12),
command=self.root.quit, bg='red', fg='white').pack(side='right', padx=50)
def save_report(self):
"""保存汇总信息为JPG图片"""
try:
@ -628,6 +724,78 @@ class ModbusGasAnalyzer:
return False
def upload_mqtt(self):
# 切换到MQTT页面准备将数据上传
self.create_page4()
def upload_mqtt_start(self):
# 保存MQTT信息
self.mqtt_info = {
"服务器地址": self.ip_entry.get(),
"端口号": self.port_entry.get(),
"主题": self.topic_entry.get(),
"用户名": self.user_name_entry.get(),
"密码": self.user_password_entry.get(),
}
# 将数据通过MQTT上传到服务器
print(f"开始上传到MQTT");
"""连接MQTT服务器"""
try:
self.mqtt_client = mqtt.Client()
self.mqtt_client.username_pw_set(
self.mqtt_info["用户名"],
self.mqtt_info["密码"]
)
def on_connect(client, userdata, flags, rc):
if rc == 0:
print(f"MQTT连接成功: {rc}")
else:
messagebox.showerror("错误", f"MQTT连接失败: {rc}")
return
self.mqtt_client.on_connect = on_connect
self.mqtt_client.connect(
self.mqtt_info["服务器地址"],
int(self.mqtt_info["端口号"]),
3
)
self.mqtt_client.loop_start()
except ValueError as e:
# 处理端口号转换错误
messagebox.showerror("错误", f"端口号必须是数字: {str(e)}")
return
except Exception as e:
messagebox.showerror("错误", f"MQTT连接错误: {str(e)}")
return
"""整理MQTT数据"""
mqtt_payload = []
for key, value in self.user_info.items():
mqtt_payload.append(f"{key}: {value}")
mqtt_payload.append(f"浓度: {max(0.0, min(self.show_concentration, 99.990)):.3f}%")
"""上传数据到MQTT"""
try:
if self.mqtt_client:
result = self.mqtt_client.publish(
self.mqtt_info["主题"],
"\r\n".join(mqtt_payload),
qos=1 #服务质量等级
)
if result.rc == mqtt.MQTT_ERR_SUCCESS:
messagebox.showinfo("成功", f"MQTT上传成功")
else:
messagebox.showerror("错误", f"MQTT上传失败: {result}")
return
except Exception as e:
messagebox.showerror("错误", f"MQTT上传错误: {str(e)}")
return
"""断开MQTT连接"""
try:
self.mqtt_client.loop_stop()
self.mqtt_client.disconnect()
self.mqtt_client = None
except Exception as e:
print(f"MQTT断开错误: {e}")
return
def get_windows_serial_number():
"""
获取Windows系统的唯一序列号