Tuxi_Test_Qt/src/mainwindow.cpp

1237 lines
49 KiB
C++
Raw Normal View History

#include "mainwindow.h"
#include "lightstripmanager.h"
#include <QDateTime>
#include <QJsonObject>
#include <QJsonDocument>
//#include <QNetworkAccessManager>
//#include <QNetworkRequest>
//#include <QNetworkReply>
//#include <QFileInfo>
#include <QDir>
#include <QStandardPaths>
#include <QMessageBox>
#include <QUrl>
#include <QIcon>
#include <QDebug>
#include <QScreen>
#include <QGuiApplication>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), otaOperationPending(false), isUpgradeOperation(true)
{
// 初始化设置对象
settings = new QSettings("TuxiApp", "LightStripSN", this);
setupUI();
// 创建MQTT客户端
mqttClient = new MqttClient(this);
// 连接信号和槽
connect(connectBtn, &QPushButton::clicked, this, &MainWindow::onConnectClicked);
connect(disconnectBtn, &QPushButton::clicked, this, &MainWindow::onDisconnectClicked);
connect(sendLightAllBtn, &QPushButton::clicked, this, &MainWindow::onSendLightAllClicked);
connect(clearSnBtn, &QPushButton::clicked, this, &MainWindow::onClearSnListClicked);
connect(searchLightStripBtn, &QPushButton::clicked, this, &MainWindow::onSearchLightStripClicked);
connect(mqttClient, &MqttClient::connected, this, &MainWindow::onMqttConnected);
connect(mqttClient, &MqttClient::disconnected, this, &MainWindow::onMqttDisconnected);
connect(mqttClient, &MqttClient::messageReceived, this, &MainWindow::onMessageReceived);
connect(mqttClient, &MqttClient::errorOccurred, this, &MainWindow::onMqttError);
connect(otaUpgradeBtn, &QPushButton::clicked, this, &MainWindow::onOtaUpgradeClicked);
connect(otaDowngradeBtn, &QPushButton::clicked, this, &MainWindow::onOtaDowngradeClicked);
connect(getVersionBtn, &QPushButton::clicked, this, &MainWindow::onGetVersionClicked);
// 初始化灯条管理器
lightStripManager = nullptr;
// 加载已保存的灯条SN列表
loadSnList();
// 初始化状态
updateConnectionStatus(false);
currentVersionEdit->setText("请点击获取版本");
}
MainWindow::~MainWindow()
{
}
void MainWindow::setupUI() {
setWindowTitle("兔喜Test Author:Zhangzhenghao Email:zzh9953477@gmail.com");
// 参考qt_bak的合理尺寸设置增加竖向高度
setMinimumSize(850, 720); // 增加最小高度
resize(900, 770); // 增加初始高度从750增加到850
// 获取屏幕尺寸并设置合适的窗口大小
QScreen *screen = QGuiApplication::primaryScreen();
if (screen) {
QRect screenGeometry = screen->geometry();
int screenWidth = screenGeometry.width();
int screenHeight = screenGeometry.height();
// 设置合理的窗口大小,增加竖向比例
int windowWidth = qMin(1000, static_cast<int>(screenWidth * 0.6));
int windowHeight = qMin(900, static_cast<int>(screenHeight * 0.7)); // 增加到75%
// 确保高度明显大于宽度
if (windowHeight < windowWidth * 0.95) {
windowHeight = static_cast<int>(windowWidth * 0.9); // 高度等于宽度
}
resize(windowWidth, windowHeight);
// 居中显示
move((screenWidth - windowWidth) / 2, (screenHeight - windowHeight) / 2 - 50);
}
setWindowIcon(QIcon(":/image/src/tuxi.ico"));
centralWidget = new QWidget(this);
setCentralWidget(centralWidget);
mainLayout = new QVBoxLayout(centralWidget);
mainLayout->setSpacing(10); // 减少布局间距
mainLayout->setContentsMargins(15, 10, 15, 10); // 减少边距
// MQTT连接区域
connectionGroup = new QGroupBox("MQTT连接设置", this);
connectionGroup->setStyleSheet("QGroupBox { font-weight: bold; font-size: 12px; padding-top: 10px; }");
QVBoxLayout *connectionLayout = new QVBoxLayout(connectionGroup);
connectionLayout->setSpacing(10);
// 服务器和端口 - 使用水平布局
QHBoxLayout *serverLayout = new QHBoxLayout();
serverLayout->addWidget(new QLabel("服务器:"));
brokerEdit = new QLineEdit("tx-mqtt.zt-express.com");
brokerEdit->setMinimumHeight(30);
serverLayout->addWidget(brokerEdit);
serverLayout->addWidget(new QLabel("端口:"));
portEdit = new QLineEdit("1883");
portEdit->setMinimumHeight(30);
portEdit->setMaximumWidth(100);
serverLayout->addWidget(portEdit);
connectionLayout->addLayout(serverLayout);
// 用户名和密码
QHBoxLayout *authLayout = new QHBoxLayout();
authLayout->addWidget(new QLabel("用户名:"));
usernameEdit = new QLineEdit("TJ251679787196");
usernameEdit->setMinimumHeight(30);
authLayout->addWidget(usernameEdit);
authLayout->addWidget(new QLabel("密码:"));
passwordEdit = new QLineEdit();
passwordEdit->setEchoMode(QLineEdit::Password);
passwordEdit->setMinimumHeight(30);
authLayout->addWidget(passwordEdit);
connectionLayout->addLayout(authLayout);
// 连接按钮
QHBoxLayout *btnLayout = new QHBoxLayout();
connectBtn = new QPushButton("连接");
connectBtn->setMinimumHeight(35);
connectBtn->setStyleSheet("QPushButton { background-color: #4CAF50; color: white; font-weight: bold; padding: 8px 16px; border-radius: 4px; }");
disconnectBtn = new QPushButton("断开");
disconnectBtn->setMinimumHeight(35);
disconnectBtn->setStyleSheet("QPushButton { background-color: #f44336; color: white; font-weight: bold; padding: 8px 16px; border-radius: 4px; }");
btnLayout->addWidget(connectBtn);
btnLayout->addWidget(disconnectBtn);
btnLayout->addStretch();
connectionLayout->addLayout(btnLayout);
mainLayout->addWidget(connectionGroup);
// 设备控制区域
deviceGroup = new QGroupBox("设备控制", this);
deviceGroup->setStyleSheet("QGroupBox { font-weight: bold; font-size: 12px; padding-top: 10px; }");
QHBoxLayout *deviceLayout = new QHBoxLayout(deviceGroup);
deviceLayout->setSpacing(10);
deviceLayout->addWidget(new QLabel("需要测试的设备SN:"));
deviceSnEdit = new QLineEdit("TJ251617198122");
deviceSnEdit->setMinimumHeight(30);
deviceLayout->addWidget(deviceSnEdit);
mainLayout->addWidget(deviceGroup);
// 点亮参数控制区域
lightGroup = new QGroupBox("点亮参数设置", this);
lightGroup->setStyleSheet("QGroupBox { font-weight: bold; font-size: 12px; padding-top: 10px; }");
QVBoxLayout *lightLayout = new QVBoxLayout(lightGroup);
lightLayout->setSpacing(10);
// 第一行:颜色和闪烁
QHBoxLayout *row1Layout = new QHBoxLayout();
row1Layout->addWidget(new QLabel("颜色:"));
colorCombo = new QComboBox();
colorCombo->addItems({"8-灭", "1-红", "2-黄", "3-蓝", "4-绿", "5-青", "6-白", "7-紫"});
colorCombo->setCurrentIndex(6);
colorCombo->setMinimumHeight(30);
row1Layout->addWidget(colorCombo);
row1Layout->addWidget(new QLabel("闪烁:"));
flashCombo = new QComboBox();
flashCombo->addItems({"0-关闭", "1-开启"});
flashCombo->setCurrentIndex(0);
flashCombo->setMinimumHeight(30);
row1Layout->addWidget(flashCombo);
row1Layout->addStretch();
lightLayout->addLayout(row1Layout);
// 第二行:闪烁间隔和点亮时长
QHBoxLayout *row2Layout = new QHBoxLayout();
row2Layout->addWidget(new QLabel("闪烁间隔(秒):"));
flashIntervalSpin = new QSpinBox();
flashIntervalSpin->setRange(1, 60);
flashIntervalSpin->setValue(4);
flashIntervalSpin->setMinimumHeight(30);
row2Layout->addWidget(flashIntervalSpin);
row2Layout->addWidget(new QLabel("点亮时长(秒):"));
lightDurationSpin = new QSpinBox();
lightDurationSpin->setRange(1, 300);
lightDurationSpin->setValue(30);
lightDurationSpin->setMinimumHeight(30);
row2Layout->addWidget(lightDurationSpin);
row2Layout->addStretch();
lightLayout->addLayout(row2Layout);
// 第三行:声音和发送按钮
QHBoxLayout *row3Layout = new QHBoxLayout();
row3Layout->addWidget(new QLabel("声音:"));
soundCombo = new QComboBox();
soundCombo->addItems({"0-关闭", "1-开启"});
soundCombo->setCurrentIndex(0);
soundCombo->setMinimumHeight(30);
row3Layout->addWidget(soundCombo);
row3Layout->addStretch();
sendLightAllBtn = new QPushButton("发送全部点亮");
sendLightAllBtn->setMinimumHeight(40);
sendLightAllBtn->setMinimumWidth(120);
sendLightAllBtn->setStyleSheet("QPushButton { background-color: #4CAF50; color: white; font-weight: bold; padding: 10px 20px; border-radius: 6px; font-size: 14px; }");
row3Layout->addWidget(sendLightAllBtn);
lightLayout->addLayout(row3Layout);
mainLayout->addWidget(lightGroup);
// 灯条SN管理区域 - 简化为一个按钮
snGroup = new QGroupBox("灯条SN管理", this);
snGroup->setStyleSheet(
"QGroupBox { "
" font-weight: bold; "
" font-size: 14px; "
" padding-top: 15px; "
" margin: 5px; "
" border: 2px solid #ddd; "
" border-radius: 8px; "
"}"
);
snGroup->setMinimumHeight(120); // 减少最小高度
snGroup->setMaximumHeight(140); // 设置最大高度限制
QVBoxLayout *snLayout = new QVBoxLayout(snGroup);
snLayout->setSpacing(8); // 减少组件间距
snLayout->setContentsMargins(10, 20, 10, 10); // 减少内边距
// 统计信息和搜索按钮布局
QHBoxLayout *snHeaderLayout = new QHBoxLayout();
snHeaderLayout->setSpacing(8);
snCountLabel = new QLabel("已发现灯条: 0 个");
snCountLabel->setStyleSheet(
"QLabel { "
" font-weight: bold; "
" font-size: 13px; "
" color: #2196F3; "
" padding: 3px 8px; "
" background-color: #f0f8ff; "
" border: 1px solid #ddd; "
" border-radius: 6px; "
" min-height: 12px; "
"}"
);
snHeaderLayout->addWidget(snCountLabel);
snHeaderLayout->addStretch();
searchLightStripBtn = new QPushButton("搜索灯条", this);
searchLightStripBtn->setMinimumHeight(26); // 减少按钮高度
searchLightStripBtn->setMinimumWidth(90);
searchLightStripBtn->setStyleSheet(
"QPushButton { "
" background-color: #2196F3; "
" color: white; "
" padding: 4px 10px; "
" font-weight: bold; "
" border-radius: 6px; "
" font-size: 12px; "
" border: none; "
"} "
"QPushButton:hover { "
" background-color: #1976D2; "
"}"
);
snHeaderLayout->addWidget(searchLightStripBtn);
snLayout->addLayout(snHeaderLayout);
// 打开管理器按钮
openManagerBtn = new QPushButton("打开灯条SN管理器");
openManagerBtn->setMinimumHeight(32); // 减少按钮高度
openManagerBtn->setStyleSheet(
"QPushButton { "
" background-color: #2196F3; "
" color: white; "
" font-weight: bold; "
" font-size: 14px; "
" padding: 6px 16px; "
" border-radius: 8px; "
" border: none; "
" margin: 1px; "
"} "
"QPushButton:hover { "
" background-color: #1976D2; "
"} "
"QPushButton:pressed { "
" background-color: #1565C0; "
"}"
);
connect(openManagerBtn, &QPushButton::clicked, this, &MainWindow::openLightStripManager);
snLayout->addWidget(openManagerBtn);
mainLayout->addWidget(snGroup);
// 消息显示区域
messageGroup = new QGroupBox("消息日志", this);
QVBoxLayout *msgLayout = new QVBoxLayout(messageGroup);
messageDisplay = new QTextEdit();
messageDisplay->setReadOnly(true);
msgLayout->addWidget(messageDisplay);
mainLayout->addWidget(messageGroup);
// 状态栏
statusLabel = new QLabel("未连接");
statusBar()->addWidget(statusLabel);
// OTA升级区域
otaGroup = new QGroupBox("OTA升降级", this);
QVBoxLayout *otaLayout = new QVBoxLayout(otaGroup);
// 当前版本显示
QHBoxLayout *versionLayout = new QHBoxLayout();
versionLayout->addWidget(new QLabel("当前版本:"));
currentVersionEdit = new QLineEdit(this);
currentVersionEdit->setReadOnly(true);
versionLayout->addWidget(currentVersionEdit);
// 创建获取版本按钮
getVersionBtn = new QPushButton("获取版本", this);
versionLayout->addWidget(getVersionBtn);
otaLayout->addLayout(versionLayout);
// OTA按钮
QHBoxLayout *otaButtonLayout = new QHBoxLayout();
2025-09-11 01:43:22 +00:00
otaUpgradeBtn = new QPushButton("升级", this);
otaDowngradeBtn = new QPushButton("降级", this);
otaButtonLayout->addWidget(otaUpgradeBtn);
otaButtonLayout->addWidget(otaDowngradeBtn);
otaLayout->addLayout(otaButtonLayout);
// 下载进度条
otaProgressBar = new QProgressBar(this); // 修正变量名
otaProgressBar->setVisible(false);
otaLayout->addWidget(otaProgressBar);
// OTA状态标签
otaStatusLabel = new QLabel("就绪", this);
otaLayout->addWidget(otaStatusLabel);
mainLayout->addWidget(otaGroup);
}
void MainWindow::onConnectClicked() {
QString broker = brokerEdit->text().trimmed();
int portNum = portEdit->text().toInt();
QString username = usernameEdit->text().trimmed();
QString password = passwordEdit->text();
QString deviceSn = deviceSnEdit->text().trimmed();
if (broker.isEmpty()) {
QMessageBox::warning(this, "警告", "请输入MQTT服务器地址");
return;
}
if (portNum <= 0 || portNum > 65535) {
QMessageBox::warning(this, "警告", "请输入有效的端口号 (1-65535)");
return;
}
// 设置用户名和密码(如果有的话)
if (!username.isEmpty()) {
mqttClient->setUsername(username);
}
if (!password.isEmpty()) {
mqttClient->setPassword(password);
}
// 连接到MQTT服务器
mqttClient->connectToHost(broker, static_cast<quint16>(portNum));
// 更新状态
statusLabel->setText("正在连接...");
connectBtn->setEnabled(false);
// 注意订阅操作应该在连接成功后进行在onMqttConnected()函数中处理
}
void MainWindow::onDisconnectClicked()
{
mqttClient->disconnectFromHost();
}
void MainWindow::onSendLightAllClicked()
{
QString deviceSn = deviceSnEdit->text().trimmed();
if (deviceSn.isEmpty()) {
messageDisplay->append(QString("[%1] 错误: 请输入设备SN")
.arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
return;
}
if (!mqttClient->isConnected()) {
messageDisplay->append(QString("[%1] 错误: MQTT未连接")
.arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
return;
}
// 获取参数值
QString color = QString::number(colorCombo->currentIndex());
QString flash = QString::number(flashCombo->currentIndex());
QString flashInterval = QString::number(flashIntervalSpin->value());
QString lightDuration = QString::number(lightDurationSpin->value());
QString sound = QString::number(soundCombo->currentIndex());
// 构造消息内容
QJsonObject dataObj;
dataObj["color"] = color;
dataObj["flash"] = flash;
dataObj["flashInterval"] = flashInterval;
dataObj["lightDuration"] = lightDuration;
dataObj["sound"] = sound;
QJsonObject msgObj;
msgObj["data"] = dataObj;
msgObj["msgType"] = "3027";
QJsonObject rootObj;
rootObj["deviceId"] = deviceSn;
rootObj["messageId"] = "1933039995430551552";
// 修复将QByteArray转换为QString
rootObj["msg"] = QString::fromUtf8(QJsonDocument(msgObj).toJson(QJsonDocument::Compact));
rootObj["timestamp"] = 2147483647;
QString message = QJsonDocument(rootObj).toJson(QJsonDocument::Compact);
// 发送到指定主题
QString topic = QString("iot/10045/%1/message/adviceDevice").arg(deviceSn);
if (mqttClient->publish(topic, message)) {
messageDisplay->append(QString("[%1] 发送全部点亮指令到设备 %2")
.arg(QDateTime::currentDateTime().toString("hh:mm:ss"))
.arg(deviceSn));
messageDisplay->append(QString("主题: %1").arg(topic));
messageDisplay->append(QString("参数: 颜色=%1, 闪烁=%2, 间隔=%3s, 时长=%4s, 声音=%5")
.arg(colorCombo->currentText())
.arg(flashCombo->currentText())
.arg(flashInterval)
.arg(lightDuration)
.arg(soundCombo->currentText()));
} else {
messageDisplay->append(QString("[%1] 发送全部点亮指令失败")
.arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
}
}
void MainWindow::onMqttConnected() {
statusLabel->setText("MQTT连接成功");
statusLabel->setStyleSheet("QLabel { color: green; font-weight: bold; }");
updateConnectionStatus(true);
QString deviceSn = deviceSnEdit->text().trimmed();
if (!deviceSn.isEmpty()) {
// 订阅原有主题
QString responseTopic = QString("iot/10045/%1/response").arg(deviceSn);
QString stationTopic = QString("iot/10045/%1/station/report").arg(deviceSn);
// 订阅light report主题
QString lightReportTopic = QString("iot/10045/%1/light/report").arg(deviceSn);
// 订阅adviceDevice主题用于搜索灯条响应
QString adviceDeviceTopic = QString("iot/10045/%1/message/adviceDevice").arg(deviceSn);
QString resourceReportTopic = QString("iot/10045/%1/resource/report").arg(deviceSn);
mqttClient->subscribe(responseTopic);
mqttClient->subscribe(stationTopic);
mqttClient->subscribe(lightReportTopic);
mqttClient->subscribe(adviceDeviceTopic);
mqttClient->subscribe(resourceReportTopic);
messageDisplay->append(QString("[%1] 已订阅主题: %2")
.arg(QDateTime::currentDateTime().toString("hh:mm:ss"))
.arg(responseTopic));
messageDisplay->append(QString("[%1] 已订阅主题: %2")
.arg(QDateTime::currentDateTime().toString("hh:mm:ss"))
.arg(stationTopic));
messageDisplay->append(QString("[%1] 已订阅主题: %2")
.arg(QDateTime::currentDateTime().toString("hh:mm:ss"))
.arg(lightReportTopic));
messageDisplay->append(QString("[%1] 已订阅主题: %2")
.arg(QDateTime::currentDateTime().toString("hh:mm:ss"))
.arg(adviceDeviceTopic));
messageDisplay->append(QString("[%1] 已订阅主题: %2")
.arg(QDateTime::currentDateTime().toString("hh:mm:ss"))
.arg(resourceReportTopic));
}
}
void MainWindow::onMqttDisconnected()
{
messageDisplay->append(QString("[%1] MQTT连接断开")
.arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
updateConnectionStatus(false);
}
void MainWindow::onMqttError(const QString &error)
{
messageDisplay->append(QString("[%1] MQTT错误: %2")
.arg(QDateTime::currentDateTime().toString("hh:mm:ss"))
.arg(error));
updateConnectionStatus(false);
}
void MainWindow::onMessageReceived(const QString &topic, const QString &message) {
// 显示接收到的消息
messageDisplay->append(QString("[%1] 收到消息").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
messageDisplay->append(QString("Topic: %1").arg(topic));
messageDisplay->append(QString("Message: %1").arg(message));
messageDisplay->append("---");
// 处理消息格式问题提取纯JSON部分
QString jsonMessage = message;
QString realTopic = topic;
// 如果topic是默认的incoming/topic尝试从消息中提取真实主题
if (topic == "incoming/topic" && message.contains("{")) {
// 查找消息中的主题信息(格式:%topic{json}
if (message.startsWith("%")) {
int jsonStart = message.indexOf("{");
if (jsonStart > 1) {
realTopic = message.mid(1, jsonStart - 1); // 去掉开头的%
messageDisplay->append(QString("[DEBUG] 从消息中提取到真实主题: %1").arg(realTopic));
}
}
}
// 去除开头的单引号
if (jsonMessage.startsWith("'")) {
jsonMessage = jsonMessage.mid(1);
}
// 去除结尾的单引号
if (jsonMessage.endsWith("'")) {
jsonMessage = jsonMessage.left(jsonMessage.length() - 1);
}
// 检查消息是否包含主题信息(格式:%topic{json}或topic{json}
if (jsonMessage.contains("{")) {
int jsonStart = jsonMessage.indexOf("{");
if (jsonStart != -1) {
jsonMessage = jsonMessage.mid(jsonStart);
}
}
// 解析JSON消息
QJsonParseError error;
QJsonDocument doc = QJsonDocument::fromJson(jsonMessage.toUtf8(), &error);
if (error.error != QJsonParseError::NoError) {
messageDisplay->append(QString("[%1] JSON解析错误: %2")
.arg(QDateTime::currentDateTime().toString("hh:mm:ss"))
.arg(error.errorString()));
return;
}
QJsonObject root = doc.object();
messageDisplay->append(QString("[%1] JSON解析成功").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
// 检查是否包含msg字段优先处理
if (root.contains("msg")) {
messageDisplay->append(QString("[%1] 找到msg字段").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
QJsonValue msgValue = root["msg"];
QJsonObject msgObj;
// msg可能是字符串或对象
if (msgValue.isString()) {
QJsonDocument msgDoc = QJsonDocument::fromJson(msgValue.toString().toUtf8());
if (!msgDoc.isNull()) {
msgObj = msgDoc.object();
}
} else if (msgValue.isObject()) {
msgObj = msgValue.toObject();
messageDisplay->append(QString("[%1] msg是对象类型").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
}
// 解析data中的baseVersion
if (msgObj.contains("data")) {
messageDisplay->append(QString("[%1] 找到data字段").arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
QJsonObject dataObj = msgObj["data"].toObject();
if (dataObj.contains("baseVersion")) {
QString version = dataObj["baseVersion"].toString();
messageDisplay->append(QString("[%1] 找到baseVersion: %2")
.arg(QDateTime::currentDateTime().toString("hh:mm:ss"))
.arg(version));
// 确保currentVersionEdit存在
if (currentVersionEdit) {
currentVersionEdit->setText(version);
messageDisplay->append(QString("[%1] 版本已设置到输入框: %2")
.arg(QDateTime::currentDateTime().toString("hh:mm:ss"))
.arg(version));
} else {
messageDisplay->append(QString("[%1] 错误: currentVersionEdit为空")
.arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
}
statusLabel->setText(QString("获取到当前版本: %1").arg(version));
return;
}
}
}
// 检查是否包含resource字段直接在根对象中
if (root.contains("resource")) {
QString resource = root["resource"].toString();
QString version = resource.trimmed();
messageDisplay->append(QString("[%1] 找到resource字段: %2")
.arg(QDateTime::currentDateTime().toString("hh:mm:ss"))
.arg(version));
if (currentVersionEdit) {
currentVersionEdit->setText(version);
messageDisplay->append(QString("[%1] 版本已设置到输入框: %2")
.arg(QDateTime::currentDateTime().toString("hh:mm:ss"))
.arg(version));
}
statusLabel->setText(QString("获取到当前版本: %1").arg(version));
return;
}
// 检查是否是light/report主题使用提取的真实主题
if (realTopic.contains("/light/report")) {
messageDisplay->append("[DEBUG] 检测到light/report消息开始解析SN");
processLightReportMessage(jsonMessage);
}
// 检查是否是station/report主题且有待处理的OTA操作
if (otaOperationPending && (realTopic.contains("/station/report") || realTopic.contains("/resource/report"))) {
QString operationType = isUpgradeOperation ? "升级" : "降级";
QString successMessage = QString("OTA%1成功 版本: %2")
.arg(operationType)
.arg(pendingOtaVersion);
messageDisplay->append(QString("[%1] %2")
.arg(QDateTime::currentDateTime().toString("hh:mm:ss"))
.arg(successMessage));
// 重置OTA状态
otaOperationPending = false;
pendingOtaVersion.clear();
isUpgradeOperation = false;
statusLabel->setText(successMessage);
}
}
void MainWindow::processOtaMessage(const QJsonObject &otaData)
{
QString version = otaData["version"].toString();
QString zipPath = otaData["zipPath"].toString();
int installType = otaData["installType"].toInt();
int immediately = otaData["immediately"].toInt();
otaStatusLabel->setText(QString("收到OTA任务: 版本 %1").arg(version));
}
void MainWindow::onOtaUpgradeClicked() {
// 获取设备SN
QString deviceSn = deviceSnEdit->text().trimmed();
if (deviceSn.isEmpty()) {
QMessageBox::warning(this, "警告", "请先输入设备SN");
return;
}
// 设置OTA状态跟踪
otaOperationPending = true;
pendingOtaVersion = "1.1.41";
isUpgradeOperation = true;
// 构造符合您格式的OTA升级消息
QJsonObject data;
data["msgType"] = "1014";
QJsonObject otaData;
otaData["needWifi"] = 2;
otaData["zipPath"] = "http://180.163.74.83:8000/tx_ota_1.1.41.zip";
otaData["installType"] = 2;
otaData["immediately"] = 0;
otaData["installTime"] = QDateTime::currentMSecsSinceEpoch() + 300000; // 5分钟后安装
otaData["version"] = "1.1.41";
data["data"] = otaData;
QJsonObject root;
root["deviceId"] = deviceSn; // 使用输入的设备SN
root["header"] = QJsonValue::Null;
root["messageId"] = QString::number(QDateTime::currentMSecsSinceEpoch());
root["msg"] = QString::fromUtf8(QJsonDocument(data).toJson(QJsonDocument::Compact));
root["productId"] = "";
root["timestamp"] = QDateTime::currentMSecsSinceEpoch();
QJsonDocument doc(root);
QString message = QString::fromUtf8(doc.toJson(QJsonDocument::Compact));
// 构建正确的MQTT主题
QString topic = QString("iot/10045/%1/message/adviceDevice").arg(deviceSn);
if (mqttClient && mqttClient->isConnected()) {
mqttClient->publish(topic, message);
statusLabel->setText(QString("已发送OTA升级命令到设备 %1 (版本 1.1.41)").arg(deviceSn));
// 显示发送的消息内容
QMessageBox::information(this, "OTA升级命令",
QString("已发送升级命令:\n设备SN: %1\n版本: 1.1.41\n主题: %2\n消息: %3")
.arg(deviceSn, topic, message));
} else {
statusLabel->setText("MQTT未连接无法发送OTA命令");
// 如果发送失败,重置状态
otaOperationPending = false;
}
}
void MainWindow::onOtaDowngradeClicked() {
// 获取设备SN
QString deviceSn = deviceSnEdit->text().trimmed();
if (deviceSn.isEmpty()) {
QMessageBox::warning(this, "警告", "请先输入设备SN");
return;
}
// 设置OTA状态跟踪
otaOperationPending = true;
pendingOtaVersion = "1.1.40";
isUpgradeOperation = false;
// 构造符合您格式的OTA降级消息
QJsonObject data;
data["msgType"] = "1014";
QJsonObject otaData;
otaData["needWifi"] = 2;
otaData["zipPath"] = "http://180.163.74.83:8000/tx_ota_1.1.40.zip";
otaData["installType"] = 2;
otaData["immediately"] = 0;
otaData["installTime"] = QDateTime::currentMSecsSinceEpoch() + 300000; // 5分钟后安装
otaData["version"] = "1.1.40";
data["data"] = otaData;
QJsonObject root;
root["deviceId"] = deviceSn; // 使用输入的设备SN
root["header"] = QJsonValue::Null;
root["messageId"] = QString::number(QDateTime::currentMSecsSinceEpoch());
root["msg"] = QString::fromUtf8(QJsonDocument(data).toJson(QJsonDocument::Compact));
root["productId"] = "";
root["timestamp"] = QDateTime::currentMSecsSinceEpoch();
QJsonDocument doc(root);
QString message = QString::fromUtf8(doc.toJson(QJsonDocument::Compact));
// 构建正确的MQTT主题
QString topic = QString("iot/10045/%1/message/adviceDevice").arg(deviceSn);
if (mqttClient && mqttClient->isConnected()) {
mqttClient->publish(topic, message);
statusLabel->setText(QString("已发送OTA降级命令到设备 %1 (版本 1.1.40)").arg(deviceSn));
// 显示发送的消息内容
QMessageBox::information(this, "OTA降级命令",
QString("已发送降级命令:\n设备SN: %1\n版本: 1.1.40\n主题: %2\n消息: %3")
.arg(deviceSn, topic, message));
} else {
statusLabel->setText("MQTT未连接无法发送OTA命令");
// 如果发送失败,重置状态
otaOperationPending = false;
}
}
void MainWindow::onSearchLightStripClicked() {
sendSearchLightStripCommand();
}
void MainWindow::sendSearchLightStripCommand() {
QString deviceSn = deviceSnEdit->text().trimmed();
if (deviceSn.isEmpty()) {
messageDisplay->append(QString("[%1] 错误: 设备SN不能为空")
.arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
return;
}
QString topic = QString("iot/10045/%1/message/adviceDevice").arg(deviceSn);
// 构造消息
QJsonObject message;
message["deviceId"] = "";
message["header"] = QJsonValue::Null;
message["messageId"] = "1958474134031921152";
message["productId"] = "";
message["timestamp"] = QDateTime::currentMSecsSinceEpoch();
// 构造msg字段
QJsonObject msgData;
msgData["scene"] = "1";
msgData["timeout"] = "120";
QJsonObject msgObj;
msgObj["data"] = msgData;
msgObj["msgType"] = "5005";
QJsonDocument msgDoc(msgObj);
message["msg"] = QString::fromUtf8(msgDoc.toJson(QJsonDocument::Compact));
QJsonDocument doc(message);
QString jsonString = doc.toJson(QJsonDocument::Compact);
// 发送消息
mqttClient->publish(topic, jsonString);
messageDisplay->append(QString("[%1] 发送搜索灯条命令")
.arg(QDateTime::currentDateTime().toString("hh:mm:ss")));
messageDisplay->append(QString("Topic: %1").arg(topic));
messageDisplay->append(QString("Message: %1").arg(jsonString));
messageDisplay->append("---");
}
void MainWindow::sendOtaCommand(const QString& version, bool isUpgrade) {
QJsonObject msg;
msg["action"] = isUpgrade ? "upgrade" : "downgrade";
msg["version"] = version;
QJsonObject root;
root["type"] = "ota_command";
root["msg"] = QString::fromUtf8(QJsonDocument(msg).toJson(QJsonDocument::Compact));
QJsonDocument doc(root);
QString message = QString::fromUtf8(doc.toJson(QJsonDocument::Compact));
if (mqttClient && mqttClient->isConnected()) {
mqttClient->publish("device/ota/command", message);
statusLabel->setText(QString("已发送OTA%1命令 (版本 %2)").arg(isUpgrade ? "升级" : "降级", version));
} else {
statusLabel->setText("MQTT未连接无法发送OTA命令");
}
}
void MainWindow::onGetVersionClicked() {
// 获取设备SN
QString deviceSn = deviceSnEdit->text().trimmed();
if (deviceSn.isEmpty()) {
QMessageBox::warning(this, "警告", "请先输入设备SN");
return;
}
// 构造获取版本的消息
QJsonObject data;
data["msgType"] = "2335";
QJsonObject cmdData;
cmdData["cmd"] = "cat /userdata/tx_version";
data["data"] = cmdData;
QJsonObject root;
root["deviceId"] = deviceSn;
root["header"] = QJsonValue::Null;
root["messageId"] = QString::number(QDateTime::currentMSecsSinceEpoch());
root["msg"] = QString::fromUtf8(QJsonDocument(data).toJson(QJsonDocument::Compact));
root["productId"] = "";
root["timestamp"] = QDateTime::currentMSecsSinceEpoch();
QJsonDocument doc(root);
QString message = QString::fromUtf8(doc.toJson(QJsonDocument::Compact));
// 使用正确的发送主题
QString topic = QString("iot/10045/%1/message/adviceDevice").arg(deviceSn);
if (mqttClient && mqttClient->isConnected()) {
mqttClient->publish(topic, message);
statusLabel->setText(QString("已发送获取版本命令到设备 %1").arg(deviceSn));
} else {
statusLabel->setText("MQTT未连接无法发送命令");
}
}
void MainWindow::updateConnectionStatus(bool connected)
{
connectBtn->setEnabled(!connected);
disconnectBtn->setEnabled(connected);
sendLightAllBtn->setEnabled(connected);
// 新增:连接成功后禁用连接参数输入框,断开后重新启用
usernameEdit->setEnabled(!connected);
portEdit->setEnabled(!connected);
passwordEdit->setEnabled(!connected);
brokerEdit->setEnabled(!connected); // 同时也禁用服务器地址输入框
// 修改连接按钮样式:连接成功后设置灰色背景,断开后恢复绿色
if (connected) {
connectBtn->setStyleSheet("QPushButton { background-color: #cccccc; color: #666666; font-weight: bold; padding: 8px 16px; border-radius: 4px; }");
statusLabel->setText("已连接");
statusLabel->setStyleSheet("color: green;");
} else {
connectBtn->setStyleSheet("QPushButton { background-color: #4CAF50; color: white; font-weight: bold; padding: 8px 16px; border-radius: 4px; }");
statusLabel->setText("未连接");
statusLabel->setStyleSheet("color: red;");
}
}
void MainWindow::processLightReportMessage(const QString &message) {
messageDisplay->append(QString("[DEBUG] 开始处理light/report消息: %1").arg(message));
QJsonParseError error;
QJsonDocument doc = QJsonDocument::fromJson(message.toUtf8(), &error);
if (error.error != QJsonParseError::NoError) {
messageDisplay->append(QString("[ERROR] JSON解析失败: %1").arg(error.errorString()));
return;
}
QJsonObject rootObj = doc.object();
messageDisplay->append(QString("[DEBUG] 根对象键: %1").arg(QStringList(rootObj.keys()).join(", ")));
QJsonObject msgObj = rootObj["msg"].toObject();
messageDisplay->append(QString("[DEBUG] msg对象键: %1").arg(QStringList(msgObj.keys()).join(", ")));
QJsonObject dataObj = msgObj["data"].toObject();
messageDisplay->append(QString("[DEBUG] data对象键: %1").arg(QStringList(dataObj.keys()).join(", ")));
QJsonArray lightsArray = dataObj["lights"].toArray();
messageDisplay->append(QString("[DEBUG] lights数组长度: %1").arg(lightsArray.size()));
int newSnCount = 0;
for (const QJsonValue &lightValue : lightsArray) {
QJsonObject lightObj = lightValue.toObject();
QString sn = lightObj["sn"].toString();
messageDisplay->append(QString("[DEBUG] 处理灯条SN: %1").arg(sn));
if (!sn.isEmpty() && !uniqueSnSet.contains(sn)) {
messageDisplay->append(QString("[DEBUG] 添加新SN到列表: %1").arg(sn));
addSnToList(sn);
newSnCount++;
} else if (sn.isEmpty()) {
messageDisplay->append("[DEBUG] SN为空跳过");
} else if (uniqueSnSet.contains(sn)) {
messageDisplay->append(QString("[DEBUG] SN已存在跳过: %1").arg(sn));
}
}
if (newSnCount > 0) {
messageDisplay->append(QString("[INFO] 新发现 %1 个灯条SN").arg(newSnCount));
saveSnList();
} else {
messageDisplay->append("[DEBUG] 没有发现新的灯条SN");
}
}
void MainWindow::addSnToList(const QString &sn)
{
if (uniqueSnSet.contains(sn)) {
return;
}
uniqueSnSet.insert(sn);
// 更新主窗口的计数显示
snCountLabel->setText(QString("已发现灯条: %1 个").arg(uniqueSnSet.size()));
// 如果灯条管理器已打开同步添加但不重复更新MainWindow的计数
if (lightStripManager) {
// 临时断开信号连接,避免重复更新
disconnect(lightStripManager, &LightStripManager::snCountChanged, this, nullptr);
lightStripManager->addSnToList(sn);
// 重新连接信号
connect(lightStripManager, &LightStripManager::snCountChanged,
this, [this](int count) {
snCountLabel->setText(QString("已发现灯条: %1 个").arg(count));
});
}
// 移除这里的saveSnList()调用,让调用方决定何时保存
// saveSnList();
}
void MainWindow::saveSnList() {
QStringList snList = uniqueSnSet.values();
settings->setValue("lightStripSnList", snList);
settings->sync();
}
void MainWindow::loadSnList() {
QStringList snList = settings->value("lightStripSnList").toStringList();
for (const QString &sn : snList) {
addSnToList(sn);
}
}
void MainWindow::onClearSnListClicked()
{
// 清空所有灯条widget
QLayoutItem *item;
while ((item = snHorizontalLayout->takeAt(0)) != nullptr) {
delete item->widget();
delete item;
}
// 清空复选框列表和SN集合
lightStripCheckBoxes.clear();
uniqueSnSet.clear();
// 更新计数显示
snCountLabel->setText("已发现灯条: 0 个");
// 移除对lightStripManager的直接调用
// 让灯条管理器独立管理自己的数据
// 保存设置
saveSnList();
}
void MainWindow::openLightStripManager()
{
if (!lightStripManager) {
lightStripManager = new LightStripManager(this);
// 连接信号
connect(lightStripManager, &LightStripManager::lightControlRequested,
this, [this](const QStringList &sns, const QString &color, bool flash, int interval, int duration, bool sound) {
// 处理点亮控制请求
// 实现MQTT发送逻辑
// 检查MQTT连接状态
if (!mqttClient->isConnected()) {
qDebug() << "MQTT未连接无法发送灯条控制命令";
QMessageBox::warning(this, "警告", "MQTT未连接请先连接MQTT服务器");
return;
}
// 获取设备SN从界面获取
QString deviceSn = deviceSnEdit->text().trimmed();
if (deviceSn.isEmpty()) {
QMessageBox::warning(this, "警告", "请先输入需要测试的设备SN");
return;
}
// 构建内层msg数据
QJsonObject msgData;
QRegularExpression re("\\d+");
QRegularExpressionMatch match = re.match(color);
if (match.hasMatch()) {
msgData["color"] = match.captured(0); // 提取到的数字字符串
} else {
msgData["color"] = "0"; // 默认值
}
msgData["flash"] = flash ? "1" : "0";
msgData["flashInterval"] = QString::number(interval);
msgData["lightDuration"] = QString::number(duration);
msgData["scene"] = "3"; // 根据业务需求设置
msgData["sound"] = sound ? "1" : "0";
// 构建lights数组
QJsonArray lightsArray;
for (const QString &sn : sns) {
QJsonObject lightObj;
lightObj["sn"] = sn;
lightsArray.append(lightObj);
}
msgData["lights"] = lightsArray;
// 构建完整的msg对象
QJsonObject fullMsg;
fullMsg["data"] = msgData;
fullMsg["msgType"] = "3015"; // 根据业务协议设置
// 转换msg为JSON字符串
QJsonDocument msgDoc(fullMsg);
QString msgString = msgDoc.toJson(QJsonDocument::Compact);
// 构建最外层消息
QJsonObject outerMessage;
outerMessage["deviceId"] = ""; // 根据需要设置
outerMessage["messageId"] = QString::number(QDateTime::currentMSecsSinceEpoch()); // 生成唯一消息ID
outerMessage["msg"] = msgString;
outerMessage["timestamp"] = QDateTime::currentMSecsSinceEpoch();
// 转换为最终JSON字符串
QJsonDocument finalDoc(outerMessage);
QString finalMessage = finalDoc.toJson(QJsonDocument::Compact);
// 构建MQTT主题
QString topic = QString("iot/10045/%1/message/adviceDevice").arg(deviceSn);
// 发送MQTT消息
bool success = mqttClient->publish(topic, finalMessage);
if (success) {
qDebug() << "成功发送灯条控制命令";
qDebug() << "主题:" << topic;
qDebug() << "消息:" << finalMessage;
// 显示成功提示
QString resultMessage = QString("已向设备 %1 发送控制命令,控制 %2 个灯条")
.arg(deviceSn)
.arg(sns.size());
QMessageBox::information(this, "成功", resultMessage);
} else {
qDebug() << "发送灯条控制命令失败";
QMessageBox::warning(this, "错误", "发送MQTT消息失败请检查网络连接");
}
});
connect(lightStripManager, &LightStripManager::snSelectionChanged,
this, [this](const QStringList &selectedSns) {
// 处理选择变化
qDebug() << "Selected SNs changed:" << selectedSns;
});
// 新增:连接数量变化信号
connect(lightStripManager, &LightStripManager::snCountChanged,
this, [this](int count) {
// 同步更新MainWindow中的灯条数量显示
snCountLabel->setText(QString("已发现灯条: %1 个").arg(count));
});
2025-09-11 02:12:19 +00:00
// 新增:连接身份信息绑定信号
connect(lightStripManager, &LightStripManager::identityBindingRequested,
this, [this](const QString &sn, const QString &label1, const QString &label2, const QString &label3) {
// 处理身份信息绑定请求
// 检查MQTT连接状态
if (!mqttClient->isConnected()) {
qDebug() << "MQTT未连接无法发送身份信息绑定命令";
QMessageBox::warning(this, "警告", "MQTT未连接请先连接MQTT服务器");
return;
}
// 获取设备SN从界面获取
QString deviceSn = deviceSnEdit->text().trimmed();
if (deviceSn.isEmpty()) {
QMessageBox::warning(this, "警告", "请先输入需要测试的设备SN");
return;
}
// 构建身份信息绑定消息
QJsonObject msgData;
msgData["sn"] = sn;
msgData["label1"] = label1;
msgData["label2"] = label2;
msgData["label3"] = label3;
// 构建完整的msg对象
QJsonObject fullMsg;
fullMsg["data"] = msgData;
fullMsg["msgType"] = "3022"; // 身份信息绑定消息类型
// 转换msg为JSON字符串
QJsonDocument msgDoc(fullMsg);
QString msgString = msgDoc.toJson(QJsonDocument::Compact);
// 构建最外层消息
QJsonObject outerMessage;
outerMessage["deviceId"] = "";
outerMessage["messageId"] = QString::number(QDateTime::currentMSecsSinceEpoch());
outerMessage["msg"] = msgString;
outerMessage["timestamp"] = QDateTime::currentMSecsSinceEpoch();
// 转换为最终JSON字符串
QJsonDocument finalDoc(outerMessage);
QString finalMessage = finalDoc.toJson(QJsonDocument::Compact);
// 构建MQTT主题
QString topic = QString("iot/10045/%1/message/adviceDevice").arg(deviceSn);
// 发送MQTT消息
bool success = mqttClient->publish(topic, finalMessage);
if (success) {
qDebug() << "成功发送身份信息绑定命令";
qDebug() << "主题:" << topic;
qDebug() << "消息:" << finalMessage;
// 在消息显示区域显示发送的消息
messageDisplay->append(QString("[%1] 发送身份信息绑定到设备 %2")
.arg(QDateTime::currentDateTime().toString("hh:mm:ss"))
.arg(deviceSn));
messageDisplay->append(QString("主题: %1").arg(topic));
messageDisplay->append(QString("灯条SN: %1, Label1: %2, Label2: %3, Label3: %4")
.arg(sn).arg(label1).arg(label2).arg(label3));
} else {
qDebug() << "发送身份信息绑定命令失败";
QMessageBox::warning(this, "错误", "发送MQTT消息失败请检查网络连接");
}
});
// 连接关闭信号
connect(lightStripManager, &QWidget::destroyed,
this, &MainWindow::onLightStripManagerClosed);
// 同步当前的SN列表到管理器
for (const QString &sn : uniqueSnSet) {
lightStripManager->addSnToList(sn);
}
}
lightStripManager->show();
lightStripManager->raise();
lightStripManager->activateWindow();
}
void MainWindow::onLightStripManagerClosed()
{
// 灯条管理器关闭时的处理
lightStripManager = nullptr;
qDebug() << "Light strip manager closed";
}
QString MainWindow::getDeviceSn() const
{
return deviceSnEdit->text().trimmed();
}
bool MainWindow::isMqttConnected() const
{
return mqttClient && mqttClient->isConnected();
}
void MainWindow::publishMqttMessage(const QString &topic, const QString &message)
{
if (mqttClient && mqttClient->isConnected()) {
mqttClient->publish(topic, message);
messageDisplay->append(QString("[%1] 发送消息到主题: %2")
.arg(QDateTime::currentDateTime().toString("hh:mm:ss"))
.arg(topic));
} else {
QMessageBox::warning(this, "错误", "MQTT未连接无法发送消息");
}
}