Browse Source

V0.3.9
1、新增了发送到MQTT中对比项信息的功能

Apple 1 day ago
parent
commit
c29f8e2647

+ 25 - 37
JSON/对比项信息.json

@@ -1,46 +1,34 @@
 [
     {
         "compareItem_id": 1,
-        "compareItem_name": "对比项1号",
-        "recordRoad": [
-            {
-                "recordRoad_id" : 1,
-                "recordRoad_name": "录音通道1号",
-                "recordRoad_num": 1
-            },
-            {
-                "recordRoad_id" : 2,
-                "recordRoad_name": "录音通道2号",
-                "recordRoad_num" : 2
-            }
-        ],
-        "silence_switch" : true,
-        "silence_threshold": 90,
-        "silence_duration": 10,
+        "compareItem_name": "one",
+        "overload_duration": 30,
+        "overload_sensitivity": 20,
         "overload_switch": true,
-        "overload_threshold": 120,
-        "overload_duration": 10
+        "overload_threshold": 4,
+        "reverse_duration": 60,
+        "reverse_sensitivity": 60,
+        "reverse_switch": true,
+        "reverse_threshold": 0.75,
+        "silence_duration": 8,
+        "silence_sensitivity": 80,
+        "silence_switch": true,
+        "silence_threshold": 64
     },
     {
         "compareItem_id": 2,
-        "compareItem_name": "对比项2号",
-        "recordRoad": [
-            {
-                "recordRoad_id" : 3,
-                "recordRoad_name": "录音通道3号",
-                "recordRoad_num": 3
-            },
-            {
-                "recordRoad_id" : 4,
-                "recordRoad_name": "录音通道4号",
-                "recordRoad_num" : 4
-            }
-        ],
-        "silence_switch" : false,
-        "silence_threshold": 80,
-        "silence_duration": 5,
-        "overload_switch": false,
-        "overload_threshold": 100,
-        "overload_duration": 5
+        "compareItem_name": "two",
+        "overload_duration": 30,
+        "overload_sensitivity": 20,
+        "overload_switch": true,
+        "overload_threshold": 4,
+        "reverse_duration": 60,
+        "reverse_sensitivity": 60,
+        "reverse_switch": true,
+        "reverse_threshold": 0.75,
+        "silence_duration": 8,
+        "silence_sensitivity": 80,
+        "silence_switch": true,
+        "silence_threshold": 64
     }
 ]

+ 1 - 0
Server/ACAServer.h

@@ -56,6 +56,7 @@ private:
     void thread_deleteRecordThread();
     /* 线程函数,开启RTP监听服务,一个壳 */
     void thread_RTPServer();
+    /* 线程函数,为了发送MQTT消息,更新对比项信息到MQTT中,数据由对比项管理器提供 */
 
 private slots:
     /* 处理MQTT消息 */

+ 3 - 3
Server/GlobalInfo/GlobalInfo.h

@@ -50,8 +50,8 @@ public:
     QString mqttIP() const {return m_mqttIP;}
     int mqttPort() const {return m_mqttPort;}
     void setMqttInfo(const QString& ip, int port);
-    QString mqttPublishTopic() const {return m_mqttPublishTopic;}
-    QString mqttPubTopicDB() const {return m_pubTopicDB;}
+    const QString& mqttPubTopicDB() const {return m_pubTopicDB;}
+    const QString& mqttPubTopicCompareItem() const {return m_pubTopicCompareItem;}
     
     /* 获取WebAPI信息 */
     QString webAPIUrl() const {return m_webAPIUrl;}
@@ -147,8 +147,8 @@ private:
     QString m_webAPIUrl;               /* WebAPI地址 */
     QString m_webAPIID;                /* WebAPI ID */
     const QString m_webAPIAppType = "ACAWatch"; /* 应用类型 */
-    QString m_mqttPublishTopic = "LH_ACAServer"; /* MQTT发布主题 */
     QString m_pubTopicDB = "LH_ACAServer/DB"; /* 音量包发布主题 */
+    QString m_pubTopicCompareItem = "LH_ACAServer/CompareItems"; /* 对比项发布主题 */
 
     /******************** 音频基础数据 *********************/
     /* 环形队列中每个文件的大小,也是生成的wav文件的大小

+ 1 - 0
Server/ThreadCalculate/BaseCalculateThread.h

@@ -33,6 +33,7 @@ public:
     virtual void stopThread();
     /* 停止线程 */
     virtual void stopThreadBlock();
+
     
 
 protected:

+ 40 - 18
Server/ThreadCalculate/CalculateDBThread.cpp

@@ -115,7 +115,6 @@ void CalculateDBThread::task()
     while(m_isRunning)
     {
         std::this_thread::sleep_for(std::chrono::milliseconds(10));
-        /* 判断是否是需要计算的时间段 */
 
         /* --------------------------------------------------------------------------------
          * 更新最新数据
@@ -132,9 +131,10 @@ void CalculateDBThread::task()
         /* --------------------------------------------------------------------------------
          * 计算数据
          * --------------------------------------------------------------------------------*/
-        calcuDBPhase();
+        calcuDBData();
     }
-
+    /* 停止所有的报警 */
+    endAllAlarm();
     /* 清理数据 */
     clearData();
 
@@ -220,8 +220,11 @@ void CalculateDBThread::clearData()
 
 }
 
-/* 计算静音过载反相 */
-void CalculateDBThread::calcuDBPhase()
+/**
+    计算静音过载反相,如果不是在某一项的计算时间段内,那么这个项目无需计算,全部为false,
+    报警检测依旧是要继续的,为了结束可能还存在的报警
+ */
+void CalculateDBThread::calcuDBData()
 {
     /* 有最新数据,进行计算 */
     m_mutexVolumeInfo.lock();
@@ -232,21 +235,39 @@ void CalculateDBThread::calcuDBPhase()
         m_roadVolumeInfo.vecrightDB[i] = m_currSecondData.aryRightDB[i];
     }
 
+    /* 更新时间信息 */
+    m_roadVolumeInfo.dateTime = m_currSecondData.startTime;
+
     /* 计算静音 */
-    m_roadVolumeInfo.isSilence = m_caculateDBData.calculateSilent(m_volumeParam, m_avgCalculateDBSeconds, 
+    if(m_isSilenceInDetectPeriod)
+    {
+        m_roadVolumeInfo.isSilence = m_caculateDBData.calculateSilent(m_volumeParam, m_avgCalculateDBSeconds, 
                                     m_silentStartPos, m_silentEndPos);
+    }else {
+        m_roadVolumeInfo.isSilence = false;
+    }
+    
     /* 计算过载 */
-    m_roadVolumeInfo.isOverload = m_caculateDBData.calculateOverload(m_volumeParam, m_avgCalculateDBSeconds, 
+    if(m_isOverloadInDetectPeriod)
+    {
+        m_roadVolumeInfo.isOverload = m_caculateDBData.calculateOverload(m_volumeParam, m_avgCalculateDBSeconds, 
                                     m_overloadStartPos, m_overloadEndPos, m_bLastOverload);
+    }else {
+        m_roadVolumeInfo.isOverload = false;
+    }
+    
     /* 计算反相 */
-    m_roadVolumeInfo.isReversed = m_caculateDBData.calculatePhase(m_volumeParam, m_avgCalculateDBSeconds, 
+    if(m_isPhaseInDetectPeriod)
+    {
+        m_roadVolumeInfo.isReversed = m_caculateDBData.calculatePhase(m_volumeParam, m_avgCalculateDBSeconds, 
                                     m_phaseStartPos, m_phaseEndPos, m_bLastReversed);
+    }else {
+        m_roadVolumeInfo.isReversed = false;
+    }
     
     /* 处理报警信息 */
     processAlarm();
-
-    /* 更新时间信息 */
-    m_roadVolumeInfo.dateTime = m_currSecondData.startTime;
+    
 
     m_mutexVolumeInfo.unlock();
 }
@@ -573,13 +594,14 @@ void CalculateDBThread::processPhase()
 }
 
 
-/* 生成报警文件路径 */
-std::string CalculateDBThread::generateAlarmFilePath(const AlarmInfo_t& alarmInfo)
+/* 结束所有的报警 */
+void CalculateDBThread::endAllAlarm()
 {
-    std::string filePath = fmt::format("Alarm_{}_{}_{}.wav", 
-        alarmInfo.strCompareItemName, 
-        static_cast<int>(alarmInfo.AlarmType), 
-        alarmInfo.StartTime.toString("yyyyMMdd_hhmmss").toStdString());
-    return filePath;
+    m_roadVolumeInfo.isSilence = false;
+    m_roadVolumeInfo.isOverload = false;
+    m_roadVolumeInfo.isReversed = false;
+
+    processAlarm();
 }
 
+

+ 25 - 11
Server/ThreadCalculate/CalculateDBThread.h

@@ -11,14 +11,17 @@
 
 
 /**
- *  这个线程类进行静音、过载和反相等报警的计算,这个线程和对比项相关,需要对比项中的参数,由对比项线程创建
- *      1、计算静音、过载和反相
- *      2、保存报警结果得出的报警信息,外部获取是实时的报警状态,通过一个中介报警信息解决了报警时间粘连的问题
- *  线程输出结果
- *      1、静音报警信息
- *      2、过载报警信息
- *      3、反相报警信息
- *      4、音量包信息
+    这个线程类进行静音、过载和反相等报警的计算,这个线程和对比项相关,需要对比项中的参数,由对比项线程创建
+        1、计算静音、过载和反相
+        2、保存报警结果得出的报警信息,外部获取是实时的报警状态,通过一个中介报警信息解决了报警时间粘连的问题
+    线程输出结果
+        1、静音报警信息
+        2、过载报警信息
+        3、反相报警信息
+        4、音量包信息
+    检测时间段:
+        1、如果某一项不在检测时间段内,那么这一项不会进行计算,检测结果全部为false
+        2、即使所有的检测项目都不在检测时间段内,这个线程也不能停,因为对比项需要从这里获取音量包信息
  */
 class CalculateDBThread : public BaseCalculateThread
 {
@@ -37,6 +40,11 @@ public:
     /* 获取最新的结果,实时结果 */
     // AlarmInfo_t getAlarm(EAlarmType alarmType);
 
+    /* 设置是否在检测时段内 */
+    void setSilenceInDetectPeriod(bool isInPeriod) { m_isSilenceInDetectPeriod = isInPeriod; }
+    void setOverloadInDetectPeriod(bool isInPeriod) { m_isOverloadInDetectPeriod = isInPeriod; }
+    void setPhaseInDetectPeriod(bool isInPeriod) { m_isPhaseInDetectPeriod = isInPeriod; }
+
 protected:
     /* 线程功能函数 */
     void task() override;
@@ -47,7 +55,7 @@ protected:
 
 private:
     /* 计算静音过载反相 */
-    void calcuDBPhase();
+    void calcuDBData();
     /* 判断是否报警 */
     void processAlarm();
     /* 处理静音报警 */
@@ -57,10 +65,16 @@ private:
     /* 处理反相报警 */
     void processPhase();
 
-    /* 生成报警文件路径 */
-    std::string generateAlarmFilePath(const AlarmInfo_t& alarmInfo);
+    /* 结束所有的报警 */
+    void endAllAlarm();
+
 
 private:
+    /* 静音、过载、反相是否在检测时间段内 */
+    std::atomic_bool m_isSilenceInDetectPeriod = true;  /* 静音检测是否在检测时间段内 */
+    std::atomic_bool m_isOverloadInDetectPeriod = true; /* 过载检测是否在检测时间段内 */
+    std::atomic_bool m_isPhaseInDetectPeriod = true;    /* 反相检测是否在检测时间段内 */
+
     /* 录音通道信息 */
     CompareItemRoadInfo_t  m_roadInfo;                      /* 录音通道编号,带有对比项信息 */
     std::string m_roadName;                                 /* 录音通道名称 */

+ 46 - 2
Server/ThreadCalculate/CompareDoubleThread.cpp

@@ -65,7 +65,21 @@ void CompareDoubleThread::task()
     SPDLOG_LOGGER_INFO(m_logger, " ★ {} 计算一致性对比的线程开始运行  ", m_logBase);
     while(m_isRunning)
     {
-        std::this_thread::sleep_for(std::chrono::milliseconds(10));
+        std::this_thread::sleep_for(std::chrono::milliseconds(20));
+
+        /* 判断是否在检测时间段内 */
+        if(m_isInDetectPeriod.load() == false)
+        {
+            /* 不在检测时间段内,不需要比对,结果一直为一致性 */
+            m_roadResult.isConsistency = true;
+            m_roadResult.isNotConsistencyWarning = false;
+            /* 如果此时还在非一致性报警中,结束报警 */
+            if(m_alarmConsistencyMain.isAlarm || m_alarmConsistencySub.isAlarm)
+            {
+                saveAlarmInfo();
+            }
+            continue;
+        }
 
         /* 使用比对动态库比对一致性 */
         m_pConsistencyCompareThread->compareConsistencyData();
@@ -86,7 +100,8 @@ void CompareDoubleThread::task()
         m_isUpdated1 = false;
         m_isUpdated2 = false;
     }
-
+    /* 结束报警,主要是为了停止报警录音 */
+    endAlarm();
     /* 清理数据 */
     clearData();
     SPDLOG_LOGGER_WARN(m_logger, " ★ {} 计算双通道对比的线程结束 ", m_logBase);
@@ -725,3 +740,32 @@ void CompareDoubleThread::saveAlarmInfo()
     }
 }
 
+/* 结束报警 */
+void CompareDoubleThread::endAlarm()
+{
+    m_roadResult.isConsistency = true;
+
+    /* 这次是一致的,判断之前是否在一致性报警中 */
+    if(m_alarmConsistencyMain.isAlarm || m_alarmConsistencySub.isAlarm)
+    {
+        /* 之前在一致性报警中,这次一致,结束不一致性报警 */
+        m_alarmConsistencyMain.isAlarm = false;
+        m_alarmConsistencySub.isAlarm = false;
+        /* 结束时间向前推1秒 */
+        m_alarmConsistencyMain.EndTime = m_localData1.ringQueue.back()->endTime.addSecs(1);
+        m_alarmConsistencySub.EndTime = m_localData2.ringQueue.back()->endTime.addSecs(1);
+        /* 结束录制报警音频 */
+        m_threadCreateAlarmFile1->stopRecordAlarmFile(m_alarmConsistencyMain);
+        m_threadCreateAlarmFile2->stopRecordAlarmFile(m_alarmConsistencySub);
+        /* 将报警信息写入数据库 */
+        AlarmManager.addAlarmInfo(m_alarmConsistencyMain);
+        AlarmManager.addAlarmInfo(m_alarmConsistencySub);
+        
+        SPDLOG_LOGGER_INFO(m_logger, "{}: 一致性报警结束", m_logBase);
+        /* 清除报警信息 */
+        m_alarmConsistencyMain = AlarmInfo_t();
+        m_alarmConsistencySub = AlarmInfo_t();
+    }
+    
+}
+

+ 8 - 0
Server/ThreadCalculate/CompareDoubleThread.h

@@ -24,6 +24,7 @@ class CreateLongFileThread;
         2、正弦波是用来判断噪音的,不过貌似没用到这个计算结果
         3、一致性检测通过检测是否静音来进行计算的,这里直接获取两个通道的音量值进行对比,
             获取一致性对比结果,再结合动态库检测的一致性进行判断
+        4、调用动态库检测的功能没有再开一个线程,直接在这个线程中进行检测
   
  */
 class CompareDoubleThread : public BaseCalculateThread
@@ -58,6 +59,9 @@ public:
     /* 获取最新的计算结果 */
     bool getlastResult(OneRoadVolume_t& volumeInfo);
 
+    /* 设置是否在检测时间段 */
+    void setInDetectPeriod(bool isInDetectPeriod) { m_isInDetectPeriod = isInDetectPeriod; }
+
 protected:
     /* 线程功能函数 */
     void task() override;
@@ -89,6 +93,8 @@ private:
 
     /* 保存报警信息 */
     void saveAlarmInfo();
+    /* 结束报警 */
+    void endAlarm();
 
 private:
     /* ----------------- 基础成员变量 ------------------ */
@@ -96,6 +102,8 @@ private:
     SoundCardRoadInfo_t m_roadInfo2;                        /* 录音通道2信息 */
     CompareItemRoadInfo_t m_itemRoadInfo1;                  /* 对比项通道1信息,这两个给报警信息使用的 */
     CompareItemRoadInfo_t m_itemRoadInfo2;                  /* 对比项通道2信息 */
+
+    std::atomic_bool m_isInDetectPeriod = true;             /* 是否在检测时段内 */
     
 
     /* ----------------- 生成音量数据的线程 ------------------ */

+ 96 - 27
Server/ThreadCalculate/CompareItemThread.cpp

@@ -246,8 +246,8 @@ bool CompareItemThread::initData()
     createCompareThreads();
 
     /* 获取计算噪音的线程 */
-    removeNoiseDetectThreads(); // 清理之前的噪音检测线程
-    getNoiseDetectThreads();
+    destroyNoiseDetectThreads();
+    createNoiseDetectThreads();
 
     /* 初始化存储结果的数据结构 */
     m_compareResult = CompareResult_t();
@@ -303,7 +303,8 @@ void CompareItemThread::clearData()
     /* 销毁音量报警线程 */
     destroyCalculateDBThreads();
     /* 移除噪音检测线程 */
-    removeNoiseDetectThreads();
+    // removeNoiseDetectThreads();
+    destroyNoiseDetectThreads();
 
     /* 移除使用到的录音通道 */
     for(auto& it : m_threadInfo.compareItemInfo.mapRoad)
@@ -454,44 +455,85 @@ void CompareItemThread::destroyCalculateDBThreads()
     SPDLOG_LOGGER_INFO(m_logger, "{} 音量计算线程销毁完成", m_logBase);
 }
 
-/* 获取噪音检测的线程 */
-bool CompareItemThread::getNoiseDetectThreads()
+/* 创建噪音检测线程 */
+void CompareItemThread::createNoiseDetectThreads()
 {
     for(const auto& road : m_threadInfo.compareItemInfo.mapRoad)
     {
-        NoiseDetectThread* pThread = ThreadMan.getNoiseDetectThread(road.scRoadInfo, m_threadInfo.compareItemInfo.nID);
+        CalculateThreadInfo_t threadInfo;
+        threadInfo.compareItemInfo.mapRoad.clear(); // 清空通道信息
+        threadInfo.compareItemInfo.mapRoad.insert(road.nCompareRoadNum, road); // 添加当前通道
+        threadInfo.threadState = EThreadState::State_Inited; // 初始化线程状态
+        threadInfo.threadType = EThreadType::Type_CalculateDB;
+        NoiseDetectThread* pThread = new NoiseDetectThread(threadInfo);
         if(pThread == nullptr)
         {
-            SPDLOG_LOGGER_ERROR(m_logger, "{} 获取噪音检测线程失败", m_logBase);
-            return false; // 获取线程失败
+            SPDLOG_LOGGER_ERROR(m_logger, "{} 创建噪音检测线程失败", m_logBase);
+            return; // 获取线程失败
         }
-        /* 向噪音检测线程写入对比项通道信息 */
-        pThread->startCompareItemNoiseAlarm(m_threadInfo.compareItemInfo.nID, m_threadInfo.compareItemInfo.strName, road);
         m_mapNoiseDetectThreads.insert({road.nCompareRoadNum, pThread});
     }
-
-    return true;
 }
 
-/* 移除噪音检测的线程 */
-void CompareItemThread::removeNoiseDetectThreads()
+/* 销毁噪音检测线程 */
+void CompareItemThread::destroyNoiseDetectThreads()
 {
     if(m_mapNoiseDetectThreads.size() == 0)
     {
         return; // 没有噪音检测线程
     }
-    SPDLOG_LOGGER_INFO(m_logger, "{} 移除噪音检测线程", m_logBase);
+    SPDLOG_LOGGER_INFO(m_logger, "{} 销毁噪音检测线程", m_logBase);
     for(auto& pair : m_mapNoiseDetectThreads)
     {
         if(pair.second != nullptr)
         {
-            ThreadMan.removeNoiseDetectThread(pair.second->getRoadInfo(), m_threadInfo.compareItemInfo.nID);
+            pair.second->stopThreadBlock(); // 停止线程
+            delete pair.second;             // 删除线程
+            pair.second = nullptr;          // 设置为nullptr
         }
     }
     m_mapNoiseDetectThreads.clear();
-    SPDLOG_LOGGER_INFO(m_logger, "{} 噪音检测线程移除完成", m_logBase);
+    SPDLOG_LOGGER_INFO(m_logger, "{} 噪音检测线程销毁完成", m_logBase);
 }
 
+/* 获取噪音检测的线程 */
+// bool CompareItemThread::getNoiseDetectThreads()
+// {
+//     for(const auto& road : m_threadInfo.compareItemInfo.mapRoad)
+//     {
+//         NoiseDetectThread* pThread = ThreadMan.getNoiseDetectThread(road.scRoadInfo, m_threadInfo.compareItemInfo.nID);
+//         if(pThread == nullptr)
+//         {
+//             SPDLOG_LOGGER_ERROR(m_logger, "{} 获取噪音检测线程失败", m_logBase);
+//             return false; // 获取线程失败
+//         }
+//         /* 向噪音检测线程写入对比项通道信息 */
+//         pThread->startCompareItemNoiseAlarm(m_threadInfo.compareItemInfo.nID, m_threadInfo.compareItemInfo.strName, road);
+//         m_mapNoiseDetectThreads.insert({road.nCompareRoadNum, pThread});
+//     }
+
+//     return true;
+// }
+
+/* 移除噪音检测的线程 */
+// void CompareItemThread::removeNoiseDetectThreads()
+// {
+//     if(m_mapNoiseDetectThreads.size() == 0)
+//     {
+//         return; // 没有噪音检测线程
+//     }
+//     SPDLOG_LOGGER_INFO(m_logger, "{} 移除噪音检测线程", m_logBase);
+//     for(auto& pair : m_mapNoiseDetectThreads)
+//     {
+//         if(pair.second != nullptr)
+//         {
+//             ThreadMan.removeNoiseDetectThread(pair.second->getRoadInfo(), m_threadInfo.compareItemInfo.nID);
+//         }
+//     }
+//     m_mapNoiseDetectThreads.clear();
+//     SPDLOG_LOGGER_INFO(m_logger, "{} 噪音检测线程移除完成", m_logBase);
+// }
+
 
 /**
  * @brief 更新数据
@@ -791,22 +833,49 @@ bool CompareItemThread::checkDetectPeriod()
         }
     }
 
-    /* 判断是否应用于噪音、过载、反相、噪声检测 */
-    if(m_detectPeriod.isApplySlient)
+    /* 应用于对比项检测,对比项不设置日期不会进行检测 */
+    for(auto& pThread : m_mapCompareDoubleThreads)
     {
-
+        pThread.second->setInDetectPeriod(isInDetectPeriod);
     }
-    if(m_detectPeriod.isApplyOverload)
-    {
 
-    }
-    if(m_detectPeriod.isApplyPhase)
+    /* 判断是否应用于静音、过载、反相检测 */
+    for(auto& pThread : m_mapCalculateDBThreads)
     {
-
+        if(m_detectPeriod.isApplySlient)
+        {
+            pThread.second->setSilenceInDetectPeriod(isInDetectPeriod);
+        }else {
+            /* 没有应用于静音检测,就一直检测 */
+            pThread.second->setSilenceInDetectPeriod(true);
+        }
+        if(m_detectPeriod.isApplyOverload)
+        {
+            pThread.second->setOverloadInDetectPeriod(isInDetectPeriod);
+        } else {
+            /* 没有应用于过载检测,就一直检测 */
+            pThread.second->setOverloadInDetectPeriod(true);
+        }
+        if(m_detectPeriod.isApplyPhase)
+        {
+            pThread.second->setPhaseInDetectPeriod(isInDetectPeriod);
+        }else 
+        {
+            /* 没有应用于反相检测,就一直检测 */
+            pThread.second->setPhaseInDetectPeriod(true);
+        }
     }
-    if(m_detectPeriod.isApplyNoise)
+    /* 应用于噪音检测 */
+    for(auto& pThread : m_mapNoiseDetectThreads)
     {
-
+        if(m_detectPeriod.isApplyNoise)
+        {
+            pThread.second->setInDetectPeriod(isInDetectPeriod);
+        }else 
+        {
+            /* 没有应用于噪音检测,就一直检测 */
+            pThread.second->setInDetectPeriod(true);
+        }
     }
 
     return true;

+ 7 - 2
Server/ThreadCalculate/CompareItemThread.h

@@ -81,10 +81,15 @@ private:
     bool createCalculateDBThreads();
     /* 销毁音量计算的线程 */
     void destroyCalculateDBThreads();
+    /* 创建噪音检测线程 */
+    void createNoiseDetectThreads();
+    /* 销毁噪音检测线程 */
+    void destroyNoiseDetectThreads();
+
     /* 获取噪音检测的线程 */
-    bool getNoiseDetectThreads();
+    // bool getNoiseDetectThreads();
     /* 移除噪音检测的线程 */
-    void removeNoiseDetectThreads();
+    // void removeNoiseDetectThreads();
 
 
     /* 更新数据 */

+ 214 - 72
Server/ThreadCalculate/NoiseDetectThread.cpp

@@ -30,39 +30,39 @@ NoiseDetectThread::~NoiseDetectThread()
 }
 
 /* 开启对比项通道的噪音报警功能 */
-void NoiseDetectThread::startCompareItemNoiseAlarm(const int itemID, const QString strName, const CompareItemRoadInfo_t& compareItemRoadInfo)
-{
-    std::lock_guard<std::mutex> lock(m_mutexAlarm);
-    /* 如果已经存在这个对比项的报警信息,就不需要重复添加了 */
-    if(m_mapAlarmInfo.find(itemID) != m_mapAlarmInfo.end())
-    {
-        SPDLOG_LOGGER_INFO(m_logger, "{} 对比项 {} 的噪音报警功能已经开启", m_logBase, strName.toStdString());
-        return;
-    }
-    /* 添加对比项的噪音报警信息 */
-    AlarmInfo_t alarmInfo;
-    alarmInfo.CompareItemID = itemID;
-    alarmInfo.strCompareItemName = strName.toStdString();
-    alarmInfo.isAlarm = false; // 初始状态没有报警
-    alarmInfo.RoadInfo = compareItemRoadInfo; 
-    alarmInfo.AlarmType = EAlarmType::EAT_Noise;
-
-    m_mapAlarmInfo[itemID] = alarmInfo;
-}
+// void NoiseDetectThread::startCompareItemNoiseAlarm(const int itemID, const QString strName, const CompareItemRoadInfo_t& compareItemRoadInfo)
+// {
+//     std::lock_guard<std::mutex> lock(m_mutexAlarm);
+//     /* 如果已经存在这个对比项的报警信息,就不需要重复添加了 */
+//     if(m_mapAlarmInfo.find(itemID) != m_mapAlarmInfo.end())
+//     {
+//         SPDLOG_LOGGER_INFO(m_logger, "{} 对比项 {} 的噪音报警功能已经开启", m_logBase, strName.toStdString());
+//         return;
+//     }
+//     /* 添加对比项的噪音报警信息 */
+//     AlarmInfo_t alarmInfo;
+//     alarmInfo.CompareItemID = itemID;
+//     alarmInfo.strCompareItemName = strName.toStdString();
+//     alarmInfo.isAlarm = false; // 初始状态没有报警
+//     alarmInfo.RoadInfo = compareItemRoadInfo; 
+//     alarmInfo.AlarmType = EAlarmType::EAT_Noise;
+
+//     m_mapAlarmInfo[itemID] = alarmInfo;
+// }
 
 /* 关闭对比项通道的噪音报警功能 */
-void NoiseDetectThread::stopCompareItemNoiseAlarm(const int itemID, const QString strName, const CompareItemRoadInfo_t& compareItemRoadInfo)
-{
-    std::lock_guard<std::mutex> lock(m_mutexAlarm);
-    auto it = m_mapAlarmInfo.find(itemID);
-    if(it != m_mapAlarmInfo.end())
-    {
-        SPDLOG_LOGGER_INFO(m_logger, "{} 对比项 {} 的噪音报警功能已关闭", m_logBase, strName.toStdString());
-        m_mapAlarmInfo.erase(it); // 移除对比项的噪音报警信息
-    }else {
-        SPDLOG_LOGGER_WARN(m_logger, "{} 对比项 {} 的噪音报警功能未开启,无法关闭", m_logBase, strName.toStdString());
-    }
-}
+// void NoiseDetectThread::stopCompareItemNoiseAlarm(const int itemID, const QString strName, const CompareItemRoadInfo_t& compareItemRoadInfo)
+// {
+//     std::lock_guard<std::mutex> lock(m_mutexAlarm);
+//     auto it = m_mapAlarmInfo.find(itemID);
+//     if(it != m_mapAlarmInfo.end())
+//     {
+//         SPDLOG_LOGGER_INFO(m_logger, "{} 对比项 {} 的噪音报警功能已关闭", m_logBase, strName.toStdString());
+//         m_mapAlarmInfo.erase(it); // 移除对比项的噪音报警信息
+//     }else {
+//         SPDLOG_LOGGER_WARN(m_logger, "{} 对比项 {} 的噪音报警功能未开启,无法关闭", m_logBase, strName.toStdString());
+//     }
+// }
 
 
 /* 线程功能函数 */
@@ -81,6 +81,20 @@ void NoiseDetectThread::task()
     {
         std::this_thread::sleep_for(std::chrono::milliseconds(10));
 
+        /* 判断是否还在噪音检测时间段内,如果还在噪音报警中,
+            则继续保存数据 */
+        if(m_isInDetectPeriod.load() == false)
+        {
+            m_currentIsNoise = false;
+            if(m_currentAlarmInfo.isAlarm)
+            {
+                saveResultOnlyOneItem();
+            }else {
+                m_isNoise.store(false);
+                m_isNoiseWarning.store(false);
+            }
+            continue;
+        }
         /*------------------------------------------------------------------------
          * 获取最新的左右声道数据
          *------------------------------------------------------------------------*/
@@ -113,7 +127,8 @@ void NoiseDetectThread::task()
          * 处理结果,写噪音报警信息到数据库(这里不写数据库,只计算结果返回给对比项)
          * 上面那个函数已经把结果保存了
          *------------------------------------------------------------------------*/
-        saveResult();
+        // saveResult();
+        saveResultOnlyOneItem();
 
     }
     clearData(); // 清理数据
@@ -166,8 +181,8 @@ bool NoiseDetectThread::initData()
 /* 清理数据 */
 void NoiseDetectThread::clearData()
 {
-    /* 释放资源 */
-    // signalstats_wrapper::finalize();
+    /* 判断是否还在报警中,如果是,则结束报警 */
+    endAlarm();
 }
 
 /* 调用动态库检测噪音 */
@@ -246,7 +261,111 @@ bool NoiseDetectThread::detectNoise()
 
 
 /* 保存结果 */
-void NoiseDetectThread::saveResult()
+// void NoiseDetectThread::saveResult()
+// {
+//     /* 将当前噪音检测结果保存到环形队列中 */
+//     m_ringQueueIsNoise.push(m_currentIsNoise);
+//     /* 计算出噪音个数和噪音所占百分比 */
+//     const int size = m_ringQueueIsNoise.QueueSize();
+//     int numNoise = 0;           // 噪音的个数
+//     int numCountinueNoise = 0;  // 连续噪音的个数
+//     double percentNoise = 0.0;  // 噪音所占百分比
+//     for(int i = 0; i < size; ++i)
+//     {
+//         if(m_ringQueueIsNoise.at(i))
+//         {
+//             numNoise++;
+//             numCountinueNoise++;
+//         }else {
+//             numCountinueNoise = 0; // 如果不是噪音,连续噪音计数清零
+//         }
+//     }
+//     /* 判断是否是噪音预警 */
+//     if(numCountinueNoise >= m_noiseDetectParam.nNoiseContinueCountIsWarn)
+//     {
+//         m_isNoiseWarning.store(true);
+//     }
+//     percentNoise = numNoise * 100.0 / m_noiseDetectParam.nNoiseDetectContinueCount;
+//     /* 根据噪音所占的百分比判断是否是噪音 */
+//     if(percentNoise >= m_noiseDetectParam.nNoiseContinueCountPercent)
+//     {
+//         m_isNoise.store(true);
+//     }else {
+//         m_isNoise.store(false);
+//     }
+//     // SPDLOG_LOGGER_INFO(m_logger, "{} 当前噪音检测结果: {}, 噪音预警: {}, 连续噪音个数: {}, 噪音所占百分比: {:.2f}%", 
+//     //     m_logBase, m_currentIsNoise, m_isNoiseWarning.load(), numCountinueNoise, percentNoise);
+//     /* 噪音报警信息 */
+//     if(m_isNoise.load())
+//     {
+//         /* 判断上次是否是噪音 */
+//         if(!m_isNoiseLast)
+//         {
+//             /* 开始噪音报警 */
+//             m_isNoiseWarning = true;
+//             /* 通知对比项线程,开始噪音报警 */
+//             std::lock_guard<std::mutex> lock(m_mutexAlarm);
+//             for(auto& pair : m_mapAlarmInfo)
+//             {
+//                 AlarmInfo_t& alarmInfo = pair.second;
+//                 if(!alarmInfo.isAlarm) // 如果没有报警
+//                 {
+//                     alarmInfo.isAlarm = true; // 设置为报警状态
+//                     /* 向前推算噪音开始时间,开始时间需要向前推 n次噪音检测的时间 x 单次噪音检测需要的时间,单位秒 */
+//                     int nNoiseDetectTime = m_noiseDetectParam.nNoiseDetectContinueCount * 1;
+//                     QDateTime startTime = m_leftRightData.startTime;
+//                     startTime = startTime.addSecs(-nNoiseDetectTime);
+//                     alarmInfo.StartTime = startTime;
+//                     SPDLOG_LOGGER_WARN(m_logger, "{} 对比项-{} {} 开始噪音报警, 报警开始时间: {}", m_logBase, alarmInfo.strCompareItemName, 
+//                                                     alarmInfo.RoadInfo.strCompareRoadName.toStdString(), 
+//                                                     startTime.toString("yyyy-MM-dd hh:mm:ss").toStdString());
+//                     /* 这里可以添加通知录制报警文件的线程开始录音 */
+//                     if(m_pThreadCreateAlarm != nullptr)
+//                     {
+//                         m_pThreadCreateAlarm->startRecordAlarmFile(alarmInfo);
+//                     }
+//                 }
+//             }
+//         }
+//     }else 
+//     {
+//         /* 没有噪音,判断是否结束报警 */
+//         if(m_isNoiseLast)
+//         {
+//             /* 停止噪音报警 */
+//             m_isNoiseWarning = false;
+//             /* 通知对比项线程,结束噪音报警 */
+//             std::lock_guard<std::mutex> lock(m_mutexAlarm);
+//             for(auto& pair : m_mapAlarmInfo)
+//             {
+//                 AlarmInfo_t& alarmInfo = pair.second;
+//                 if(alarmInfo.isAlarm) // 如果正在报警
+//                 {
+//                      // 设置为非报警状态
+//                     alarmInfo.isAlarm = false;
+//                     /* 设置结束时间 */
+//                     alarmInfo.EndTime = m_leftRightData.endTime;
+//                     SPDLOG_LOGGER_WARN(m_logger, "{} 对比项-{} {} 结束噪音报警", m_logBase, alarmInfo.strCompareItemName, 
+//                                                     alarmInfo.RoadInfo.strCompareRoadName.toStdString());
+//                     /* 这里可以添加通知录制报警文件的线程停止录音 */
+//                     if(m_pThreadCreateAlarm != nullptr)
+//                     {
+//                         m_pThreadCreateAlarm->stopRecordAlarmFile(alarmInfo);
+//                     }
+//                     /* 写入数据库,并清空时间 */
+//                     AlarmManager.addAlarmInfo(alarmInfo);
+//                     alarmInfo.StartTime = QDateTime();
+//                     alarmInfo.EndTime = QDateTime();               
+//                 }
+//             } 
+//         }
+        
+//     }
+//     m_isNoiseLast = m_isNoise.load(); // 更新这一次的噪音检测结果
+// }
+
+/* 新的保存结果函数,只有一个对比项信息 */
+void NoiseDetectThread::saveResultOnlyOneItem()
 {
     /* 将当前噪音检测结果保存到环形队列中 */
     m_ringQueueIsNoise.push(m_currentIsNoise);
@@ -289,28 +408,28 @@ void NoiseDetectThread::saveResult()
             /* 开始噪音报警 */
             m_isNoiseWarning = true;
             /* 通知对比项线程,开始噪音报警 */
-            std::lock_guard<std::mutex> lock(m_mutexAlarm);
-            for(auto& pair : m_mapAlarmInfo)
+            if(!m_currentAlarmInfo.isAlarm) // 如果没有报警
             {
-                AlarmInfo_t& alarmInfo = pair.second;
-                if(!alarmInfo.isAlarm) // 如果没有报警
+                m_currentAlarmInfo.isAlarm = true; // 设置为报警状态
+                m_currentAlarmInfo.CompareItemID = m_threadInfo.compareItemInfo.nID;
+                m_currentAlarmInfo.strCompareItemName = m_threadInfo.compareItemInfo.strName.toStdString();
+                m_currentAlarmInfo.RoadInfo = m_threadInfo.compareItemInfo.mapRoad.first();
+                m_currentAlarmInfo.AlarmType = EAlarmType::EAT_Noise;
+                /* 向前推算噪音开始时间,开始时间需要向前推 n次噪音检测的时间 x 单次噪音检测需要的时间,单位秒 */
+                int nNoiseDetectTime = m_noiseDetectParam.nNoiseDetectContinueCount * 1;
+                QDateTime startTime = m_leftRightData.startTime;
+                startTime = startTime.addSecs(-nNoiseDetectTime);
+                m_currentAlarmInfo.StartTime = startTime;
+                SPDLOG_LOGGER_WARN(m_logger, "{} 对比项-{} {} 开始噪音报警, 报警开始时间: {}", m_logBase, m_currentAlarmInfo.strCompareItemName, 
+                                                m_currentAlarmInfo.RoadInfo.strCompareRoadName.toStdString(), 
+                                                startTime.toString("yyyy-MM-dd hh:mm:ss").toStdString());
+                /* 这里可以添加通知录制报警文件的线程开始录音 */
+                if(m_pThreadCreateAlarm != nullptr)
                 {
-                    alarmInfo.isAlarm = true; // 设置为报警状态
-                    /* 向前推算噪音开始时间,开始时间需要向前推 n次噪音检测的时间 x 单次噪音检测需要的时间,单位秒 */
-                    int nNoiseDetectTime = m_noiseDetectParam.nNoiseDetectContinueCount * 1;
-                    QDateTime startTime = m_leftRightData.startTime;
-                    startTime = startTime.addSecs(-nNoiseDetectTime);
-                    alarmInfo.StartTime = startTime;
-                    SPDLOG_LOGGER_WARN(m_logger, "{} 对比项-{} {} 开始噪音报警, 报警开始时间: {}", m_logBase, alarmInfo.strCompareItemName, 
-                                                    alarmInfo.RoadInfo.strCompareRoadName.toStdString(), 
-                                                    startTime.toString("yyyy-MM-dd hh:mm:ss").toStdString());
-                    /* 这里可以添加通知录制报警文件的线程开始录音 */
-                    if(m_pThreadCreateAlarm != nullptr)
-                    {
-                        m_pThreadCreateAlarm->startRecordAlarmFile(alarmInfo);
-                    }
+                    m_pThreadCreateAlarm->startRecordAlarmFile(m_currentAlarmInfo);
                 }
             }
+            
         }
     }else 
     {
@@ -321,31 +440,54 @@ void NoiseDetectThread::saveResult()
             m_isNoiseWarning = false;
             /* 通知对比项线程,结束噪音报警 */
             std::lock_guard<std::mutex> lock(m_mutexAlarm);
-            for(auto& pair : m_mapAlarmInfo)
+
+            if(m_currentAlarmInfo.isAlarm) // 如果正在报警
             {
-                AlarmInfo_t& alarmInfo = pair.second;
-                if(alarmInfo.isAlarm) // 如果正在报警
+                 // 设置为非报警状态
+                m_currentAlarmInfo.isAlarm = false;
+                /* 设置结束时间 */
+                m_currentAlarmInfo.EndTime = m_leftRightData.endTime;
+                SPDLOG_LOGGER_WARN(m_logger, "{} 对比项-{} {} 结束噪音报警", m_logBase, m_currentAlarmInfo.strCompareItemName, 
+                                                m_currentAlarmInfo.RoadInfo.strCompareRoadName.toStdString());
+                /* 这里可以添加通知录制报警文件的线程停止录音 */
+                if(m_pThreadCreateAlarm != nullptr)
                 {
-                     // 设置为非报警状态
-                    alarmInfo.isAlarm = false;
-                    /* 设置结束时间 */
-                    alarmInfo.EndTime = m_leftRightData.endTime;
-                    SPDLOG_LOGGER_WARN(m_logger, "{} 对比项-{} {} 结束噪音报警", m_logBase, alarmInfo.strCompareItemName, 
-                                                    alarmInfo.RoadInfo.strCompareRoadName.toStdString());
-                    /* 这里可以添加通知录制报警文件的线程停止录音 */
-                    if(m_pThreadCreateAlarm != nullptr)
-                    {
-                        m_pThreadCreateAlarm->stopRecordAlarmFile(alarmInfo);
-                    }
-                    /* 写入数据库,并清空时间 */
-                    AlarmManager.addAlarmInfo(alarmInfo);
-                    alarmInfo.StartTime = QDateTime();
-                    alarmInfo.EndTime = QDateTime();               
+                    m_pThreadCreateAlarm->stopRecordAlarmFile(m_currentAlarmInfo);
                 }
-            } 
+                /* 写入数据库,并清空时间 */
+                AlarmManager.addAlarmInfo(m_currentAlarmInfo);
+                m_currentAlarmInfo = AlarmInfo_t(); // 清空当前报警信息         
+            }
+            
         }
         
     }
     m_isNoiseLast = m_isNoise.load(); // 更新这一次的噪音检测结果
 }
 
+/* 结束报警 */
+void NoiseDetectThread::endAlarm()
+{
+    if(m_currentAlarmInfo.isAlarm) // 如果正在报警
+    {
+         // 设置为非报警状态
+        m_currentAlarmInfo.isAlarm = false;
+        /* 设置结束时间 */
+        m_currentAlarmInfo.EndTime = m_leftRightData.endTime;
+        SPDLOG_LOGGER_WARN(m_logger, "{} 对比项-{} {} 结束噪音报警", m_logBase, m_currentAlarmInfo.strCompareItemName, 
+                                        m_currentAlarmInfo.RoadInfo.strCompareRoadName.toStdString());
+        /* 这里可以添加通知录制报警文件的线程停止录音 */
+        if(m_pThreadCreateAlarm != nullptr)
+        {
+            m_pThreadCreateAlarm->stopRecordAlarmFile(m_currentAlarmInfo);
+        }
+        /* 写入数据库,并清空时间 */
+        AlarmManager.addAlarmInfo(m_currentAlarmInfo);
+        m_currentAlarmInfo = AlarmInfo_t(); // 清空当前报警信息         
+    }
+    m_isNoiseWarning.store(false);
+    m_isNoise.store(false);
+    m_isNoiseLast = false;
+    m_currentIsNoise = false;
+}
+

+ 20 - 6
Server/ThreadCalculate/NoiseDetectThread.h

@@ -17,6 +17,10 @@ class CreateLongFileThread ;
         2、噪音检测线程参数和对比项无关,是公共的参数,这里没有对比项信息
         3、因为报警信息需要有对比项信息,所以这里有个map,保存对比项传入的信息,根据对比项信息
            开启报警录制,如果这个通道被多个对比项使用,可能会同时录制多个报警文件。
+        
+        上面说明作废,现在是由对比项线程来开启噪音检测线程,因为报警、录制报警文件,检测时段和对比项信息绑定太深了,
+        所以,这个线程所有权归到对比项线程中,因为噪音检测动态库检测速度很快,即使同一个通道多次开启噪音检测线程,
+        也不会有太大影响,噪音检测线程会根据对比项,已有的函数没有删除,依旧保留
     
     噪音判断逻辑
         1、每次检测噪音时,都会检测左右声道的噪音,如果有一个声道有噪音,就认为是噪音
@@ -38,10 +42,15 @@ public:
     /* 获取是否噪音预警 */
     bool isNoiseWarning() const { return m_isNoiseWarning.load(); }
 
+    /* 设置是否在检测时间段内 */
+    void setInDetectPeriod(bool isInDetectPeriod) { m_isInDetectPeriod.store(isInDetectPeriod); }
+
+private:
+    /* 这两个函数私有化,不再使用 */
     /* 开启对比项通道的噪音报警功能 */
-    void startCompareItemNoiseAlarm(const int itemID, const QString strName, const CompareItemRoadInfo_t& compareItemRoadInfo);
+    // void startCompareItemNoiseAlarm(const int itemID, const QString strName, const CompareItemRoadInfo_t& compareItemRoadInfo);
     /* 关闭对比项通道的噪音报警功能 */
-    void stopCompareItemNoiseAlarm(const int itemID, const QString strName, const CompareItemRoadInfo_t& compareItemRoadInfo);
+    // void stopCompareItemNoiseAlarm(const int itemID, const QString strName, const CompareItemRoadInfo_t& compareItemRoadInfo);
 
 protected:
     /* 线程功能函数 */
@@ -54,15 +63,19 @@ protected:
 private:
     /* 调用动态库检测噪音 */
     bool detectNoise();
-    /* 保存结果 */
-    void saveResult();
-
+    /* 保存结果,不再使用 */
+    // void saveResult();
+    /* 新的保存结果函数,只有一个对比项信息 */
+    void saveResultOnlyOneItem();
+    /* 结束报警 */
+    void endAlarm();
 
 private:
     SoundCardRoadInfo_t m_roadInfo;                 /* 录音通道编号 */
     std::string m_roadName;                         /* 录音通道名称 */
     CreateWAVThread* m_pThreadWav = nullptr;        /* WAV小文件生成线程指针 */
     CreateLongFileThread * m_pThreadCreateAlarm = nullptr; /* 生成报警文件的线程 */
+    std::atomic_bool m_isInDetectPeriod = true;     /* 是否在检测时间段内 */
 
     AudioLeftRightData m_leftRightData;             /* 左右声道数据 */
 
@@ -88,8 +101,9 @@ private:
 
     /* ------------------------------------ 报警相关变量 ------------------------------------ */
     std::mutex m_mutexAlarm;                    /* 报警信息互斥锁 */
-    std::map<int, AlarmInfo_t> m_mapAlarmInfo;  /* 报警信息,key是对比项ID */
+    // std::map<int, AlarmInfo_t> m_mapAlarmInfo;  /* 报警信息,key是对比项ID */
     RingQueueManualMutex<bool> m_ringQueueIsNoise; /* 噪音检测结果环形队列,保存最近的噪音检测结果 */
+    AlarmInfo_t m_currentAlarmInfo;             /* 当前报警信息 */
 };
 
 

+ 181 - 46
Server/ThreadManager/ThreadCompareItemManager.cpp

@@ -4,7 +4,9 @@
 #include "SystemConfig.h"
 #include "CompareItemThread.h"
 #include "ThreadPool.h"
-#include "OneThread.h"
+#include "FromMQTT.h"
+#include "commonDefine.h"
+
 
 
 /* 给对比项套一层壳,这个函数就是新的线程,在里面new出新的对比项实例,防止Qt报线程归属权错误
@@ -29,8 +31,6 @@ void ThreadCompareItemManager::thread_compareItem(CalculateThreadInfo_t threadIn
 ThreadCompareItemManager::ThreadCompareItemManager()
 {
     
-    
-    
 }
 
 ThreadCompareItemManager::~ThreadCompareItemManager()
@@ -47,6 +47,17 @@ void ThreadCompareItemManager::thread_CompareItemManager()
         fmt::print("ThreadCompareItemManager: CompareItemManager Logger not found.\n");
         return;
     }
+
+    /* 创建定时器和事件循环 */
+    m_pEventLoop = new QEventLoop();
+    m_pTimer = new QTimer();
+
+    // std::function<void()> task = std::bind(&ThreadCompareItemManager::do_task, this);
+
+    // m_pTimer->setInterval(10000);
+    m_pTimer->setTimerType(Qt::PreciseTimer);
+    m_pTimer->setSingleShot(false); // 设置为非单次定时器
+    connect(m_pTimer, &QTimer::timeout, this, &ThreadCompareItemManager::do_task, Qt::DirectConnection);
     
     /* 初始化webapi */
     m_webAPIUrl = GInfo.webAPIUrl();
@@ -57,32 +68,17 @@ void ThreadCompareItemManager::thread_CompareItemManager()
         SPDLOG_LOGGER_ERROR(m_logger, "ThreadCompareItemManager: 初始化WebAPI失败");
         return;
     }
+    /* 获取MQTT发布订阅 */
+    m_pubTopic = GInfo.mqttPubTopicCompareItem();
 
-    /* 创建一些变量 */
-    int threadSleepTime = 2; // 线程休眠时间,单位秒
 
     /* 获取基础配置,目前只获取一次 */
     updateBaseSettings();
 
     SPDLOG_LOGGER_INFO(m_logger, "开启对比项管理线程");
-    while(true)
-    {
-        std::this_thread::sleep_for(std::chrono::seconds(threadSleepTime));
-        if(threadSleepTime < 10)
-        {
-            /* 线程睡眠时间恢复为10秒 */
-            threadSleepTime = 10;
-        }
-        /* ------------------------------------------------------------------
-         * 处理对比项信息
-         * ------------------------------------------------------------------ */
-        processCompareItemInfo();
-        
-        /* ------------------------------ 更新检测时段 ------------------------------ */
 
-
-
-    }
+    m_pTimer->start(1000);
+    m_pEventLoop->exec();
 
     SPDLOG_LOGGER_INFO(m_logger, "ThreadCompareItemManager: 线程结束");
 
@@ -132,6 +128,40 @@ SoundCardRoadInfo_t ThreadCompareItemManager::getSoundCardRoadInfo(int compareIt
     return roadInfo;
 }
 
+/* 任务函数 */
+void ThreadCompareItemManager::do_task()
+{
+    // SPDLOG_LOGGER_ERROR(m_logger, "ThreadCompareItemManager: do_task() 函数被调用");
+    /* 如果定时间隔小于10秒,则设置成10秒,一开始小是为了线程开启后立马执行一次 */
+    if(m_pTimer->interval() < 10000)
+    {
+        // m_pTimer->stop();
+        m_pTimer->setInterval(10000);
+        // m_pTimer->start();
+    }
+    if(m_pFromMQTT == nullptr)
+    {
+        /* 初始化MQTT */
+        initMQTT();
+    }
+    // SPDLOG_LOGGER_WARN(m_logger, "定时器是否在运行: {}, 触发间隔: {} ms", m_pTimer->isActive(), m_pTimer->interval());
+    /* ------------------------------------------------------------------
+     * 处理对比项信息
+     * ------------------------------------------------------------------ */
+    processCompareItemInfo();
+    
+    /* ------------------------------------------------------------------
+     * 更新检测时段
+     * ------------------------------------------------------------------ */
+    processDetectPeriodInfo();
+
+    /* ------------------------------------------------------------------
+     * 更新对比项信息到MQTT
+     * ------------------------------------------------------------------ */
+    updateCompareItemInfoToMQTT();
+    // SPDLOG_LOGGER_WARN(m_logger, "ThreadCompareItemManager: do_task() 函数执行完毕");
+}
+
 /* 更新基础设置信息,如数据库设置,噪音参数等 */
 bool ThreadCompareItemManager::updateBaseSettings()
 {
@@ -161,40 +191,43 @@ bool ThreadCompareItemManager::updateBaseSettings()
 void ThreadCompareItemManager::processCompareItemInfo()
 {
     /* 获取对比项信息 */
-        if(!m_fromWebAPI.getCompareItemInfo(m_listNewItems))
-        {
-            SPDLOG_LOGGER_DEBUG(m_logger, "ThreadCompareItemManager: 获取对比项失败");
-            return;;
-        }
-        
-        checkCompareItemInfo(m_listCreateItems, m_listUpdateItems, m_listDeleteItems);
+    QList<CompareItemInfo_t> listNewItems;
+    if(!m_fromWebAPI.getCompareItemInfo(listNewItems))
+    {
+        SPDLOG_LOGGER_DEBUG(m_logger, "ThreadCompareItemManager: 获取对比项失败");
+        return;
+    }
+    
+    checkCompareItemInfo(listNewItems, m_listCreateItems, m_listUpdateItems, m_listDeleteItems);
 
-        SPDLOG_LOGGER_DEBUG(m_logger, "要退出的对比项个数: {}, 要更新的对比项个数: {}, 要创建的对比项个数: {}",
-            m_listDeleteItems.size(), m_listUpdateItems.size(), m_listCreateItems.size());
+    SPDLOG_LOGGER_DEBUG(m_logger, "要退出的对比项个数: {}, 要更新的对比项个数: {}, 要创建的对比项个数: {}",
+        m_listDeleteItems.size(), m_listUpdateItems.size(), m_listCreateItems.size());
 
-        /* 先删除已消失的对比项信息 */
-        processDeleteCompareItemThreads(m_listDeleteItems);
-        /* 更新需要更新的线程 */
-        updateRunningThreads(m_listUpdateItems);
-        /* 再创建新的对比项线程 */
-        createNewCompareItemThreads(m_listCreateItems);
+    /* 先删除已消失的对比项信息 */
+    processDeleteCompareItemThreads(m_listDeleteItems);
+    /* 更新需要更新的线程 */
+    updateRunningThreads(m_listUpdateItems);
+    /* 再创建新的对比项线程 */
+    createNewCompareItemThreads(m_listCreateItems);
 }
 
 
 /**
- * @brief 处理对比项信息,新获取的和已有的对比
+ * @brief 处理对比项信息,新获取的和已有的对比,会在这里更新 m_mapNowCompareItem 内容
  * 
  * @param createList 创建列表
  * @param updateList 更新列表,根据对比项ID进行更新信息
  * @param deleteList 删除列表
  */
-void ThreadCompareItemManager::checkCompareItemInfo(QList<CompareItemInfo_t>& createList, QList<CompareItemInfo_t>& updateList, QList<int>& deleteList)
+void ThreadCompareItemManager::checkCompareItemInfo(QList<CompareItemInfo_t>& newList, QList<CompareItemInfo_t>& createList, QList<CompareItemInfo_t>& updateList, QList<int>& deleteList)
 {
     createList.clear();
     updateList.clear();
     deleteList.clear();
 
-    QMap<int, CompareItemInfo_t> mapNowItems;
+    m_mapNowCompareItem.clear();
+
+    // QMap<int, CompareItemInfo_t> mapNowItems;
     /* 先从对比项线程中获取对比项信息 */
     for(auto it = m_mapThreads.begin(); it != m_mapThreads.end(); ++it)
     {
@@ -206,20 +239,20 @@ void ThreadCompareItemManager::checkCompareItemInfo(QList<CompareItemInfo_t>& cr
         
         /* 获取对比项信息 */
         CompareItemInfo_t itemInfo = pThread->getThreadInfo().compareItemInfo;
-        mapNowItems.insert(itemInfo.nID, itemInfo);
+        m_mapNowCompareItem.insert(itemInfo.nID, itemInfo);
     }
 
     /* 遍历新获取的对比项信息,找出需要新增的对比项和需要更新的对比项 */
-    for(const CompareItemInfo_t& item : m_listNewItems)
+    for(const CompareItemInfo_t& item : newList)
     {
-        if(!mapNowItems.contains(item.nID))
+        if(!m_mapNowCompareItem.contains(item.nID))
         {
             /* 新对比项,添加到创建列表 */
             createList.append(item);
         } else
         {
             /* 已有对比项,检查是否需要更新 */
-            const CompareItemInfo_t& existingItem = mapNowItems.value(item.nID);
+            const CompareItemInfo_t& existingItem = m_mapNowCompareItem.value(item.nID);
             /* 先对比基础信息 */
             if(!existingItem.isEqualBase(item))
             {
@@ -237,10 +270,10 @@ void ThreadCompareItemManager::checkCompareItemInfo(QList<CompareItemInfo_t>& cr
         }
     }
     /* 遍历当前对比项信息,找出需要删除的对比项 */
-    for(auto it : mapNowItems)
+    for(auto it : m_mapNowCompareItem)
     {
         bool isFound = false;
-        for(const CompareItemInfo_t& newItem : m_listNewItems)
+        for(const CompareItemInfo_t& newItem : newList)
         {
             if(it.nID == newItem.nID)
             {
@@ -380,6 +413,22 @@ void ThreadCompareItemManager::processDetectPeriodInfo()
 
     QMap<int, DetectPeriodConfig_t> mapUpdateDetectConfig;
     checkDetectPeriodInfo(mapNewDetectConfig, mapUpdateDetectConfig);
+
+    /* 更新检测时段 */
+    for(const auto& it : mapUpdateDetectConfig)
+    {
+        auto threadIt = m_mapThreads.find(it.nID);
+        if(threadIt != m_mapThreads.end())
+        {
+            /* 找到对应的对比项线程,更新检测时段 */
+            CompareItemThread* pThread = dynamic_cast<CompareItemThread*>(threadIt.value());
+            if(pThread != nullptr)
+            {
+                pThread->setDetectPeriod(it);
+                SPDLOG_LOGGER_TRACE(m_logger, "更新对比项 {} 的检测时段", pThread->getThreadInfo().compareItemInfo.strName.toStdString());
+            }
+        }
+    }
 }
 
 /* 检查获取出更新的对比项信息 */
@@ -409,4 +458,90 @@ void ThreadCompareItemManager::checkDetectPeriodInfo(QMap<int, DetectPeriodConfi
     }
 }
 
+/* 更新对比项信息到MQTT */
+void ThreadCompareItemManager::updateCompareItemInfoToMQTT()
+{
+    /* 生成发送的json文件 */
+    nJson jsonArray = nJson::array();
+    for(const auto& it : m_mapNowCompareItem)
+    {
+        nJson jsonItem;
+        /* 对比项ID */
+        jsonItem["compareItem_id"] = it.nID;
+        /* 对比项名称 */
+        jsonItem["compareItem_name"] = it.strName.toStdString();
+        for(const auto& road : it.mapRoad)
+        {
+            nJson jsonRoad;
+            /* 对比项通道编号和名称 */
+            jsonRoad["road_num"] = road.nCompareRoadNum;
+            jsonRoad["road_name"] = road.strCompareRoadName.toStdString();
+            /* 通道使用的声卡编号 */
+            jsonRoad["sound_card_num"] = road.scRoadInfo.nSoundCardNum;
+            jsonRoad["sound_card_road_num"] = road.scRoadInfo.roadInfo.nRoadNum;
+
+            jsonRoad["compareItem_roads"].push_back(jsonRoad);
+        }
+        /* 静音条件 */
+        jsonItem["silence_switch"] = it.paramMute.isEnable;
+        jsonItem["silence_threshold"] = it.paramMute.threshold.nThreshold;
+        jsonItem["silence_duration"] = it.paramMute.nLen;
+        jsonItem["silence_sensitivity"] = it.paramMute.nSensitivity;
+        /* 过载条件 */
+        jsonItem["overload_switch"] = it.paramOverload.isEnable;
+        jsonItem["overload_threshold"] = it.paramOverload.threshold.nThreshold;
+        jsonItem["overload_duration"] = it.paramOverload.nLen;
+        jsonItem["overload_sensitivity"] = it.paramOverload.nSensitivity;
+        /* 反相条件 */
+        jsonItem["reverse_switch"] = it.paramPhase.isEnable;
+        jsonItem["reverse_threshold"] = it.paramPhase.threshold.dThreshold;
+        jsonItem["reverse_duration"] = it.paramPhase.nLen;
+        jsonItem["reverse_sensitivity"] = it.paramPhase.nSensitivity;
+
+        jsonArray.push_back(jsonItem);
+    }
+
+    /* 发送到MQTT */
+    if(m_pFromMQTT->connectState() == QMQTT::ConnectionState::STATE_CONNECTED)
+    {
+        QByteArray jsonData = QByteArray::fromStdString(jsonArray.dump());
+        if(!m_pFromMQTT->sendMessage(m_pubTopic, jsonData, 0, true))
+        {
+            SPDLOG_LOGGER_WARN(m_logger, "ThreadCompareItemManager: 发送对比项信息到MQTT失败");
+        }else
+        {
+            SPDLOG_LOGGER_TRACE(m_logger, "ThreadCompareItemManager: 发送对比项信息到MQTT成功");
+        }
+    } else
+    {
+        SPDLOG_LOGGER_WARN(m_logger, "m_pFromMQTT 未连接到服务器,无法发送");
+    }
+}
+
+/* 初始化MQTT */
+void ThreadCompareItemManager::initMQTT()
+{
+    if(m_pFromMQTT == nullptr)
+    {
+        m_pFromMQTT = new FromMQTT();
+        if(m_pFromMQTT == nullptr)
+        {
+            SPDLOG_LOGGER_ERROR(m_logger, "创建MQTT对象失败");
+            return;
+        }
+    }
+    /* 登陆MQTT */
+    m_pFromMQTT->setIPAndPort(GInfo.mqttIP(), GInfo.mqttPort());
+    // m_pFromMQTT->addSubcribe("LH_WEBINFO");
+    m_pFromMQTT->setAutoReconnect(true);
+    m_pFromMQTT->connectToServer();
+
+    // connect(m_pFromMQTT, &FromMQTT::signal_recvMessage, [this](const QMQTT::Message& message) {
+    //     SPDLOG_LOGGER_WARN(m_logger, "--------------------- 接收到MQTT消息: {}", message.topic().toStdString());
+    //     SPDLOG_LOGGER_WARN(m_logger, "消息内容: {}", message.payload().toStdString());
+    // });
+
+    SPDLOG_LOGGER_INFO(m_logger, "☆ 连接MQTT服务器: {}:{}, 对比项信息订阅主题: {}", GInfo.mqttIP().toStdString(), GInfo.mqttPort(), m_pubTopic.toStdString());
+}
+
 

+ 28 - 3
Server/ThreadManager/ThreadCompareItemManager.h

@@ -6,6 +6,11 @@
 #include "FromWebAPI.h"
 #include "CompareItemThread.h"
 
+#include <QObject>
+#include <QEventLoop>
+#include <QTimer>
+
+class FromMQTT;
 
 /**
     对比项管理线程
@@ -18,8 +23,10 @@
 
 
 #define CompareItemManager ThreadCompareItemManager::instance()
-class ThreadCompareItemManager
+class ThreadCompareItemManager : public QObject
 {
+    Q_OBJECT
+
     ThreadCompareItemManager();
     ThreadCompareItemManager(const ThreadCompareItemManager&) = delete;
     ThreadCompareItemManager& operator=(const ThreadCompareItemManager&) = delete;
@@ -43,6 +50,10 @@ public:
         在函数中将对比项实例插入到线程管理器中 */
     static void thread_compareItem(CalculateThreadInfo_t threadInfo);
 
+private slots:
+    /* 定时器触发,处理对比项信息 */
+    void do_task();
+
 private:
     /* 更新基础设置信息,如数据库设置,噪音参数等 */
     bool updateBaseSettings();
@@ -51,7 +62,8 @@ private:
     /* 更新对比项信息 */
     void processCompareItemInfo();
     /* 处理对比项信息,新获取的和已有的对比 */
-    void checkCompareItemInfo(QList<CompareItemInfo_t>& createList,
+    void checkCompareItemInfo(  QList<CompareItemInfo_t>& newList,
+                                QList<CompareItemInfo_t>& createList,
                                 QList<CompareItemInfo_t>& updateList,
                                 QList<int>& deleteList);
 
@@ -68,8 +80,20 @@ private:
     /* 检查获取出更新的对比项信息 */
     void checkDetectPeriodInfo(QMap<int, DetectPeriodConfig_t> newDetectInfo, QMap<int, DetectPeriodConfig_t>& updateList);
 
+    /* ---------------------- 向MQTT发送对比项信息 ---------------------- */
+    /* 更新对比项信息到MQTT */
+    void updateCompareItemInfoToMQTT();
+    /* 初始化MQTT */
+    void initMQTT();
+
 private:
     std::shared_ptr<spdlog::logger> m_logger = nullptr;
+    QEventLoop* m_pEventLoop = nullptr; // 事件循环
+    QTimer* m_pTimer = nullptr;         // 定时器
+    FromMQTT* m_pFromMQTT = nullptr;    // MQTT处理发送类
+    QString m_pubTopic;                 /* 发布的主题 */
+
+
     FromWebAPI m_fromWebAPI;                /* WebAPI处理类 */
     QString m_webAPIUrl;                    /* WebAPI地址 */
     QString m_webAPIID;                     /* WebAPI ID */
@@ -77,7 +101,8 @@ private:
 
     /* ---------------------- 对比项信息 ---------------------- */
     std::mutex m_mutexCompareItemThreads;       /* 对比项线程的互斥锁 */
-    QList<CompareItemInfo_t> m_listNewItems;    /* 对比项列表,从数据库获取到的新的列表 */
+    // QList<CompareItemInfo_t> m_listNewItems;    /* 对比项列表,从数据库获取到的新的列表 */
+    QMap<int, CompareItemInfo_t> m_mapNowCompareItem; /* 当前的对比项信息,在检查是否有对比项更新的时候更新该值 */
     QMap<int, CompareItemThread*> m_mapThreads; /* 对比项线程列表,key是对比项ID,value是对应的线程指针 */
 
     /* 临时变量 */