瀏覽代碼

fix alarm

zhuyf 2 年之前
父節點
當前提交
0051c3d4a0
共有 10 個文件被更改,包括 296 次插入27 次删除
  1. 16 1
      ant.cpp
  2. 2 1
      card_base.cpp
  3. 75 0
      card_car.cpp
  4. 5 2
      card_car.h
  5. 1 1
      common.h
  6. 165 20
      event.cpp
  7. 4 0
      event.h
  8. 18 0
      module_service/module_call.cpp
  9. 4 1
      module_service/module_traffic_light_manager.cpp
  10. 6 1
      module_service/module_web.cpp

+ 16 - 1
ant.cpp

@@ -245,6 +245,21 @@ std::vector<point> ant::getsol(const double &dist) const
 	return std::move(v);
 }
 
+/*	@brief
+ *		基站失联告警,超时阈值为30秒
+ *		采集在30秒内未收到基站(含通信基站和定位基站)数据,产生基站失联告警
+ *		采集收到了基站心跳数据,结束基站失联告警;
+ *		就在本方法内实现上述逻辑
+ *		逻辑和红绿灯失联告警一样
+ *	@param
+ *		std::shared_ptr<site> s		基站对象
+ *	@return
+ *		执行成功返回true
+ *	@note
+ *	@warning
+ *	@bug
+ *
+ * */
 bool visit_site_status::visit(std::shared_ptr<site> s)
 {
 	time_t now = time(0);
@@ -1111,6 +1126,6 @@ void sit_list_v::init_site(const std::string &ids /*= ""*/)
 		DBRes.GetField("plus_occur_time", ctx, Error);
 		site_ptr->m_coverage[1].m_time = tool_time::to_time(ctx);
 
-		log_info("site_position: site=%d, x=%.2lf, y=%.2lf, area_id=%d, m_scale=%.2f, pdoa_offset=%.2f, pdoa_direction=%d, special=%d, device_type_id=%d, plus_dist=%.2f, minus_dist=%.2f", reader_id, x, y, area_id, scale, offset, direction, special, device_type_id, site_ptr->m_coverage[0].m_distance, site_ptr->m_coverage[1].m_distance);
+		log_info("site_position: site=%d, x=%.2lf, y=%.2lf, pdoa_offset=%.2f, pdoa_direction=%d, special=%d, device_type_id=%d, plus_dist=%.2f, minus_dist=%.2f", reader_id, x, y, offset, direction, special, device_type_id, site_ptr->m_coverage[0].m_distance, site_ptr->m_coverage[1].m_distance);
 	}
 }

+ 2 - 1
card_base.cpp

@@ -206,8 +206,9 @@ void card_location_base::on_location(const std::vector<point>&vp, const std::vec
 		log_info("[help-battery] card_id=%d, battery=%d, val=%d", m_id, m_battery_value, val);
 		do_status(val);
 
+		// 只有车辆定位点的数据才会判断超速
 		if (is_vehicle())
-		{
+		{	
 			if (m_stat_last == ENUM_STATUS_BACK)
 			{
 				m_stat = ENUM_STATUS_BACK;

+ 75 - 0
card_car.cpp

@@ -23,6 +23,7 @@ car::car(const std::string&type,uint32_t cardid,uint16_t needdisplay,int16_t t,i
 	 ,m_vehicle_type_id(type_id)
 {
 	m_message_handle.reset(new card_message_handle(this));
+	m_speeds.set_capacity(30);
 	//m_his_location_card.reset(new location_vehicle(m_id,m_type,cid));
 }
 
@@ -50,6 +51,60 @@ void car::do_business(const std::shared_ptr<site>&site,const point &pt,double ac
     }
 	uint64_t id=tool_other::type_id_to_u64(m_type,m_id);
 	mine_business::inst()->make_arg(id,pt,m_time);
+
+	//超速告警业务
+	handle_over_speed();
+}
+
+/*
+ *	@brief
+ *		超速告警,频率为1hz,定位一秒一次;
+ *		开始:连续30个定位点超过35km认为开始超速告警
+ *		结束:连续10个定位点小于35km认为结束超速告警
+ *	@param
+ *		无
+ *	@return
+ *	@note
+ *	@warning
+ *	@bug
+ * */
+void car::handle_over_speed()
+{
+	// 超速告警,频率为1hz,定位一秒一次;
+	// 开始:连续30个定位点超过35km认为开始超速告警
+	// 结束:连续10个定位点小于35km认为结束超速告警			
+	m_speeds.push_back(m_speed);
+
+	bool status = true;
+	if(m_speed.size() < 30){
+		status = false;
+	}else{
+		for(size_t i = 0;i < m_speeds.size();i++){
+			if(v < 35){
+				status = false;
+			}
+		}
+	}
+
+	if(status){
+		// 产生告警
+		event_tool::instance()->handle_event(OT_CARD, ET_CARD_OVER_SPEED, id, 0, 0, status);
+	}
+
+	status = true;
+	if(m_speed.size() == 30){
+		for(size_t i = 20;i < m_speeds.size();i++){
+			if(v>35){
+				status = false;
+			}
+		}
+		if(status){
+			// 结束告警
+			event_tool::instance()->handle_event(OT_CARD, ET_CARD_OVER_SPEED, id, 0, 0, false);
+		}
+	}
+	
+	
 }
 
 int car::get_vehicle_type_id()
@@ -57,6 +112,26 @@ int car::get_vehicle_type_id()
 	return m_vehicle_type_id;
 }
 
+/*
+ * @brief 
+ *		车辆防碰撞判断
+ *		车辆定位后,检查车辆附近(根据防碰撞的三个档位距离阈值)是否有人,有人则产生防碰撞告警
+ *		如果车辆在距离最大档位内没人,则结束告警;
+ *		以车为单位,通知web端,进入一档二档三挡会将三个档位每个档位有多少人通知web端,
+ *		当人从一档变为二档也会将人档位的变化发送给web端;
+ *		发送告警的级别会根据档位的变化动态变化;产生一条告警
+ *		允许重复发送
+ *		在本方法中实现上述逻辑;
+ * @param
+ *		const point& pt		车辆定位位置
+ *		const int& sid		
+ * @return
+ *		无
+ * @note
+ * modified by zhuyf,2022-04-24
+ * @warning
+ * @bug
+ * */
 void car::handle_anti_coll(const point& pt, const int& sid)
 {
     // 车卡下发最紧急的呼叫类型

+ 5 - 2
card_car.h

@@ -15,8 +15,10 @@ struct loc_point;
 
 struct car:card_location_base,card_area
 {
-	int m_vehicle_category_id=0;
-    int m_vehicle_type_id=0;
+	int m_vehicle_category_id = 0;
+    int m_vehicle_type_id = 0;
+
+	boost::circular_buffer<double> m_speeds;
 public:
 
     car(const std::string&type,uint32_t cardid,uint16_t needdisplay,int16_t t,int32_t deptid,
@@ -43,6 +45,7 @@ private:
 	void handle_three_rates(const point &pt);
     void handle_traffic_light(const point& pt, const int& sid);
     void handle_anti_coll(const point& pt, const int& sid);
+	void handle_over_speed();
 	void on_timer();
 	void make_package();
 	loc_point getSmoothPoint();

+ 1 - 1
common.h

@@ -3,7 +3,7 @@
 
 #define LENGTH_SQL 2000
 #define SPEED_COUNT_LIMIT 5
-#define READER_TIMEOUT 20
+#define READER_TIMEOUT 30
 #define LIGHT_TIMEOUT  30
 #define PI 3.1415926
 #define TPI (2*3.1415926)

+ 165 - 20
event.cpp

@@ -72,6 +72,19 @@ event_tool * event_tool::instance()
 {
     return &et;
 }
+
+/*
+ *	@brief
+ *		告警分类:一人带多卡告警、区域告警、基站告警、卡告警、红绿灯告警
+ *	@param
+ *		无
+ *	@return
+ *		无
+ *	@note
+ *	@warning
+ *	@bug
+ *
+ * */
 void event_tool::make_event_object()
 {
     m_map[OT_MORE_CARD] = std::make_shared<mine_event>();
@@ -81,7 +94,7 @@ void event_tool::make_event_object()
     m_map[OT_DEVICE_LIGHT] = std::make_shared<light_event>();
 }
 
-void event_tool::handle_event(OBJECT_TYPE ot,EVENT_TYPE et,uint64_t id,double limit_value,double cur_value,bool f,EVENT_DIS_TYPE edt/*=DT_COMMON*/,const std::string &desc/*=""*/)
+void event_tool::handle_event(OBJECT_TYPE ot, EVENT_TYPE et, uint64_t id, double limit_value, double cur_value, bool f, EVENT_DIS_TYPE edt/*=DT_COMMON*/, const std::string &desc/*=""*/)
 {
     m_map[ot]->handle_alarm_event(et,id,limit_value,cur_value,f,edt,desc);
 }
@@ -96,7 +109,11 @@ std::shared_ptr<ya_event> Event::create_event(const std::string&obj_id,EVENT_TYP
 }
 
 /*
- * @breif		构建开始或者取消告警事件
+ * @breif		构建开始或者取消告警事件,
+ * 告警事件入口,生成事件对象,保存在内存中。
+ * end_time为零表示开始
+ * start_time为零表示结束
+ * 事件的唯一根据id判断。
  * @param		EVENT_TYPE et			事件设备类型
  * @param		uint64_t id
  * @param		double limit_value		阈值
@@ -109,10 +126,11 @@ std::shared_ptr<ya_event> Event::create_event(const std::string&obj_id,EVENT_TYP
  * @bug
  * @warning
  * */
-void Event::handle_alarm_event(EVENT_TYPE et,uint64_t id,double limit_value,double cur_value,bool f,EVENT_DIS_TYPE edt,const std::string &desc)
+void Event::handle_alarm_event(EVENT_TYPE et, uint64_t id, double limit_value, double cur_value, bool f, EVENT_DIS_TYPE edt, const std::string &desc)
 {
     std::shared_ptr<ya_event> ev_ptr = nullptr;
-    uint64_t eid = event_list::to_list_id(et,m_oid,id,edt);
+    uint64_t eid = event_list::to_list_id(et, m_oid, id, edt);
+	//eid是告警的唯一id,如果存在,查找eid来找到的已经存在的事件
     auto event_ptr = event_list::instance()->get(eid);
     if(f)
     {
@@ -125,27 +143,27 @@ void Event::handle_alarm_event(EVENT_TYPE et,uint64_t id,double limit_value,doub
         }
         else
         {
-            uint64_t _id=id;
+            uint64_t _id = id;
             //log_info("Create_Event:desc[%s],id:%d,et:%d",desc.c_str(),id,et);
             if((et == ET_UWB_MORE_CARD||et == ET_VEHICLE_REAR_END) && !desc.empty())//防追尾告警特殊处理
             {
-                std::string cardid = desc.substr(0,desc.find_first_of('&'));
+                std::string cardid = desc.substr(0, desc.find_first_of('&'));
                 _id = tool_other::card_id_to_u64(cardid);
             }
-            ev_ptr=on_message(et,_id,f);
+            ev_ptr = on_message(et,_id,f);
             if(ev_ptr){
-                ev_ptr->m_cur_value=cur_value;
-                ev_ptr->m_limit_value=limit_value;
-                ev_ptr->m_desc=desc;
-                ev_ptr->m_id=eid;
-                ev_ptr->m_dis_type=edt;
-                if(et == ET_VEHICLE_REAR_END||et==ET_UWB_MORE_CARD)//一人多卡特殊处理
+                ev_ptr->m_cur_value = cur_value;
+                ev_ptr->m_limit_value = limit_value;
+                ev_ptr->m_desc = desc;
+                ev_ptr->m_id = eid;
+                ev_ptr->m_dis_type = edt;
+                if(et == ET_VEHICLE_REAR_END|| et == ET_UWB_MORE_CARD)//一人多卡特殊处理
                 {
-                    ev_ptr->m_obj_id=desc;
+                    ev_ptr->m_obj_id = desc;
                     //ev_ptr->m_cur_time=std::chrono::system_clock::time_point(std::chrono::milliseconds((time_t)limit_value * 1000));
                 }
                 //保存告警信息
-                event_list::instance()->add(eid,ev_ptr);
+                event_list::instance()->add(eid, ev_ptr);
             }
         }
     }
@@ -157,14 +175,26 @@ void Event::handle_alarm_event(EVENT_TYPE et,uint64_t id,double limit_value,doub
             event_ptr->m_cur_time = std::chrono::system_clock::now();
             event_ptr->m_status = ES_END;
             event_ptr->m_cur_value = cur_value;
-            event_ptr->m_desc=desc;
-            event_ptr->m_is_sent=false;
+            event_ptr->m_desc = desc;
+            event_ptr->m_is_sent = false;
             ev_ptr=event_ptr;
         }
     }
-    if(ev_ptr)
+    
+	if(ev_ptr)
     {
-        event_list::save_event(ev_ptr);
+        //event_list::save_event(ev_ptr);
+		//基站失联告警:人员和车辆都要有
+		if(ev_ptr->m_ev_type == 6){
+			event_list::save_event(ev_ptr);
+			event_list::save_event_v(ev_ptr);
+		}else if(ev_ptr->m_ev_type == 8 || ev_ptr->m_ev_type == 21 || ev_ptr->m_ev_type == 41){
+			// 红绿灯失联、人车防碰撞、超速告警这三类保存到his_event_data_v表中
+			event_list::save_event_v(ev_ptr);
+		}else{
+			//其他的人员相关报警保存到his_event_data表中
+			event_list::save_event(ev_ptr);
+		}
     }
 }
 
@@ -307,6 +337,36 @@ void event_list::save_event(const std::shared_ptr<ya_event> &ev_ptr)
     db_tool::PushAsync(sql);
 }
 
+/*
+ *	@brief
+ *		保存告警事件
+ *	@param
+ *		const std::shared_ptr<ya_event>& ev_ptr		告警对象
+ *		int type									告警开始结束标志,开始为0,结束为1
+ *	@return
+ *		无
+ *	@note
+ *	@warning
+ *	@bug
+ * */
+void event_list::save_event_v(const std::shared_ptr<ya_event> &ev_ptr)
+{
+    char sql[LENGTH_SQL] = {0};
+    std::string _time = tool_time::to_str_ex(ev_ptr->m_cur_time);
+	switch(ev_ptr->m_status){
+		case 0:
+			sprintf(sql, "INSERT IGNORE INTO his_event_data_v(id, event_type_id, obj_id, x, y ,start_time) VALUES(%ld, %d, '%s', %.2f, %.2f, '%s');",
+					ev_ptr->m_ev_id, ev_ptr->m_ev_type, ev_ptr->m_obj_id.c_str(), ev_ptr->x, ev_ptr->y, _time.c_str());
+			break;
+		case 100:
+			sprintf(sql, "update his_event_data_v set end_time='%s' where id=%ld;", _time.c_str(), ev_ptr->m_ev_id);
+			break;
+	}
+    
+	db_tool::PushAsync(sql);
+}
+
+
 void event_list::load_his_data_from_db(bool init /*=true*/)
 {
     static std::time_t s_last_time=0;
@@ -315,7 +375,8 @@ void event_list::load_his_data_from_db(bool init /*=true*/)
         if(t-s_last_time<15)return;
         s_last_time=t;
     }
-    std::unordered_map<uint64_t, std::shared_ptr<ya_event>> map;
+    
+	std::unordered_map<uint64_t, std::shared_ptr<ya_event>> map;
     std::string sql("SELECT event_id, id,stat,event_type_id,obj_type_id,obj_id,dis_type,map_id,area_id,\
             limit_value,cur_value,x,y, cur_time FROM his_event_data \
             WHERE event_id IN (SELECT MAX(event_id) FROM his_event_data \
@@ -460,6 +521,17 @@ void event_list::load_his_data_from_db(bool init /*=true*/)
     }
 }
 
+/*
+ *	@brief
+ *		事件转为json
+ *	@param
+ *		std::vector<std::shared_ptr<ya_event>> arr		事件列表
+ *	@return
+ *		json字符串
+ *	@note
+ *	@warning
+ *	@bug
+ * */
 std::string event_list::evs_to_json(std::vector<std::shared_ptr<ya_event>> arr)
 {
     rapidjson::Document doc(rapidjson::kObjectType);
@@ -483,6 +555,40 @@ std::string event_list::evs_to_json(std::vector<std::shared_ptr<ya_event>> arr)
     return sb.GetString();
 }
 
+/*
+ *	@brief
+ *		构造alarm的json字符串
+ *	@param
+ *		std::vector<std::shared_ptr<ya_event>> arr	告警事件列表
+ *	@return
+ *		alarm的json字符串
+ *	@note
+ *	@warning
+ *	@bug
+ *
+ * */
+std::string event_list::evs_to_json_v(std::vector<std::shared_ptr<ya_event>> arr)
+{
+    rapidjson::Document doc(rapidjson::kObjectType);
+    rapidjson::Value data(rapidjson::kArrayType);
+    rapidjson::Document::AllocatorType& allocator=doc.GetAllocator();
+
+    auto it=arr.begin();
+    for(;it!=arr.end();++it)
+    {
+        _ev_to_node_v(*it, allocator, data);
+    }
+
+    doc.AddMember(JSON_ROOT_KEY_CMD, "alarm", allocator);
+    doc.AddMember(JSON_ROOT_KEY_DATA, data, allocator);
+
+    rapidjson::StringBuffer sb;
+    rapidjson::Writer<rapidjson::StringBuffer> writer(sb);
+    doc.Accept(writer);
+
+    return sb.GetString();
+}
+
 void event_list::_ev_to_node(std::shared_ptr<ya_event> ev_ptr,
                              rapidjson::Document::AllocatorType& allocator,
                              rapidjson::Value& out_data)
@@ -510,4 +616,43 @@ void event_list::_ev_to_node(std::shared_ptr<ya_event> ev_ptr,
     out_data.PushBack(ev, allocator);
 }
 
+/*
+ * @brief
+ *		构造每个具体告警的数据
+ * @param
+ *		std::shared_ptr<ya_event> ev_ptr				//告警对象
+ *		rapidjson::Document::AllocatorType& allocator	//json的allocator
+ *		rapidjson::Value& out_data						//输出的json value对象
+ * @return
+ * @note
+ * @warning
+ * @bug
+ * */
+void event_list::_ev_to_node_v(std::shared_ptr<ya_event> ev_ptr,
+                             rapidjson::Document::AllocatorType& allocator,
+                             rapidjson::Value& out_data)
+{
+    rapidjson::Value ev(rapidjson::kObjectType);
+
+    //ev.AddMember(JSON_KEY_EVENT_EVENT_ID,ev_ptr->m_id, allocator);
+    tool_json::add_member(ev, JSON_KEY_EVENT_EVENT_ID, std::to_string(ev_ptr->m_id), allocator);
+    ev.AddMember(JSON_KEY_EVENT_TYPE_ID,ev_ptr->m_ev_type, allocator);
+
+    tool_json::add_member(ev, JSON_KEY_EVENT_OBJ_ID, ev_ptr->m_obj_id, allocator);
+    ev.AddMember(JSON_KEY_EVENT_X,ev_ptr->x, allocator);
+    ev.AddMember(JSON_KEY_EVENT_Y,ev_ptr->y, allocator);
+
+	switch(ev_ptr->m_status){
+		case 0:
+			ev.AddMember("start_time", tool_time::to_ms(ev_ptr->m_cur_time), allocator);
+			break;
+		case 100:
+			ev.AddMember("end_time", tool_time::to_ms(ev_ptr->m_cur_time), allocator);
+			break;
+	}
+    
+	out_data.PushBack(ev, allocator);
+}
+
+
 //template<> std::shared_ptr<event_list> single_base<event_list, uint64_t, std::shared_ptr<ya_event>>::m_instance=std::make_shared<event_list>();

+ 4 - 0
event.h

@@ -130,6 +130,7 @@ public:
     }
 
     static void save_event(const std::shared_ptr<ya_event> &event_ptr);
+	static void save_event_v(const std::shared_ptr<ya_event>& event_ptr);
 
     void load_his_data_from_db(bool init=true);
 
@@ -142,6 +143,9 @@ public:
         return evs_to_json(evs);
     }
 
+	static std::string evs_to_json_v(std::vector<std::shared_ptr<ya_event>> arr);
+	static void _ev_to_node_v(std::shared_ptr<ya_event> ev_ptr, rapidjson::Document::AllocatorType& allocator, rapidjson::Value& out_data);
+
     static std::string evs_to_json(std::vector<std::shared_ptr<ya_event>> arr);
 private:
     static void _ev_to_node(std::shared_ptr<ya_event> ev_ptr,

+ 18 - 0
module_service/module_call.cpp

@@ -793,9 +793,27 @@ void module_call::system_cancel_call_apoint(int card_id,int card_type)
 
 /*
  * @brief       发送防碰撞告警
+ * 发送方:采集
+ * 接收方:gis-server
+ * 场景1:开始和结束都调用此send
+ * 数据接口样例:
+ *{
+	"cmd":"alarm",		// 命令字, 4种类型的告警:基站通信异常、红绿灯通信异常、人车防碰撞、车辆超速
+	"data":[{
+		"event_id":1122334423321	// 告警id,唯一性
+		"type_id": 1,	//告警类型,4种类型的一种	
+		"obj_id":"0010000001001", // obj_id为车辆号、基站号,人车防碰撞时,车号[人卡号,...人卡号]
+		"x":0.1, //告警发生的位置
+		"y":0.2, //告警发生的位置 
+		"start_time": 17890234234234,	// 触发时间
+		"end_time":						// 结束时间
+		},......]
+	}
+
  * @param       const std::map<int, call_card>& cards       key为车id,val为人卡信息
  * @return
  * @note
+ *		modify zhuyf, 2022-04-24
  * @warning
  * @bug
  *

+ 4 - 1
module_service/module_traffic_light_manager.cpp

@@ -690,10 +690,13 @@ std::string traffic_light_manager::get_light_state()
 }
 
 /*
- * @brief       红绿灯通信异常告警
+ * @brief       红绿灯失联告警, 红绿灯超过30秒未收到心跳数据产生红绿灯失联告警
+ * 如果采集在30秒内未收到红绿灯的心跳数据,产生红绿灯失联告警;(告警id+start_time)
+ * 采集收到了红绿灯心跳数据,结束红绿灯失联告警(告警id+end_time)
  * @param       无
  * @return      无
  * @note
+ * modified by zhuyf, 2022-04-22
  * @warning
  * @bug
  * */

+ 6 - 1
module_service/module_web.cpp

@@ -111,6 +111,7 @@ void module_web::response_login()
     if(!arr.empty())
     {
         tool_json::push_back(nodes, event_list::evs_to_json(arr), allocator);
+		tool_json::push_back(nodes, event_list::evs_to_json_v(arr), allocator);
     }
 
     //所有红绿灯信息
@@ -136,7 +137,8 @@ void module_web::response_login()
 }
 
 /*
- * @brief   构造事件列表,并发送给请求端
+ * @brief   构造事件列表,并发送给web端
+ * 将所有事件包括:红绿灯失联、基站失联、超速、人车防碰撞告警发送给web端
  * @param   无
  * @return  无
  * @note
@@ -154,6 +156,9 @@ void module_web::run()
 
         std::string tmp = event_list::evs_to_json(arr);
         swsClientMgr.send(JSON_CMD_VALUE_PUSH, tmp);
+
+		tmp = event_list::evs_to_json_v(arr);
+		swsClientMgr.send(JSON_CMD_VALUE_PUSH, tmp);
     }
 
     // 向web端发送呼救数据