#include "stdafx.h" #include "ResistAlarm.h" #include "MonitorObject.h" #include "Device.h" #include #include #include #include #include #include #include #include "AppService.h" #include CResistAlarm::CResistAlarm() { } CResistAlarm::~CResistAlarm() { } CResistAlarmMng::CResistAlarmMng() { } CResistAlarmMng::~CResistAlarmMng() { } BOOL CResistAlarmMng::Start() { LoadAlarmSet(); if (FALSE == LoadAlarmID()) return FALSE; LoadUnAck(); //无须开启线程检测 /* m_bWork = true; m_pThreadAlarmSet = new thread(CResistAlarmMng::ThreadProcAlarmSet, (DWORD_PTR)this); if (m_pThreadAlarmSet == nullptr) return FALSE; m_pThreadDevice = new thread(CResistAlarmMng::ThreadProcDevice, (DWORD_PTR)this); if (m_pThreadDevice == nullptr) return FALSE; */ return TRUE; } void CResistAlarmMng::Stop() { m_bWork = false; if (m_pThreadAlarmSet) { m_pThreadAlarmSet->join(); delete m_pThreadAlarmSet; m_pThreadAlarmSet = nullptr; } for (auto& it : m_alarm_set) { if (it.second) { if (it.second->type == eZL_ALARMTYPE::MAX_OVER_LIMIT) { delete (MAX_OVER_LIMIT_INFO*)it.second; it.second = nullptr; } else if (it.second->type == eZL_ALARMTYPE::FRICTION_OVER_LIMIT) { delete (FRICTION_OVER_LIMIT_INFO*)it.second; it.second = nullptr; } else { assert(0); } } } m_alarm_set.clear(); for (auto& it : m_lstUnConfirmAlarm) delete it; m_lstUnConfirmAlarm.clear(); } //BASE_INFO* CResistAlarmMng::Find(string momp, uint8_t no, uint8_t type) //{ // stringstream ss; // ss << momp << '.' << to_string(no) << '.' << to_string(type); // auto it = m_alarm_set.find(ss.str()); // if (it != m_alarm_set.end()) // { // return it->second; // } // return nullptr; //} BASE_INFO* CResistAlarmMng::Find(string mo, string mp, uint8_t no, eZL_ALARMTYPE type) { stringstream ss; ss << mo << '.' << mp << '.' << to_string(no) << '.' << to_string((uint8_t)type); auto it = m_alarm_set.find(ss.str()); if (it != m_alarm_set.end()) { return it->second; } return nullptr; } //bool CResistAlarmMng::Insert(const string& momp, uint8_t no, uint8_t type, BASE_INFO* info) //{ // auto it = m_alarm_set.insert(make_pair(momp + '.' + to_string(no) + '.' + to_string(type), info)); // return it.second; //} bool CResistAlarmMng::Insert(string mo, string mp, uint8_t no, uint8_t type, BASE_INFO* info) { auto it = m_alarm_set.insert(make_pair(mo + '.' + mp + '.' + to_string(no) + '.' + to_string(type), info)); return it.second; } //bool CResistAlarmMng::ConfirmAlarm(string mo, string mp, uint8_t no, uint8_t type, const SYSTEMTIME& st) //{ // lock_guard lock(m_mtxAlarm); // auto it = m_lstUnConfirmAlarm.begin(); // for (it; it != m_lstUnConfirmAlarm.end(); ++it) // { // const auto& pInfo = *it; // if (pInfo->mo.compare(mo) == 0 && pInfo->mp.compare(mp) == 0 && pInfo->no == no && pInfo->type == type && pInfo->time.wYear == st.wYear && // pInfo->time.wMonth == st.wMonth && pInfo->time.wDay == st.wDay && pInfo->time.wHour == st.wHour && pInfo->time.wMinute == st.wMinute) // { // m_lstUnConfirmAlarm.erase(it); // return true; // } // } // return false; //} bool CResistAlarmMng::AckAlarm(int alarm_id, string& name, CTime& time) { lock_guard lock(m_mtxAlarm); auto it = m_lstUnConfirmAlarm.begin(); for (it; it != m_lstUnConfirmAlarm.end(); ++it) { auto& pInfo = *it; if (alarm_id == pInfo->id) { pInfo->ack_result = 1; pInfo->ack_name = name; pInfo->ack_time = time; return true; } } return false; } bool CResistAlarmMng::HandleAlarm(int alarm_id) { lock_guard lock(m_mtxAlarm); auto it = m_lstUnConfirmAlarm.begin(); for (it; it != m_lstUnConfirmAlarm.end(); ++it) { const auto& pInfo = *it; if (pInfo->id == alarm_id) { m_lstUnConfirmAlarm.erase(it); return true; } } return false; } void CResistAlarmMng::GeneralAlarm(string mo, string mp, uint8_t no, eZL_ALARMTYPE type, uint8_t level, SYSTEMTIME& tAlarm) { ALARM_INFO* pAlarmInfo = nullptr; bool bNew = false; { std::lock_guard lock(m_mtxAlarm); for (const auto& alarm : m_lstUnConfirmAlarm) { if (alarm->type == eZL_ALARMTYPE::SENSOR_ABNORMAL && alarm->mo.compare(mo) == 0 && alarm->mp.compare(mp) == 0 && no == alarm->no/* && ctAlarmTime - CTime(alarm->time) < cts*/) //跟上次报警时间超过1小时,则算新报警 { pAlarmInfo = alarm; break; } } } if (pAlarmInfo == nullptr) { bNew = true; pAlarmInfo = new ALARM_INFO; pAlarmInfo->id = ++m_nAlarmID; pAlarmInfo->level = 1; pAlarmInfo->mo = mo; pAlarmInfo->mp = mp; pAlarmInfo->no = no; pAlarmInfo->time = tAlarm; //pAlarmInfo->time.wMilliseconds = alarm_time % 1000; pAlarmInfo->type = eZL_ALARMTYPE::SENSOR_ABNORMAL; pAlarmInfo->val = 0; char szInfo[200]; sprintf_s(szInfo, sizeof(szInfo), "传感器异常时间:%04d-%02d-%02d %02d:%02d:%02d", tAlarm.wYear, tAlarm.wMonth, tAlarm.wDay, tAlarm.wHour, tAlarm.wMinute, tAlarm.wSecond); pAlarmInfo->desc = szInfo; lock_guard lock(m_mtxAlarm); m_lstUnConfirmAlarm.push_back(pAlarmInfo); } //send if (bNew) //不再推送 { rapidjson::StringBuffer buffer; auto ret = AlarmInfo2Pack(pAlarmInfo, buffer); const char* output = buffer.GetString(); //CAppService::Instance()->GetLwsServer()->SendPackToALLClient_with_noEncode((uint8_t*)output, buffer.GetLength()); CAppService::Instance()->GetMgServer()->SendToAllClient(output, buffer.GetLength()); } //save if (bNew) { CTime ctAlarmTime(tAlarm); CString sql; sql.Format("INSERT INTO [rm_alarm]([ID],[mo],[mp],[no],[type],[occur_time],[level],[desc],[suggest],[val]) "\ "VALUES(%d, '%s', '%s', %d, %d, '%s', %d, '%s', '%s', %d);", pAlarmInfo->id, pAlarmInfo->mo.c_str(), pAlarmInfo->mp.c_str(), pAlarmInfo->no, (int)pAlarmInfo->type, (LPCSTR)(ctAlarmTime.Format("%Y-%m-%d %H:%M:%S")), pAlarmInfo->level, pAlarmInfo->desc.c_str(), pAlarmInfo->suggest.c_str(), pAlarmInfo->val); if (false == CDBConnectPool::Instance()->DBExecuteSQL(sql)) { CSimpleLog::Error("执行语句失败" + sql); } } } void CResistAlarmMng::RecoverAlarm(const string mo, const string mp, const uint8_t no, const eZL_ALARMTYPE type, const uint8_t level, const SYSTEMTIME& tAlarm) { uint32_t alarm_id = -1; { std::lock_guard lock(m_mtxAlarm); for (auto it = m_lstUnConfirmAlarm.begin(); it != m_lstUnConfirmAlarm.end(); it++) { auto alarm = *it; if (alarm->type == type && alarm->mo.compare(mo) == 0 && alarm->mp.compare(mp) == 0 && no == alarm->no && level == alarm->level/* && ctAlarmTime - CTime(alarm->time) < cts*/) //跟上次报警时间超过1小时,则算新报警 { alarm_id = alarm->id; m_lstUnConfirmAlarm.erase(it); break; } } } if (alarm_id == -1) return; CTime ctAlarm(tAlarm); string ack_time = ctAlarm.Format("%Y-%m-%d %H:%M:%S"); //更新数据库 { CString sql; sql.Format("UPDATE [rm_alarm] SET ack_result = 1, ack_name='%s', ack_time='%s' WHERE ID = %d;", "系统", ack_time.c_str(), alarm_id); CDBConnectPool::Instance()->DBExecuteSQL(sql); } auto doc = yyjson_mut_doc_new(nullptr); auto root = yyjson_mut_obj(doc); yyjson_mut_doc_set_root(doc, root); yyjson_mut_obj_add_str(doc, root, "cmd", "alm_ack"); yyjson_mut_obj_add_uint(doc, root, "alarm_id", alarm_id); yyjson_mut_obj_add_strcpy(doc, root, "ack_time", ack_time.c_str()); yyjson_mut_obj_add_strcpy(doc, root, "ack_name", ANSItoUTF8("系统").c_str()); size_t len; auto json = yyjson_mut_write(doc, 0, &len); if (json) { CAppService::Instance()->GetMgServer()->SendToAllClient(json, len); free(json); } yyjson_mut_doc_free(doc); } eZL_MP_STAT CResistAlarmMng::GetAlarmStat(string& mo, string& mp, SYSTEMTIME& stAlarm) { eZL_MP_STAT stat = eZL_MP_STAT::MP_STAT_NORMAL_GREEN; lock_guard lock(m_mtxAlarm); auto it = m_lstUnConfirmAlarm.rbegin(); for (it; it != m_lstUnConfirmAlarm.rend(); ++it) { const auto& pInfo = *it; if (pInfo->ack_result) continue;//受理了暂时放过 if (pInfo->mo.compare(mo) == 0 && pInfo->mp.compare(mp) == 0) { if (pInfo->type == eZL_ALARMTYPE::EQUIP_OFFLINE || pInfo->type == eZL_ALARMTYPE::SENSOR_ABNORMAL) { stat = eZL_MP_STAT::MP_STAT_OFFLINE_GRAY; break; } else if (pInfo->level == 1) { stAlarm = pInfo->time; stat = eZL_MP_STAT::MP_STAT_ALARM_RED; break; } else if (pInfo->level == 0) { stAlarm = pInfo->time; stat = eZL_MP_STAT::MP_STAT_WARN_ORANGE; break; } } } return stat; } bool CResistAlarmMng::AlarmInfo2Pack(const ALARM_INFO* pAlarmInfo, rapidjson::StringBuffer& buffer, bool bGb2312 /*= false*/) { char szInfo[200]; char szUtf[200]; using namespace rapidjson; Writer writer(buffer); writer.StartObject(); writer.Key("cmd"); writer.String("new_alarm"); writer.Key("type"); //if (pAlarmInfo->type == MAX_OVER_LIMIT) writer.String("monitor.alarm.max_over_limit"); //else if (pAlarmInfo->type == EQUIP_OFFLINE) writer.String("monitor.alarm.equip_offline"); //else if (pAlarmInfo->type == SENSOR_ABNORMAL) writer.String("monitor.alarm.sensor_abnormal"); //else writer.String(""); writer.Int((int)pAlarmInfo->type); writer.Key("tag"); writer.String((pAlarmInfo->mo + '.' + pAlarmInfo->mp + '.' + to_string(pAlarmInfo->no + 1) + "#").c_str()); string up, momp_name, up_name; string momp = pAlarmInfo->mo + "." + pAlarmInfo->mp; CMonitorObjectMng::Instance()->GetStationNameByMomP(momp, up, momp_name); auto pObject = CMonitorObjectMng::Instance()->GetTreeByID(up); if (pObject) up_name = pObject->name; string name1, name2, name3; CMonitorObjectMng::Instance()->GetNameByMoMp(momp, name1, name2, name3); if (pAlarmInfo->no == 0 && name1.length() == 0) name1 = "1号测力点"; else if (pAlarmInfo->no == 1 && name2.length() == 0) name2 = "2号测力点"; else if (pAlarmInfo->no == 2 && name3.length() == 0) name3 = "3号测力点"; sprintf_s(szInfo, 200, "%s.%s.%s.%s%s", up_name.c_str(), momp_name.c_str(), pAlarmInfo->no == 0 ? name1.c_str() : pAlarmInfo->no == 1 ? name2.c_str() : pAlarmInfo->no == 2 ? name3.c_str() : "", GetAlarmName(pAlarmInfo->type).c_str(), pAlarmInfo->level == 1 ? "报警" : "预警" ); gbk2utf8(szUtf, sizeof(szUtf), szInfo); writer.Key("title"); writer.String(szUtf); gbk2utf8(szUtf, sizeof(szUtf), up.c_str()); writer.Key("up"); writer.String(szUtf); gbk2utf8(szUtf, sizeof(szUtf), up_name.c_str()); writer.Key("up_name"); writer.String(szUtf); writer.Key("alarm_id"); writer.Uint(pAlarmInfo->id); writer.Key("level"); if (pAlarmInfo->level) writer.String("alarm"); else writer.String("warn"); writer.Key("occur_time"); sprintf_s(szInfo, sizeof(szInfo), "%04d-%02d-%02d %02d:%02d:%02d.%03d", pAlarmInfo->time.wYear, pAlarmInfo->time.wMonth, pAlarmInfo->time.wDay, pAlarmInfo->time.wHour, pAlarmInfo->time.wMinute, pAlarmInfo->time.wSecond, pAlarmInfo->time.wMilliseconds); writer.String(szInfo); writer.Key("val"); if (pAlarmInfo->type == eZL_ALARMTYPE::EQUIP_OFFLINE || pAlarmInfo->type == eZL_ALARMTYPE::SENSOR_ABNORMAL) writer.String("-"); else writer.String(to_string(pAlarmInfo->val).c_str()); writer.String("desc"); gbk2utf8(szInfo, sizeof(szInfo), pAlarmInfo->desc.c_str()); writer.String(szInfo); writer.Key("suggest"); writer.String(""); if (pAlarmInfo->ack_result) { //已受理的报警 writer.String("ack_result"); writer.Int(pAlarmInfo->ack_result); writer.Key("ack_name"); writer.String(ANSItoUTF8(pAlarmInfo->ack_name).c_str()); writer.Key("ack_time"); writer.String(pAlarmInfo->ack_time.Format("%Y-%m-%d %H:%M:%S")); } writer.EndObject(); return true; } CResistAlarmMng CResistAlarmMng::obj; void CResistAlarmMng::InsertToDBByMove(string mo, string mp, time_t show_time, time_t start_time, time_t end_time, int curr_val, int show_val, uint8_t idx, uint8_t posi, string mark) { if (show_time == 0) return; CTime ctShowTime(show_time / 1000); string table_name = fmt::format("rm_move_{:0>4}{:0>2}", ctShowTime.GetYear(), ctShowTime.GetMonth()); CString sql = fmt::format("INSERT INTO {} (mo,mp,show_time,start_time,end_time,curr_val,show_val,idx,posi,mark) values ('{}', '{}', '{}', '{}','{}', {}, {}, {}, {}, '{}');", table_name, mo, mp, (LPCSTR)ctShowTime.Format("%Y-%m-%d %H:%M:%S.") + to_string(show_time % 1000), start_time ? CTime(start_time).Format("%Y-%m-%d %H:%M:%S") : "", end_time ? CTime(end_time).Format("%Y-%m-%d %H:%M:%S") : "", curr_val, show_val, idx, posi, mark).c_str(); if (CDBConnectPool::Instance()->DBExecuteSQL(sql) == FALSE) SPDLOG_ERROR(sql); } BOOL ConmpareValue(std::map::const_iterator i, std::map::const_iterator j, short refer_value, int& hight_num, int low_num) { int start_value = 0; for (i; i != j; i++) { if (i->second > refer_value) { if (start_value == 1) { //原来大于,现在也是大于 continue; } else { //原来小于或者无效,现在大于 start_value = 1; hight_num++; } } else { if (start_value == -1) { //原来小于,现在小于等于 continue; } else { //原来大于或者无效,现在小于 start_value = -1; low_num++; } } } return TRUE; } void CResistAlarmMng::ThreadProcAlarmSet(DWORD_PTR param) { auto pService = (CResistAlarmMng*)param; Sleep(2000); time_t tmNow; do { Sleep(100); time(&tmNow); if (tmNow == pService->m_lastDetectTime) continue; pService->m_lastDetectTime = tmNow; //1秒判断一次 for (const auto& item : pService->m_alarm_set) { if (item.second == nullptr) continue; if (item.second->enable == false) continue; if (item.second->type != eZL_ALARMTYPE::MAX_OVER_LIMIT && item.second->type != eZL_ALARMTYPE::FRICTION_OVER_LIMIT) //这个逻辑里面只支持这两种 continue; if (item.second->no < 0 || item.second->no > 2) continue; int nPos = item.first.find('.'); if (nPos == -1) continue; int nPos2 = item.first.find('.', nPos + 1); if (nPos2 == -1) continue; string mo = item.first.substr(0, nPos); string mp = item.first.substr(nPos + 1, nPos2 - nPos - 1); string momp = item.first.substr(0, nPos2); bool bNew = false; ALARM_INFO *pAlarmInfo = nullptr; CTime ctAlarmTime; string imei; int idx; //auto ret = CMonitorObjectMng::Instance()->MOMP2IMEI(momp, imei, idx); //TODO //if (ret == false) continue; #ifdef _DEBUG if (strcmp("860588048955283", imei.c_str()) != 0) continue; #endif auto pDevice = CDeviceMng::Instance()->Find(imei); if (pDevice == nullptr) { CSimpleLog::Error(("找不到imei(" + imei + ")" + std::to_string(__LINE__)).c_str()); continue; } int desc_type = 0; bool bAlarm = false, bWarn = false; int alarm_value = 0; time_t alarm_time; short high_alarm_limit = SHORT_MAX, high_warn_limit = SHORT_MAX, low_alarm_limit = -SHORT_MAX, low_warn_limit = -SHORT_MAX, alarm_refer = SHORT_MAX; time_t tmNow; time(&tmNow); BASE_INFO* pAlarmSet = item.second; do{ Sleep(100); lock_guard lock(pDevice->m_mtx); std::map* pData = pDevice->GetMapData(idx, item.second->no); assert(pData); if (pData == nullptr) continue; if (pData->size() == 0) continue; if (item.second->type == eZL_ALARMTYPE::MAX_OVER_LIMIT) { auto pInfo = (MAX_OVER_LIMIT_INFO*)item.second; #ifdef _DEBUG if (pInfo->tmLastCheckTime > pData->rbegin()->first) pInfo->tmLastCheckTime = pData->rbegin()->first; #endif auto it = pData->cbegin(); if (pInfo->tmLastCheckTime == 0) pInfo->tmLastCheckTime = pData->rbegin()->first; else if (pInfo->tmLastCheckTime != 0) it = pData->find(pInfo->tmLastCheckTime); if (it == pData->cend()) { it = pData->find(pInfo->tmLastCheckTime / 1000 * 1000); if (it == pData->cend()) { pInfo->tmLastCheckTime = pData->rbegin()->first; continue; } } if (pInfo->tmLastCheckTime == pData->rbegin()->first) //没有新的数据 continue; #ifdef _DEBUG TRACE("%s.%s.%d.%d lastcheck:%s now:%s\r\n", mo.c_str(), mp.c_str(), pInfo->no, (int)eZL_ALARMTYPE::MAX_OVER_LIMIT, CTime(pInfo->tmLastCheckTime / 1000).Format("%Y-%m-%d %H:%M:%S"), CTime(pData->rbegin()->first / 1000).Format("%Y-%m-%d %H:%M:%S")); #endif // _DEBUG time_t tmStartSteady = pInfo->tmLastCheckTime / 1000 - 3; //稳态报警检测开始, 从上次3秒前到当前秒 if (item.second->no == 2) { if (pInfo->alarm_high_limit > pInfo->f_alarm_high_limit) {//定板反 high_alarm_limit = pInfo->alarm_high_limit; high_warn_limit = pInfo->warn_high_limit; low_alarm_limit = pInfo->f_alarm_high_limit; low_warn_limit = pInfo->f_warn_high_limit; } else {//反板定 low_alarm_limit = pInfo->alarm_high_limit; low_warn_limit = pInfo->warn_high_limit; high_alarm_limit = pInfo->f_alarm_high_limit; high_warn_limit = pInfo->f_warn_high_limit; } } for (++it; it != pData->cend(); ++it) { //CString str = CTime(it->first / 1000).Format("%Y-%m-%d %H:%M:%S"); if (it->second == INVALID_RESIST) { pInfo->tmLastCheckTime = it->first; continue; } if (item.second->no < 2) { //1,2 锁闭力报警 if (it->second > pInfo->alarm_high_limit) { bAlarm = true; alarm_refer = pInfo->alarm_high_limit; alarm_value = it->second; alarm_time = it->first; pInfo->tmLastCheckTime = pData->rbegin()->first; desc_type = 1; break; } //else if (it->second > pInfo->warn_high_limit) //稳态报警单独判断 //{ // bWarn = true; // alarm_refer = pInfo->warn_high_limit; // alarm_value = it->second; // alarm_time = it->first; // pInfo->tmLastCheckTime = pData->rbegin()->first; //} } else { assert(item.second->no == 2); if (pInfo->alarm_high_limit == SHORT_MAX || pInfo->f_alarm_high_limit == SHORT_MAX || pInfo->alarm_high_limit == pInfo->f_alarm_high_limit) break; desc_type = 3; if (it->second > high_alarm_limit) { bAlarm = true; alarm_refer = high_alarm_limit; alarm_value = it->second; alarm_time = it->first; pInfo->tmLastCheckTime = pData->rbegin()->first; break; } else if (it->second < low_alarm_limit) { bAlarm = true; alarm_refer = low_alarm_limit; alarm_value = it->second; alarm_time = it->first; pInfo->tmLastCheckTime = pData->rbegin()->first; break; } else if (low_warn_limit == SHORT_MAX || high_warn_limit == SHORT_MAX) { //未设置预警值 } else if (it->second > high_warn_limit) { bWarn = true; alarm_refer = high_warn_limit; alarm_value = it->second; alarm_time = it->first; pInfo->tmLastCheckTime = pData->rbegin()->first; } else if (it->second < low_warn_limit) { bWarn = true; alarm_refer = low_warn_limit; alarm_value = it->second; alarm_time = it->first; pInfo->tmLastCheckTime = pData->rbegin()->first; } } pInfo->tmLastCheckTime = it->first; } //稳态报警判断 if (item.second->no < 2 && bAlarm == false) { time_t tmEnd = pInfo->tmLastCheckTime / 1000; int dif = tmEnd - tmStartSteady; for (time_t i = tmStartSteady; i < tmEnd - 3; i++) { #ifdef _DEBUG COleDateTime t(i); TRACE("%s\r\n", t.Format("%Y-%m-%d %H:%M:%S")); #endif // _DEBUG auto j = pData->find(i * 1000); if (j == pData->end()) continue; time_t t2 = (i + 1) * 1000; auto k = pData->find(t2); if (k == pData->end()) continue; t2 = (i + 2) * 1000; k = pData->find(t2); if (k == pData->end()) continue; //连续3秒在线,继续找下一个结束点 t2 = (i + 3) * 1000; auto g = pData->find(t2); if (g == pData->end()) { for (++k; k != pData->end(); k++) { if (k->first >= t2) { g = k; break; } } } if (g == pData->end()) continue; int high_num = 0, low_num = 0; ConmpareValue(j, g, pInfo->warn_high_limit, high_num, low_num); if (high_num > 0 && high_num <= 2) { bWarn = true; desc_type = 2; alarm_refer = pInfo->warn_high_limit; alarm_value = high_num; alarm_time = i * 1000; //报警时间 pInfo->tmLastCheckTime = pData->rbegin()->first; break; } } } } else if (item.second->type == eZL_ALARMTYPE::FRICTION_OVER_LIMIT) { auto pInfo = (FRICTION_OVER_LIMIT_INFO*)item.second; #ifdef _DEBUG if (pInfo->tmLastCheckTime > pData->rbegin()->first) pInfo->tmLastCheckTime = pData->rbegin()->first; #endif auto it = pData->cbegin(); if (pInfo->tmLastCheckTime == 0) pInfo->tmLastCheckTime = pData->rbegin()->first; else if (pInfo->tmLastCheckTime != 0) it = pData->find(pInfo->tmLastCheckTime); if (it == pData->cend()) { it = pData->find(pInfo->tmLastCheckTime / 1000 * 1000); if (it == pData->cend()) { pInfo->tmLastCheckTime = pData->rbegin()->first; continue; } } if (pInfo->tmLastCheckTime == pData->rbegin()->first) //没有新的数据 continue; if (tmNow * 1000 - pInfo->tmLastCheckTime < 5000) //5秒检测一次 continue; #ifdef _DEBUG TRACE("%s.%s.%d.%d lastcheck:%s now:%s\r\n", mo.c_str(), mp.c_str(), pInfo->no, (int)eZL_ALARMTYPE::FRICTION_OVER_LIMIT, CTime(pInfo->tmLastCheckTime / 1000).Format("%Y-%m-%d %H:%M:%S"), CTime(pData->rbegin()->first / 1000).Format("%Y-%m-%d %H:%M:%S")); #endif // _DEBUG if (item.second->no != 2) continue; //从检测时间往前取30秒的数据 static const int dif_resist = 200; //稳定期判定差值 int up_max_resist = INT_MIN; //上最大值 time_t up_max_time = 0; int up_avg_resist = INT_MIN; //上稳定期平均值 uint64_t up_stable_sum = 0; //上稳定期的和 int up_stable_time = 0; //上稳定期的数值个数 int up_start_resist_stabel = INT_MIN; //上稳定期开始值 time_t up_start_stable_time = 0; //规定是最大值之后的2秒 time_t up_end_stable_time = 0;//稳定结束的时间 int up_dif_time_stable = 0; //上稳定期的时长 int down_max_resist = INT_MAX; //上最大值 time_t down_max_time = 0; int down_avg_resist = INT_MAX; //上稳定期平均值 uint64_t down_stable_sum = 0; //上稳定期的和 int down_stable_time = 0; //上稳定期的数值个数 int down_start_resist_stabel = INT_MAX; //上稳定期开始值 time_t down_start_stable_time = 0; //规定是最大值之后的2秒 int down_dif_time_stable = 0; //上稳定期的时长 time_t tmEnd = pData->rbegin()->first / 1000 + 1; //结束时间 time_t tmStart = tmEnd - 36;//开始时间是从上次35秒到当前秒 std::map::const_iterator it_start, it_up_max, it_down_min, it_up_stable_start, it_down_stable_start, it_up_stable_end, it_down_stable_end; //寻找起始时间 for (time_t i = tmStart; i < tmEnd; i++) { #ifdef _DEBUG COleDateTime t(i); TRACE("%s\r\n", t.Format("%Y-%m-%d %H:%M:%S")); #endif // _DEBUG it_start = pData->find(i * 1000); if (it_start != pData->cend()) break; } pInfo->tmLastCheckTime = pData->rbegin()->first; //赋值最后的时间 if (it_start == pData->cend()) break; bool bUp = true, bDown = true; //先找最大值 for (auto i = it_start; i != pData->cend(); i++) { //寻找最大的点 if (i->second > up_max_resist) { up_max_resist = i->second; it_up_max = i; } //寻找最小的点 if (i->second < down_max_resist) { down_max_resist = i->second; it_down_min = i; } } if (pInfo->tmLastCheckTime - it_up_max->first < 17000) bUp = false; //小于17秒 if (pInfo->tmLastCheckTime - it_down_min->first < 1700) bDown = false; //小于17秒 if(bUp == false && bDown == false) break; //再找稳定开始 if (bUp) { it_up_stable_start = it_up_max; for (auto i = it_up_max; i != pData->cend(); i++) { if (i->first - it_up_max->first < 2000) continue; else { it_up_stable_start = i; break; } } if (it_up_stable_start == it_up_max) bUp = false; } if (bDown) { it_down_stable_start = it_down_min; for (auto i = it_down_min; i != pData->cend(); i++) { if (i->first - it_down_min->first < 2000) continue; else { it_down_stable_start = i; break; } } if (it_down_stable_start == it_down_min) bDown = false; } if (bUp == false && bDown == false) break; if (bUp) { up_start_resist_stabel = it_up_stable_start->second;//稳定期开始的值 it_up_stable_end = it_up_stable_start; for (auto i = it_up_stable_start; i != pData->cend(); i++) { if (abs(up_start_resist_stabel - i->second) < dif_resist) { up_stable_sum += i->second; up_start_stable_time++; it_up_stable_end = i; continue; } else { break; } } //时间条件限定在 15s-30s 之间 auto dif = it_up_stable_end->first - it_up_stable_start->first; if (dif > 15000 && dif < 30000) { //平均值 up_avg_resist = up_stable_sum / up_start_stable_time; if (up_avg_resist < pInfo->up_alarm_low_limit) { bAlarm = true; alarm_value = up_avg_resist; alarm_time = it_up_stable_start->first; alarm_refer = pInfo->up_alarm_low_limit; desc_type = 4; } else if (up_avg_resist < pInfo->up_warn_low_limit) { bWarn = true; alarm_value = up_avg_resist; alarm_time = it_up_stable_start->first; alarm_refer = pInfo->up_warn_low_limit; desc_type = 4; } } } if (bDown) { down_start_resist_stabel = it_down_stable_start->second;//稳定期开始的值 it_down_stable_end = it_down_stable_start; for (auto i = it_down_stable_start; i != pData->cend(); i++) { if (abs(down_start_resist_stabel - i->second) < dif_resist) { down_stable_sum += i->second; down_start_stable_time++; it_down_stable_end = i; continue; } else { break; } } //时间条件限定在 15s-30s 之间 auto dif = it_down_stable_end->first - it_down_stable_start->first; if (dif > 15000 && dif < 30000) { //平均值 down_avg_resist = down_stable_sum / down_start_stable_time; if (down_avg_resist > pInfo->dw_alarm_high_limit) { bAlarm = true; alarm_value = down_avg_resist; alarm_time = it_down_stable_start->first; alarm_refer = pInfo->dw_alarm_high_limit; desc_type = 5; } else if (down_avg_resist > pInfo->dw_warn_high_limit) { bWarn = true; alarm_value = down_avg_resist; alarm_time = it_down_stable_start->first; alarm_refer = pInfo->dw_warn_high_limit; desc_type = 5; } } } } else { //其他未实现 //TODO assert(0); continue; } }while (false); //update CString sql; sql.Format("update rm_alarm_set SET time = %I64u WHERE mo = '%s' and mp = '%s' and no = %d and type = %d", pAlarmSet->tmLastCheckTime, mo.c_str(), mp.c_str(), pAlarmSet->no, pAlarmSet->type); if (CDBConnectPool::Instance()->DBExecuteSQL(sql) == FALSE) { assert(0); CSimpleLog::Error("语句执行失败" + sql); } if (bAlarm == false && bWarn == false) continue; //没有报警 //查找是否原有的报警已存在 uint8_t level = 0; if (bAlarm) level = 1; ctAlarmTime = CTime(alarm_time / 1000); { std::lock_guard lock(pService->m_mtxAlarm); for (const auto& alarm : pService->m_lstUnConfirmAlarm) { static CTimeSpan cts(0, 6, 0, 0); //报警间隔6小时重新生成报警 if (alarm->no == item.second->no && alarm->type == pAlarmSet->type && level == alarm->level //预警和报警单独计算 && alarm->mo.compare(mo) == 0 && alarm->mp.compare(mp) == 0 && ctAlarmTime - CTime(alarm->time) < cts) //跟上次报警时间超过1小时,则算新报警 { pAlarmInfo = alarm; break; } } } if (pAlarmInfo == nullptr) { bNew = true; pAlarmInfo = new ALARM_INFO; pAlarmInfo->id = ++pService->m_nAlarmID; pAlarmInfo->level = (bAlarm == 1); pAlarmInfo->mo = mo; pAlarmInfo->mp = mp; pAlarmInfo->no = item.second->no; ctAlarmTime.GetAsSystemTime(pAlarmInfo->time); pAlarmInfo->time.wMilliseconds = alarm_time % 1000; pAlarmInfo->type = item.second->type; pAlarmInfo->val = alarm_value; char szInfo[200]; if (desc_type == 1) sprintf_s(szInfo, sizeof(szInfo), "瞬时冲击力超限报警,报警值为%dN, 参考值为%dN", alarm_value, alarm_refer); else if (desc_type == 2) sprintf_s(szInfo, sizeof(szInfo), "稳态值超限预警, 超限次数为%d次, 参考值为%dN", alarm_value, alarm_refer); else if (desc_type == 3) sprintf_s(szInfo, sizeof(szInfo), "转换阻力值超限报警, 报警值为%dN, 参考值为%dN", alarm_value, alarm_refer); else if (desc_type == 4) sprintf_s(szInfo, sizeof(szInfo), "摩擦力超限%s, 缩进位报警值为%dN, 参考值为:%dN", bAlarm == 1 ? "告警" : "预警", alarm_value, alarm_refer); else if (desc_type == 5) sprintf_s(szInfo, sizeof(szInfo), "摩擦力超限%s, 伸出位报警值为%dN, 参考值为:%dN", bAlarm == 1 ? "告警" : "预警", alarm_value, alarm_refer); else assert(0); pAlarmInfo->desc = szInfo; lock_guard lock(pService->m_mtxAlarm); pService->m_lstUnConfirmAlarm.push_back(pAlarmInfo); } //send if (bNew) //不再推送 { rapidjson::StringBuffer buffer; auto ret = AlarmInfo2Pack(pAlarmInfo, buffer); const char* output = buffer.GetString(); //CAppService::Instance()->GetLwsServer()->SendPackToALLClient_with_noEncode((uint8_t*)output, buffer.GetLength()); CAppService::Instance()->GetMgServer()->SendToAllClient(output, buffer.GetLength()); } //save if (bNew) { CString sql; sql.Format("INSERT INTO [rm_alarm]([ID],[mo],[mp],[no],[type],[occur_time],[level],[desc],[suggest],[val]) "\ "VALUES(%d, '%s', '%s', %d, %d, '%s', %d, '%s', '%s', %d);", pAlarmInfo->id, pAlarmInfo->mo.c_str(), pAlarmInfo->mp.c_str(), pAlarmInfo->no, pAlarmInfo->type, ctAlarmTime.Format("%Y-%m-%d %H:%M:%S"), pAlarmInfo->level, pAlarmInfo->desc.c_str(), pAlarmInfo->suggest.c_str(), pAlarmInfo->val); if (false == CDBConnectPool::Instance()->DBExecuteSQL(sql)) { CSimpleLog::Error("执行语句失败" + sql); } } } //10秒归档一次 /*采用滑动方式检测.每次检测15秒的数据.每次滑动10秒. 即0分20秒时 取 0 - 15秒的数据, 下一次检测时间 0分30秒, 取10 - 25秒的数据. 再下一次检测时间0分40秒, 取20 - 35秒数据. */ /* if (tmNow % 10 != 0) continue; auto& mapDevice = CDeviceMng::Instance()->m_map_devices; for (auto& it : mapDevice) { auto pDevice = it.second; if (pDevice->m_tmMoveDetectTime == 0) continue; time_t tmStart = pDevice->m_tmMoveDetectTime - 20; time_t tmEnd = pDevice->m_tmMoveDetectTime - 2; #ifdef _DEBUG string strStart = CTime(tmStart).Format("%Y-%m-%d %H:%M:%S"); string strEnd = CTime(tmEnd).Format("%Y-%m-%d %H:%M:%S"); TRACE("%s-%s\r\n", strStart.c_str(), strEnd.c_str()); #endif // _DEBUG pDevice->m_tmMoveDetectTime += 10; for (auto i = 0; i < 3; i++) { std::map map0, map1, map2; if (pDevice->GetSendStatInfo(tmStart, tmEnd, i, map0, map1, map2) == FALSE) continue; list lstResit2; std::map maxlock0, maxlock1; mg_per_session_data::GetMaxResist(map2, lstResit2); if (lstResit2.size()) { mg_per_session_data::GetMaxLockNew(map0, lstResit2, maxlock0); mg_per_session_data::GetMaxLockNew(map1, lstResit2, maxlock1); } string mo, mp; if (FALSE == CMonitorObjectMng::Instance()->IMEI2MOMP(pDevice->imei, i, mo, mp)) { CSimpleLog::Error(fmt::format("IMEI2MOMP fail. imei:{}, idx:{}", pDevice->imei, i).c_str()); continue; } string name1, name2, name3, out_name, in_name; CMonitorObjectMng::Instance()->GetNameByMoMp(mo + "." + mp, name1, name2, name3, out_name, in_name); for (auto& it : maxlock0) { if (name1.find("定位") != -1) CResistAlarmMng::InsertToDBByMove(mo, mp, it.first, 0, (int)it.second, (it.second >> 32), i, (uint8_t)eDaoChaPosi::DCP_FIX, fmt::format("定位密贴锁闭力值:{}", (it.second >> 32))); else CResistAlarmMng::InsertToDBByMove(mo, mp, it.first, 0, (int)it.second, (it.second >> 32), i, (uint8_t)eDaoChaPosi::DCP_INVERT, fmt::format("反位密贴锁闭力值:{}", (it.second >> 32))); } for (auto& it : maxlock1) { if (name2.find("定位") != -1) CResistAlarmMng::InsertToDBByMove(mo, mp, it.first, 0, (int)it.second, (it.second >> 32), i, (uint8_t)eDaoChaPosi::DCP_FIX, fmt::format("定位密贴锁闭力值:{}", (it.second >> 32))); else CResistAlarmMng::InsertToDBByMove(mo, mp, it.first, 0, (int)it.second, (it.second >> 32), i, (uint8_t)eDaoChaPosi::DCP_INVERT, fmt::format("反位密贴锁闭力值:{}", (it.second >> 32))); } for (auto& it : lstResit2) { if (it.bUpOrDown == 1) { if (in_name.find("定扳反") != -1) CResistAlarmMng::InsertToDBByMove(mo, mp, it.time, it.tmStart, it.val, it.fluctuation_val, i, (uint8_t)eDaoChaPosi::DCP_FIX2INVERT, fmt::format("{}转换值:{}", in_name, it.fluctuation_val)); else CResistAlarmMng::InsertToDBByMove(mo, mp, it.time, it.tmStart, it.val, it.fluctuation_val, i, (uint8_t)eDaoChaPosi::DCP_INVERT2FIX, fmt::format("{}转换值:{}", in_name, it.fluctuation_val)); } else { if (out_name.find("定扳反") != -1) CResistAlarmMng::InsertToDBByMove(mo, mp, it.time, it.tmStart, it.val, it.fluctuation_val, i, (uint8_t)eDaoChaPosi::DCP_FIX2INVERT, fmt::format("{}转换值:{}", out_name, it.fluctuation_val)); else CResistAlarmMng::InsertToDBByMove(mo, mp, it.time, it.tmStart, it.val, it.fluctuation_val, i, (uint8_t)eDaoChaPosi::DCP_INVERT2FIX, fmt::format("{}转换值:{}", out_name, it.fluctuation_val)); } } } } */ //10秒归档一次 if (tmNow % 10 != 0) continue; time_t tt; time(&tt); auto& mapDevice = CDeviceMng::Instance()->m_map_devices; for (auto& it : mapDevice) { auto pDevice = it.second; for (auto i = 0; i < 3; i++) { string mo, mp; //if (FALSE == CMonitorObjectMng::Instance()->IMEI2MOMP(pDevice->imei, i, mo, mp)) //TODO { //CSimpleLog::Error(fmt::format("IMEI2MOMP fail. imei:{}, idx:{}, {}:{}", pDevice->imei, i, __FILE__, __LINE__).c_str()); continue; //没有绑定返回 } std::map map0, map1, map2; if (i == 0) { if (pDevice->m_mapSecondStatInfo00.size() == 0) continue; else if (tt - pDevice->m_tmMoveDetectTime0 < 20) continue; else if (pDevice->m_mapSecondStatInfo00.rbegin()->second.dif_val > 100) continue; //最后值需要稳定 lock_guard lock(pDevice->m_mtx); swap(pDevice->m_mapSecondStatInfo00, map0); swap(pDevice->m_mapSecondStatInfo01, map1); swap(pDevice->m_mapSecondStatInfo02, map2); } else if (i == 1) { if (pDevice->m_mapSecondStatInfo10.size() == 0) continue; else if (tt - pDevice->m_tmMoveDetectTime1 < 20) continue; else if (pDevice->m_mapSecondStatInfo10.rbegin()->second.dif_val > 100) continue; //最后值需要稳定 lock_guard lock(pDevice->m_mtx); swap(pDevice->m_mapSecondStatInfo10, map0); swap(pDevice->m_mapSecondStatInfo11, map1); swap(pDevice->m_mapSecondStatInfo12, map2); } else { if (pDevice->m_mapSecondStatInfo20.size() == 0) continue; else if (tt - pDevice->m_tmMoveDetectTime2 < 20) continue; else if (pDevice->m_mapSecondStatInfo20.rbegin()->second.dif_val > 100) continue; //最后值需要稳定 lock_guard lock(pDevice->m_mtx); swap(pDevice->m_mapSecondStatInfo20, map0); swap(pDevice->m_mapSecondStatInfo21, map1); swap(pDevice->m_mapSecondStatInfo22, map2); } list lstResit2; std::map maxlock0, maxlock1; mg_per_session_data::GetMaxResistNew(map2, lstResit2, mo, mp); if (lstResit2.size()) { mg_per_session_data::GetMaxLockNew(map0, lstResit2, maxlock0); mg_per_session_data::GetMaxLockNew(map1, lstResit2, maxlock1); SPDLOG_INFO("[转换阻力][{}:{}] lock0:{} lock1:{}, resist2:{}", mo, mp, maxlock0.size(), maxlock1.size(), lstResit2.size()); } else continue; //没有检查到转换阻力 string name1, name2, name3, out_name, in_name; CMonitorObjectMng::Instance()->GetNameByMoMp(mo + "." + mp, name1, name2, name3, out_name, in_name); for (auto& it : maxlock0) { if (name1.find("定位") != -1) CResistAlarmMng::InsertToDBByMove(mo, mp, it.first, 0, 0, (int)it.second, (it.second >> 32), i, (uint8_t)eDaoChaPosi::DCP_FIX, fmt::format("锁闭力:{}", (it.second >> 32))); else CResistAlarmMng::InsertToDBByMove(mo, mp, it.first, 0, 0, (int)it.second, (it.second >> 32), i, (uint8_t)eDaoChaPosi::DCP_INVERT, fmt::format("锁闭力:{}", (it.second >> 32))); } for (auto& it : maxlock1) { if (name2.find("定位") != -1) CResistAlarmMng::InsertToDBByMove(mo, mp, it.first, 0, 0, (int)it.second, (it.second >> 32), i, (uint8_t)eDaoChaPosi::DCP_FIX, fmt::format("锁闭力:{}", (it.second >> 32))); else CResistAlarmMng::InsertToDBByMove(mo, mp, it.first, 0, 0, (int)it.second, (it.second >> 32), i, (uint8_t)eDaoChaPosi::DCP_INVERT, fmt::format("锁闭力:{}", (it.second >> 32))); } for (auto& it : lstResit2) { if (it.bUpOrDown == 1) { if (in_name.find("定扳反") != -1) CResistAlarmMng::InsertToDBByMove(mo, mp, it.time, it.tmStart, it.tmEnd, it.val, it.fluctuation_val, i, (uint8_t)eDaoChaPosi::DCP_FIX2INVERT, fmt::format("{}:{}", in_name, it.fluctuation_val)); else CResistAlarmMng::InsertToDBByMove(mo, mp, it.time, it.tmStart, it.tmEnd, it.val, it.fluctuation_val, i, (uint8_t)eDaoChaPosi::DCP_INVERT2FIX, fmt::format("{}:{}", in_name, it.fluctuation_val)); } else { if (out_name.find("定扳反") != -1) CResistAlarmMng::InsertToDBByMove(mo, mp, it.time, it.tmStart, it.tmEnd, it.val, it.fluctuation_val, i, (uint8_t)eDaoChaPosi::DCP_FIX2INVERT, fmt::format("{}:{}", out_name, it.fluctuation_val)); else CResistAlarmMng::InsertToDBByMove(mo, mp, it.time, it.tmStart, it.tmEnd, it.val, it.fluctuation_val, i, (uint8_t)eDaoChaPosi::DCP_INVERT2FIX, fmt::format("{}:{}", out_name, it.fluctuation_val)); } } } } } while (pService->m_bWork); } typedef struct tagMoMp { string mo; string mp; uint8_t no; //传感器的序号 tagMoMp(string a, string b) { mo = a; mp = b; } tagMoMp(uint8_t a) { no = a; } }; typedef struct offline_info { string imei; CTime time; uint8_t idx = 0; std::vector vct; offline_info(string a, CTime b) { imei = a; time = b; } offline_info(string a, CTime b, uint8_t c, uint8_t d) { imei = a; time = b; idx = c; vct.push_back(tagMoMp(d)); } }; void CResistAlarmMng::ThreadProcDevice(DWORD_PTR param) { auto pService = (CResistAlarmMng*)param; this_thread::sleep_for(chrono::seconds(2)); static CTimeSpan offline_time(0, 0, 3, 0); //设备离线时间暂定5分钟 static CTimeSpan offline_limit(30, 0, 0, 0); do { for (int i = 0; i < 30; i++) { if (false == pService->m_bWork) break; this_thread::sleep_for(chrono::seconds(1)); } CTime ctNow = CTime::GetCurrentTime(); //传感器异常检测 { std::vector vct; { lock_guard lock(CDeviceMng::Instance()->m_mtx); const auto& pDevices = CDeviceMng::Instance()->m_map_devices; for (const auto& it : pDevices) { { const auto& item = it.second->map_resist_idx00; if (item.size() && item.rbegin()->second == INVALID_RESIST) { vct.push_back(offline_info(it.first, (item.rbegin()->first / 1000), 0, 0)); } } { const auto& item = it.second->map_resist_idx01; if (item.size() && item.rbegin()->second == INVALID_RESIST) { vct.push_back(offline_info(it.first, (item.rbegin()->first / 1000), 0, 1)); } } { const auto& item = it.second->map_resist_idx02; if (item.size() && item.rbegin()->second == INVALID_RESIST) { vct.push_back(offline_info(it.first, (item.rbegin()->first / 1000), 0, 2)); } } { const auto& item = it.second->map_resist_idx10; if (item.size() && item.rbegin()->second == INVALID_RESIST) { vct.push_back(offline_info(it.first, (item.rbegin()->first / 1000), 1, 0)); } } { const auto& item = it.second->map_resist_idx11; if (item.size() && item.rbegin()->second == INVALID_RESIST) { vct.push_back(offline_info(it.first, (item.rbegin()->first / 1000), 1, 1)); } } { const auto& item = it.second->map_resist_idx12; if (item.size() && item.rbegin()->second == INVALID_RESIST) { vct.push_back(offline_info(it.first, (item.rbegin()->first / 1000), 1, 2)); } } { const auto& item = it.second->map_resist_idx20; if (item.size() && item.rbegin()->second == INVALID_RESIST) { vct.push_back(offline_info(it.first, (item.rbegin()->first / 1000), 2, 0)); } } { const auto& item = it.second->map_resist_idx21; if (item.size() && item.rbegin()->second == INVALID_RESIST) { vct.push_back(offline_info(it.first, (item.rbegin()->first / 1000), 2, 1)); } } { const auto& item = it.second->map_resist_idx22; if (item.size() && item.rbegin()->second == INVALID_RESIST) { vct.push_back(offline_info(it.first, (item.rbegin()->first / 1000), 2, 2)); } } } } //转换成momp for (auto it = vct.begin(); it != vct.end();) { string mo, mp; //if (CMonitorObjectMng::Instance()->IMEI2MOMP(it->imei, it->idx, mo, mp) && it->vct.size() >= 1) //TODO { it->vct[0].mo = mo; it->vct[0].mp = mp; it++; } //else { it = vct.erase(it); //CString strLog; //strLog.Format("imei(%s)(%d) 转换成 mo, mp 失败.请检查是否绑定.size;(%d) %s:%d", it.imei.c_str(), it.idx, (int)it.vct.size(), __FUNCTION__, __LINE__); //CSimpleLog::Warn(strLog); } } CTime ctAlarmTime = ctNow; for (const auto& it : vct) { for (const auto& it_mo_mp : it.vct) { ALARM_INFO* pAlarmInfo = nullptr; bool bNew = false; { std::lock_guard lock(pService->m_mtxAlarm); for (const auto& alarm : pService->m_lstUnConfirmAlarm) { if (alarm->type == eZL_ALARMTYPE::SENSOR_ABNORMAL && alarm->mo.compare(it_mo_mp.mo) == 0 && alarm->mp.compare(it_mo_mp.mp) == 0 && it_mo_mp.no == alarm->no/* && ctAlarmTime - CTime(alarm->time) < cts*/) //跟上次报警时间超过1小时,则算新报警 { pAlarmInfo = alarm; break; } } } if (pAlarmInfo == nullptr) { bNew = true; pAlarmInfo = new ALARM_INFO; pAlarmInfo->id = ++pService->m_nAlarmID; pAlarmInfo->level = 1; pAlarmInfo->mo = it_mo_mp.mo; pAlarmInfo->mp = it_mo_mp.mp; pAlarmInfo->no = it_mo_mp.no; ctAlarmTime.GetAsSystemTime(pAlarmInfo->time); //pAlarmInfo->time.wMilliseconds = alarm_time % 1000; pAlarmInfo->type = eZL_ALARMTYPE::SENSOR_ABNORMAL; pAlarmInfo->val = 0; char szInfo[200]; sprintf_s(szInfo, sizeof(szInfo), "传感器异常时间:%s", (LPCSTR)(it.time.Format("%Y-%m-%d %H:%M:%S"))); pAlarmInfo->desc = szInfo; lock_guard lock(pService->m_mtxAlarm); pService->m_lstUnConfirmAlarm.push_back(pAlarmInfo); } //send if (bNew) //不再推送 { rapidjson::StringBuffer buffer; auto ret = AlarmInfo2Pack(pAlarmInfo, buffer); const char* output = buffer.GetString(); //CAppService::Instance()->GetLwsServer()->SendPackToALLClient_with_noEncode((uint8_t*)output, buffer.GetLength()); CAppService::Instance()->GetMgServer()->SendToAllClient(output, buffer.GetLength()); } //save if (bNew) { CString sql; sql.Format("INSERT INTO [rm_alarm]([ID],[mo],[mp],[no],[type],[occur_time],[level],[desc],[suggest],[val]) "\ "VALUES(%d, '%s', '%s', %d, %d, '%s', %d, '%s', '%s', %d);", pAlarmInfo->id, pAlarmInfo->mo.c_str(), pAlarmInfo->mp.c_str(), pAlarmInfo->no, (int)pAlarmInfo->type, (LPCSTR)(ctAlarmTime.Format("%Y-%m-%d %H:%M:%S")), pAlarmInfo->level, pAlarmInfo->desc.c_str(), pAlarmInfo->suggest.c_str(), pAlarmInfo->val); if (false == CDBConnectPool::Instance()->DBExecuteSQL(sql)) { CSimpleLog::Error("执行语句失败" + sql); } } } } } { //离线设备 std::vector vct; { lock_guard lock(CDeviceMng::Instance()->m_mtx); const auto& pDevices = CDeviceMng::Instance()->m_map_devices; for (const auto& it : pDevices) if (it.second->m_ctUpdateTime != 0 && ctNow - it.second->m_ctUpdateTime > offline_time && ctNow - it.second->m_ctUpdateTime < offline_limit) { vct.push_back(offline_info(it.first, it.second->m_ctUpdateTime)); } } for (auto& it : vct) { for (int i = 0; i < 3; i++) { string mo, mp; //if (CMonitorObjectMng::Instance()->IMEI2MOMP(it.imei, i, mo, mp)) //TODO { it.vct.push_back(tagMoMp(mo, mp)); } //else { //CString strLog; //strLog.Format("imei(%s)(%d) 转换成 mo, mp 失败.请检查是否绑定. size;(%d) %s:%d", it.imei.c_str(), i, (int)it.vct.size(), __FUNCTION__, __LINE__); //CSimpleLog::Warn(strLog); } } } CTime ctAlarmTime = ctNow; for (const auto& it : vct) { for (const auto& it_mo_mp : it.vct) { ALARM_INFO* pAlarmInfo = nullptr; bool bNew = false; { std::lock_guard lock(pService->m_mtxAlarm); for (const auto& alarm : pService->m_lstUnConfirmAlarm) { static CTimeSpan cts(0, 6, 0, 0); //报警间隔6小时重新生成报警 if (alarm->type == eZL_ALARMTYPE::EQUIP_OFFLINE && alarm->mo.compare(it_mo_mp.mo) == 0 && alarm->mp.compare(it_mo_mp.mp) == 0/* && ctAlarmTime - CTime(alarm->time) < cts*/) //跟上次报警时间超过1小时,则算新报警 { pAlarmInfo = alarm; break; } } } if (pAlarmInfo == nullptr) { bNew = true; pAlarmInfo = new ALARM_INFO; pAlarmInfo->id = ++pService->m_nAlarmID; pAlarmInfo->level = 1; pAlarmInfo->mo = it_mo_mp.mo; pAlarmInfo->mp = it_mo_mp.mp; pAlarmInfo->no = -1; ctAlarmTime.GetAsSystemTime(pAlarmInfo->time); //pAlarmInfo->time.wMilliseconds = alarm_time % 1000; pAlarmInfo->type = eZL_ALARMTYPE::EQUIP_OFFLINE; pAlarmInfo->val = 0; char szInfo[200]; sprintf_s(szInfo, sizeof(szInfo), "设备离线时间:%s", (LPCSTR)(it.time.Format("%Y-%m-%d %H:%M:%S"))); pAlarmInfo->desc = szInfo; lock_guard lock(pService->m_mtxAlarm); pService->m_lstUnConfirmAlarm.push_back(pAlarmInfo); } //send if (bNew) //不再推送 { rapidjson::StringBuffer buffer; auto ret = AlarmInfo2Pack(pAlarmInfo, buffer); const char* output = buffer.GetString(); //CAppService::Instance()->GetLwsServer()->SendPackToALLClient_with_noEncode((uint8_t*)output, buffer.GetLength()); CAppService::Instance()->GetMgServer()->SendToAllClient(output, buffer.GetLength()); } //save if (bNew) { CString sql; sql.Format("INSERT INTO [rm_alarm]([ID],[mo],[mp],[no],[type],[occur_time],[level],[desc],[suggest],[val]) "\ "VALUES(%d, '%s', '%s', %d, %d, '%s', %d, '%s', '%s', %d);", pAlarmInfo->id, pAlarmInfo->mo.c_str(), pAlarmInfo->mp.c_str(), pAlarmInfo->no, pAlarmInfo->type, (LPCSTR)(ctAlarmTime.Format("%Y-%m-%d %H:%M:%S")), pAlarmInfo->level, pAlarmInfo->desc.c_str(), pAlarmInfo->suggest.c_str(), pAlarmInfo->val); if (false == CDBConnectPool::Instance()->DBExecuteSQL(sql)) { CSimpleLog::Error("执行语句失败" + sql); } } } } } } while (pService->m_bWork); } BOOL CResistAlarmMng::LoadAlarmSet() { CString sql = "SELECT [mo],[mp],[no],[type],[conf],[time] FROM [rm_alarm_set]"; COdbcStatement stmt; if (!CDBConnectPool::Instance()->DBQuery(stmt, sql)) { CSimpleLog::Error("执行语句失败" + sql); return FALSE; } for (auto& it : m_alarm_set) { delete it.second; it.second = nullptr; } m_alarm_set.clear(); char mo[51], mp[51], conf[501]; uint8_t no, type; __time64_t time; int nCol = 1; stmt.BindCharCol(nCol++, mo, sizeof(mo)); stmt.BindCharCol(nCol++, mp, sizeof(mp)); stmt.BindTinyIntCol(nCol++, &no); stmt.BindTinyIntCol(nCol++, &type); stmt.BindCharCol(nCol++, conf, sizeof(conf)); stmt.BindBigIntCol(nCol++, &time); do { if (stmt.FetchNext() != 0) break; using namespace rapidjson; int len = strlen(conf); if (len == 0) continue; Document doc; if (doc.Parse(conf, len).HasParseError()) { CSimpleLog::Error(CString("解析数据出错") + conf); continue; } const auto eType = (eZL_ALARMTYPE)type; if (eType == eZL_ALARMTYPE::MAX_OVER_LIMIT) { if (doc.IsArray() == false) { CSimpleLog::Error(CString("conf是非数组") + conf); continue; } SizeType n = doc.Size(); bool enable = false; short alarm_high_limit = MAXSHORT; short warn_high_limit = MAXSHORT; short f_alarm_high_limit = MAXSHORT; short f_warn_high_limit = MAXSHORT; for (SizeType i = 0; i < n; i++) { if (doc[i].HasMember("name") == false || doc[i].HasMember("val") == false || doc[i]["name"].IsString() == false || doc[i]["val"].IsString() == false) { assert(false); continue; } string key = doc[i]["name"].GetString(); string value = doc[i]["val"].GetString(); if (key.compare("enable") == 0) { enable = (value.compare("true") == 0); } else if (key.compare("lock_alarm_high_limit") == 0) { alarm_high_limit = atoi(value.c_str()); } else if (key.compare("lock_warn_high_limit") == 0) { warn_high_limit = atoi(value.c_str()); } else if (key.compare("d_alarm_high_limit") == 0) { alarm_high_limit = atoi(value.c_str()); } else if (key.compare("d_warn_high_limit") == 0) { warn_high_limit = atoi(value.c_str()); } else if (key.compare("f_alarm_high_limit") == 0) { f_alarm_high_limit = atoi(value.c_str()); } else if (key.compare("f_warn_high_limit") == 0) { f_warn_high_limit = atoi(value.c_str()); } else if (key.compare("keep_alarm_high_limit") == 0) { f_alarm_high_limit = atoi(value.c_str()); } else if (key.compare("keep_warn_high_limit") == 0) { f_warn_high_limit = atoi(value.c_str()); } else { assert(0); } } if (alarm_high_limit == MAXSHORT || warn_high_limit == MAXSHORT) continue; auto pInfo = new MAX_OVER_LIMIT_INFO; pInfo->enable = enable; pInfo->no = no; pInfo->type = eType; pInfo->alarm_high_limit = alarm_high_limit; pInfo->warn_high_limit = warn_high_limit; pInfo->f_alarm_high_limit = f_alarm_high_limit; pInfo->f_warn_high_limit = f_warn_high_limit; pInfo->tmLastCheckTime = time; stringstream ss; ss << mo << '.' << mp << '.' << to_string(no) << '.' << to_string(type); m_alarm_set[ss.str()] = pInfo; } else if (eType == eZL_ALARMTYPE::FRICTION_OVER_LIMIT) { if (doc.IsArray() == false) { CSimpleLog::Error(CString("conf是非数组") + conf); continue; } SizeType n = doc.Size(); bool enable = false; int up_alarm_low_limit = INT_MAX; int up_warn_low_limit = INT_MAX; int dw_alarm_high_limit = INT_MIN; int dw_warn_high_limit = INT_MIN; for (SizeType i = 0; i < n; i++) { if (doc[i].HasMember("name") == false || doc[i].HasMember("val") == false || doc[i]["name"].IsString() == false || doc[i]["val"].IsString() == false) { assert(false); continue; } string key = doc[i]["name"].GetString(); string value = doc[i]["val"].GetString(); if (key.compare("enable") == 0) { enable = (value.compare("true") == 0); } else if (key.compare("up_alarm_low_limit") == 0) { up_alarm_low_limit = atoi(value.c_str()); } else if (key.compare("up_warn_low_limit") == 0) { up_warn_low_limit = atoi(value.c_str()); } else if (key.compare("dw_alarm_high_limit") == 0) { dw_alarm_high_limit = atoi(value.c_str()); } else if (key.compare("dw_warn_high_limit") == 0) { dw_warn_high_limit = atoi(value.c_str()); } else { assert(0); } } auto pInfo = new FRICTION_OVER_LIMIT_INFO; pInfo->enable = enable; pInfo->no = no; pInfo->type = eType; pInfo->up_alarm_low_limit = up_alarm_low_limit; pInfo->up_warn_low_limit = up_warn_low_limit; pInfo->dw_alarm_high_limit = dw_alarm_high_limit; pInfo->dw_warn_high_limit = dw_warn_high_limit; pInfo->tmLastCheckTime = time; stringstream ss; ss << mo << '.' << mp << '.' << to_string(no) << '.' << to_string(type); m_alarm_set[ss.str()] = pInfo; } else if (eType == eZL_ALARMTYPE::SUOBI_LOCK_LIMIT) { auto doc = yyjson_read(conf, len, 0); if (doc == nullptr) continue; auto root = yyjson_doc_get_root(doc); auto pInfo = new SUOBI_OVER_LIMIT_INFO; pInfo->type = eZL_ALARMTYPE::SUOBI_LOCK_LIMIT; pInfo->enable = yyjson_get_bool(yyjson_obj_get(root, "enable")); pInfo->alarm_low_limit = yyjson_get_int(yyjson_obj_get(root, "alarm_low_limit")); pInfo->warn_low_limit = yyjson_get_int(yyjson_obj_get(root, "warn_low_limit")); pInfo->alarm_high_limit = yyjson_get_int(yyjson_obj_get(root, "alarm_high_limit")); pInfo->warn_high_limit = yyjson_get_int(yyjson_obj_get(root, "warn_high_limit")); stringstream ss; ss << mo << '.' << mp << '.' << to_string(no) << '.' << to_string(type); m_alarm_set[ss.str()] = pInfo; yyjson_doc_free(doc); } else if (eType == eZL_ALARMTYPE::CONVERT_LIMIT) { auto doc = yyjson_read(conf, len, 0); if (doc == nullptr) continue; auto root = yyjson_doc_get_root(doc); auto pInfo = new CONVERT_RESIST_OVER_LIMIT; pInfo->type = eZL_ALARMTYPE::CONVERT_LIMIT; pInfo->no = 2; pInfo->enable = yyjson_get_bool(yyjson_obj_get(root, "enable")); pInfo->dw_alarm_low_limit = yyjson_get_int(yyjson_obj_get(root, "dw_alarm_low_limit")); pInfo->dw_warn_low_limit = yyjson_get_int(yyjson_obj_get(root, "dw_warn_low_limit")); pInfo->up_alarm_high_limit = yyjson_get_int(yyjson_obj_get(root, "up_alarm_high_limit")); pInfo->up_warn_high_limit = yyjson_get_int(yyjson_obj_get(root, "up_warn_high_limit")); stringstream ss; ss << mo << '.' << mp << '.' << to_string(no) << '.' << to_string(type); m_alarm_set[ss.str()] = pInfo; } else { ASSERT(0); } } while (true); SPDLOG_INFO("一共加载到{}条报警规则:{}", m_alarm_set.size(), sql); return TRUE; } BOOL CResistAlarmMng::LoadAlarmID() { CString sql = "SELECT TOP 1 ID FROM RM_ALARM ORDER BY ID DESC"; COdbcStatement stmt; if (!CDBConnectPool::Instance()->DBQuery(stmt, sql)) { CSimpleLog::Error("执行语句失败" + sql); return FALSE; } int alarm_id; int nCol = 1; stmt.BindIntCol(nCol++, &alarm_id); do { if (stmt.FetchNext() != 0) break; m_nAlarmID = alarm_id; } while (false); stmt.Close(); return TRUE; } BOOL CResistAlarmMng::LoadUnAck() { CString sql = "SELECT [ID],[mo],[mp],[no],[type],[occur_time],[level],[desc],[suggest],[val],[event_id],[rel_id] FROM [rm_alarm] WHERE ack_result = 0 ORDER BY ID;"; COdbcStatement stmt; if (!CDBConnectPool::Instance()->DBQuery(stmt, sql)) { SPDLOG_ERROR("执行语句失败 {}", sql); return FALSE; } char mo[51], mp[51], desc[200], suggest[200], event_id[37] = { 0 }, rel_id[37] = { 0 };; uint8_t no, type, level; short val; int id; TIMESTAMP_STRUCT ts; int nCol = 1; stmt.BindIntCol(nCol++, &id); stmt.BindCharCol(nCol++, mo, sizeof(mo)); stmt.BindCharCol(nCol++, mp, sizeof(mp)); stmt.BindTinyIntCol(nCol++, &no); stmt.BindTinyIntCol(nCol++, &type); stmt.BindTimeStampCol(nCol++, &ts); stmt.BindTinyIntCol(nCol++, &level); stmt.BindCharCol(nCol++, desc, sizeof(desc)); stmt.BindCharCol(nCol++, suggest, sizeof(suggest)); stmt.BindSmallIntCol(nCol++, &val); stmt.BindCharCol(nCol++, event_id, 36); stmt.BindCharCol(nCol++, rel_id, 36); do { if (stmt.FetchNext() != 0) break; ALARM_INFO *pAlarm = new ALARM_INFO; pAlarm->event_id = event_id; if (rel_id[0] != 0x20) pAlarm->rel_id = rel_id; pAlarm->id = id; pAlarm->mo = mo; pAlarm->mp = mp; pAlarm->no = no; pAlarm->type = (eZL_ALARMTYPE)type; pAlarm->time.wYear = ts.year; pAlarm->time.wMonth = ts.month; pAlarm->time.wDay = ts.day; pAlarm->time.wHour = ts.hour; pAlarm->time.wMinute = ts.minute; pAlarm->time.wSecond = ts.second; pAlarm->time.wMilliseconds = ts.fraction; pAlarm->val = val; pAlarm->level = level; pAlarm->desc = desc; pAlarm->suggest = suggest; m_lstUnConfirmAlarm.push_back(pAlarm); } while (true); stmt.Close(); SPDLOG_INFO("一共加载({})条未处理报警", m_lstUnConfirmAlarm.size()); return TRUE; }