diff --git a/2025-01-21 14-42-00.mkv b/2025-01-21 14-42-00.mkv new file mode 100644 index 0000000..e5fc70a --- /dev/null +++ b/2025-01-21 14-42-00.mkv Binary files differ diff --git a/2025-01-21 14-42-00.mkv b/2025-01-21 14-42-00.mkv new file mode 100644 index 0000000..e5fc70a --- /dev/null +++ b/2025-01-21 14-42-00.mkv Binary files differ diff --git a/2025-02-25 15-25-48.mkv b/2025-02-25 15-25-48.mkv new file mode 100644 index 0000000..d978d93 --- /dev/null +++ b/2025-02-25 15-25-48.mkv Binary files differ diff --git a/2025-01-21 14-42-00.mkv b/2025-01-21 14-42-00.mkv new file mode 100644 index 0000000..e5fc70a --- /dev/null +++ b/2025-01-21 14-42-00.mkv Binary files differ diff --git a/2025-02-25 15-25-48.mkv b/2025-02-25 15-25-48.mkv new file mode 100644 index 0000000..d978d93 --- /dev/null +++ b/2025-02-25 15-25-48.mkv Binary files differ diff --git a/2025-02-26 08-49-39.mkv b/2025-02-26 08-49-39.mkv new file mode 100644 index 0000000..255af95 --- /dev/null +++ b/2025-02-26 08-49-39.mkv Binary files differ diff --git a/2025-01-21 14-42-00.mkv b/2025-01-21 14-42-00.mkv new file mode 100644 index 0000000..e5fc70a --- /dev/null +++ b/2025-01-21 14-42-00.mkv Binary files differ diff --git a/2025-02-25 15-25-48.mkv b/2025-02-25 15-25-48.mkv new file mode 100644 index 0000000..d978d93 --- /dev/null +++ b/2025-02-25 15-25-48.mkv Binary files differ diff --git a/2025-02-26 08-49-39.mkv b/2025-02-26 08-49-39.mkv new file mode 100644 index 0000000..255af95 --- /dev/null +++ b/2025-02-26 08-49-39.mkv Binary files differ diff --git a/scene_handler/zyn_limit_space_scene_handler.py b/scene_handler/zyn_limit_space_scene_handler.py index 1d243fa..e300098 100644 --- a/scene_handler/zyn_limit_space_scene_handler.py +++ b/scene_handler/zyn_limit_space_scene_handler.py @@ -41,6 +41,16 @@ 'logtime': '2025-01-14 15:40:49', 'o2': '15.90', 'uptime': '2026-01-14 15:40:52'}}, {"data":{'ch4': '0.00', 'co': '0.00', 'h2s': '0.00', 'id': '142913', 'logtime': '2025-01-14 15:40:49', 'o2': '15.90', 'uptime': '2026-01-14 15:40:53'}}, + {"data": {'ch4': '0.00', 'co': '0.00', 'h2s': '0.00', 'id': '142913', + 'logtime': '2025-01-14 15:40:49', 'o2': '15.90', 'uptime': '2026-01-14 15:40:53'}}, + {"data": {'ch4': '0.00', 'co': '0.00', 'h2s': '0.00', 'id': '142913', + 'logtime': '2025-01-14 15:40:49', 'o2': '15.90', 'uptime': '2026-01-14 15:40:53'}}, + {"data": {'ch4': '0.00', 'co': '0.00', 'h2s': '0.00', 'id': '142913', + 'logtime': '2025-01-14 15:40:49', 'o2': '15.90', 'uptime': '2026-01-14 15:40:53'}}, + {"data": {'ch4': '0.00', 'co': '0.00', 'h2s': '0.00', 'id': '142913', + 'logtime': '2025-01-14 15:40:49', 'o2': '15.90', 'uptime': '2026-01-14 15:40:53'}}, + {"data": {'ch4': '0.00', 'co': '0.00', 'h2s': '0.00', 'id': '142913', + 'logtime': '2025-01-14 15:40:49', 'o2': '15.90', 'uptime': '2026-01-14 15:40:53'}}, ] value_iterator = create_value_iterator(fake_list) @@ -89,7 +99,44 @@ return data - +ALARM_DICT = { + 'hat_and_mask': { + 'alarmType': '11', + 'alarmContent': '未佩戴呼吸防护设备', + 'alarmSoundMessage': b'\xaa\x01\x00\x93\x12\x00\xA6', + 'label': '未佩戴呼吸防护设备' + }, + 'no_jiandu': { + 'alarmType': '12', + 'alarmContent': '没有监护人员', + 'alarmSoundMessage': b'\xaa\x01\x00\x93\x12\x00\xA6', + 'label': '没有监护人员' + }, + 'break': { + 'alarmType': '3', + 'alarmContent': '非法闯入', + 'alarmSoundMessage': b'\xaa\x01\x00\x93\x00\x00\x94', + 'label': '非法闯入' + }, + 'smoke': { + 'alarmType': '6', + 'alarmContent': '吸烟', + 'alarmSoundMessage': b'\xaa\x01\x00\x93\x03\x00\x97', + 'label': '吸烟' + }, + 'no_blower': { + 'alarmType': '13', + 'alarmContent': '没有检测到通风设备', + 'alarmSoundMessage': b'\xaa\x01\x00\x93\x1A\x00\xAE', + 'label': '没有检测到通风设备' + }, + 'no_extinguisher': { + 'alarmType': '14', + 'alarmContent': '没有检测到灭火器', + 'alarmSoundMessage': b'\xaa\x01\x00\x93\x1B\x00\xAF', + 'label': '没有检测到灭火器' + } +} @@ -101,8 +148,9 @@ class EventController(): def __init__(self): - self.cancel_event = asyncio.Event() + self.timeout_event = asyncio.Event() self.umd_complete = asyncio.Event() + self.qianzhi_check_complete = asyncio.Event() self.laobao_complete = asyncio.Event() class SiHeYi(): @@ -308,11 +356,12 @@ :return: None ''' for pred_label in pred_labels: - # print(f"检测到{pred_label}") + print(f"检测到{pred_label}") self.target_flag[pred_label] = True self.jiaodi_flag = jiaodi_flag if self.jiaodi_flag == False and jiaodi_flag ==True: - self.alarm.addAlarm("-------检测到交底") + print(f"劳保检测:检测到交底") + self.alarm.addAlarm("-------劳保检测:检测到交底") def model_predict_fake(self, video_path): cap = cv2.VideoCapture(video_path) @@ -320,9 +369,7 @@ try: ret, frames = cap.read() frames = [frames] - # self.addLog(self.laobao_pool, datetime.now().strftime("%H:%M:%S"), "读取帧") if not ret: - # self.addLog(self.laobao_pool, datetime.now().strftime("%H:%M:%S"), "读取视频结束,退出") break # cv2.namedWindow("Video Frame", cv2.WINDOW_AUTOSIZE) # cv2.resizeWindow('Video Frame', 800, 600) # 宽度800像素,高度600像素 @@ -336,7 +383,7 @@ if cv2.waitKey(1) & 0xFF == ord('q'): break - if self.eventController != None and self.eventController.cancel_event.is_set(): # 超时退出 + if self.eventController != None and self.eventController.timeout_event.is_set(): # 超时退出 cap.release() cv2.destroyAllWindows() return @@ -352,21 +399,19 @@ if self.getUndetectedTarget() == []: # 如果全部检验到了 # print("劳保物品 通过") # self.addLog(self.laobao_pool, datetime.now().strftime("%H:%M:%S"), f"劳保物品 通过") - self.alarm.addAlarm("-------劳保物品 通过") + self.alarm.addAlarm("-------劳保检测:劳保物品 通过") self.eventController.laobao_complete.set() cap.release() cv2.destroyAllWindows() return # 退出检测 else: # 如果还有未检测到的 - undetectedTargets = self.getUndetectedTarget() - # print(f"报警:劳保物品缺失:{wrong_class_list}") - self.alarm.addAlarm(f"-------报警:劳保物品缺失:{undetectedTargets[0]}") + self.alarm.addAlarm(f"-------报警:劳保检测:劳保物品缺失:{undetectedTargets[0]}") cap.release() cv2.destroyAllWindows() def model_predict(self, stream_loader): for frames in stream_loader: # type : list (4),连续的4帧 - if self.eventController != None and self.eventController.cancel_event.is_set(): # 超时退出 + if self.eventController != None and self.eventController.timeout_event.is_set(): # 超时退出 return # 构造 要检测目标的 id_list(把之前检测的目标 从 要检测目标的集合移出) jiaodi_flag = self.predict_isJiaodi(frames) # bool, 检测 新收集的这几帧有无交底 @@ -379,28 +424,19 @@ if self.getUndetectedTarget() == []: # 如果全部检验到了 # print("劳保物品 通过") # self.addLog(self.laobao_pool, datetime.now().strftime("%H:%M:%S"), f"劳保物品 通过") - self.alarm_list.append("劳保物品 通过") + self.alarm.addAlarm(f"劳保检测:劳保物品 通过") self.eventController.laobao_complete.set() return # 退出检测 else: # 如果还有未检测到的 undetectedTargets = self.getUndetectedTarget() - # print(f"报警:劳保物品缺失:{wrong_class_list}") - - for undetectedTarget in undetectedTargets: - alarm_content = f"报警:劳保物品缺失:{undetectedTarget}" - if alarm_content not in self.alarm_list: # 不加入 重复的报警内容 - self.alarm_list.append(alarm_content) - # self.addLog(self.laobao_pool, datetime.now().strftime("%H:%M:%S"), - # f"报警:劳保物品缺失:{undetectedTarget}") - # self.alarm_list.remove(f"报警:劳保物品缺失:{wrong_class}") # 对于同样内容的报警,删除 早的报警 - # self.alarm_list.append(f"报警:劳保物品缺失:{wrong_class}") # 保留新的报警 + self.alarm.addAlarm(f"-------报警:劳保检测:劳保物品缺失:{undetectedTargets[0]}") class YinHuanCheck(): - def __init__(self, eventController=None, alarm_list=None): + def __init__(self, eventController=None, alarm=None): self.model = YOLO("weights/yinhuan.pt") self.eventController = eventController - self.alarm_list = alarm_list + self.alarm = alarm self.anquanmao_tolerate = [] @@ -445,20 +481,20 @@ :return: ''' for person_result in person_targets: # 每个人身上的物件 - if "吸烟" in person_result: + if "烟头" in person_result: # 有一个人抽烟 return False # 没有通过吸烟检测 return True # 通过吸烟检测 def judge_xiubiao(self, person_targets): ''' - 判定有没有 吸烟的人 + 判定有没有 袖标的人 param person_targets: [[label1,label2..], [label1...]] 每个人身上的目标 :return: ''' for person_result in person_targets: # 每个人身上的物件 - if "吸烟" in person_result: - return False # 没有通过吸烟检测 - return True # 通过吸烟检测 + if "袖标" in person_result: # 有一个人带袖标就通过 + return True # 通过袖标检测 + return False # 没有通过袖标检测 def judge_dadianhua(self, person_targets): ''' 判定有没有 打电话的人 @@ -466,10 +502,9 @@ :return: ''' for person_result in person_targets: # 每个人身上的物件 - if "打电话" in person_result: + if "电话" in person_result: # 有一个人打电话 return False # 没有通过打电话检测 return True # 通过打电话检测 - def judge_xianzaren(self, person_targets): ''' 判定有没有 打电话的人 @@ -500,10 +535,10 @@ return result def isAlarm(self): - def has_consecutive_true(bool_list, threshold=30): + def has_consecutive_false(bool_list, threshold=20): count = 0 # 计数器,用于记录连续 True 的次数 for value in bool_list: - if value: # 如果当前值为 True + if value == False: # 如果当前值为 False count += 1 # 增加计数器 if count > threshold: # 如果计数器超过阈值 return True @@ -511,11 +546,24 @@ count = 0 # 重置计数器 return False # 遍历完成后没有发现连续超过 threshold 次的 True - if has_consecutive_true(self.anquanmao_tolerate) == True: + if has_consecutive_false(self.anquanmao_tolerate) == True and self.alarm != None: self.anquanmao_tolerate.clear() - # print("安全帽报警") + self.alarm.addAlarm("-------报警:未带安全帽") + if has_consecutive_false(self.xiyan_tolerate) == True and self.alarm != None: + self.xiyan_tolerate.clear() + self.alarm.addAlarm("-------报警:吸烟") + if has_consecutive_false(self.xiubiao_tolerate) == True and self.alarm != None: + self.xiubiao_tolerate.clear() + self.alarm.addAlarm("-------报警:袖标") + if has_consecutive_false(self.dadianhua_tolerate) == True and self.alarm != None: + self.dadianhua_tolerate.clear() + self.alarm.addAlarm("-------报警:打电话") + + if has_consecutive_false(self.xianzaren_tolerate) == True and self.alarm != None: + self.xianzaren_tolerate.clear() + self.alarm.addAlarm("-------报警:闲杂人") def detect_person_targets(self,person_crops): ''' @@ -537,14 +585,10 @@ cap = cv2.VideoCapture(video_path) ret, frames = cap.read() while True: - # for frames in self.stream_loader: # type : list (4),连续的4帧 try: ret, frames = cap.read() - print(f"读取帧{ret}") frames = [frames] - # self.addLog(self.laobao_pool, datetime.now().strftime("%H:%M:%S"), "读取帧") if not ret: - # self.addLog(self.laobao_pool, datetime.now().strftime("%H:%M:%S"), "读取视频结束,退出") cap.release() cv2.destroyAllWindows() break @@ -560,8 +604,11 @@ break people_results = self.detect_person(frames) # 检测人 person_detect_targets = self.detect_person_targets(people_results) - print(person_detect_targets) self.anquanmao_tolerate.append(self.judge_anquanmao(person_detect_targets)) + self.xiubiao_tolerate.append(self.judge_xiubiao(person_detect_targets)) + self.xiyan_tolerate.append(self.judge_xiyan(person_detect_targets)) + self.xianzaren_tolerate.append(self.judge_xianzaren(person_detect_targets)) + self.dadianhua_tolerate.append(self.judge_dadianhua(person_detect_targets)) self.isAlarm() def main(self, stream_loader): @@ -569,14 +616,30 @@ people_results = self.detect_person(frames) # 检测人 person_detect_targets = self.detect_person_targets(people_results) self.anquanmao_tolerate.append(self.judge_anquanmao(person_detect_targets)) + self.xiubiao_tolerate.append(self.judge_xiubiao(person_detect_targets)) + self.xiyan_tolerate.append(self.judge_xiyan(person_detect_targets)) + self.xianzaren_tolerate.append(self.judge_xianzaren(person_detect_targets)) + self.dadianhua_tolerate.append(self.judge_dadianhua(person_detect_targets)) self.isAlarm() class Alarm(): - def __init__(self): + def __init__(self,device: Device, thread_id: str, tcp_manager: TcpManager, main_loop, eventController = None): self.pool = [] + self.device = device + self.thread_id = thread_id + self.tcp_manager =tcp_manager + self.main_loop = main_loop + self.eventController = eventController + + self.alarm_interval_dict = {} + self.alarm_interval = device.alarm_interval + + self.socket_interval_dict = {} + self.socket_interval = device.alarm_interval + self.socket_retry = 3 def addAlarm(self, content): ''' - + 添加一条报警到报警队列中 :param content: :return: ''' @@ -584,20 +647,54 @@ self.pool.remove(content) self.pool.append(content) + def deleteAlarmOfLaoBao(self): + ''' + 删除池子中有关劳保检测的报警 + :return: + ''' + self.pool = [item for item in self.pool if "劳保" not in item] + + def deleteAlaramOfUmdGas(self): + ''' + 删除池子中有关上中下气体的报警 + :return: + ''' + self.pool = [item for item in self.pool if "劳保" not in item] def main(self): for i in range(1000000): + if self.eventController.timeout_event.is_set(): # 前置条件检查超时 + self.deleteAlarmOfLaoBao() + self.deleteAlaramOfUmdGas() if len(self.pool) != 0: - print(f"{self.pool.pop(0)},报警队列长度:{len(self.pool)}") + content = self.pool.pop(0) + print(f"{content},报警队列长度:{len(self.pool)}") + # self.send_alarm_message("no_jiandu") time.sleep(1) + def send_tcp_message(self, message: bytes, have_response=False): + asyncio.run_coroutine_threadsafe( + self.tcp_manager.send_message_to_device(device_id=self.device.id, + message=message, + have_response=have_response), + self.main_loop) + + def send_alarm_message(self, type): + if self.tcp_manager: + # if self.socket_interval_dict.get(type) is None \ + # or (datetime.now() - self.socket_interval_dict.get(type)).total_seconds() > int(self.socket_interval): + logger.debug("send alarm message %s %s", ALARM_DICT[type]['alarmContent'], + ALARM_DICT[type]['alarmSoundMessage']) + self.send_tcp_message(ALARM_DICT[type]['alarmSoundMessage'], have_response=True) + self.socket_interval_dict[type] = datetime.now() + class ZynLimitSpaceSceneHandler(BaseSceneHandler): def __init__(self, device: Device, thread_id: str, tcp_manager: TcpManager, main_loop, range_points): super().__init__(device=device, thread_id=thread_id, tcp_manager=tcp_manager, main_loop=main_loop) + + self.start_time = time.time() # 脚本启动时间戳 - self.alarm_message_center = AlarmMessageCenter(device.id, main_loop=main_loop, tcp_manager=tcp_manager, - category_priority={2: 0, 1: 1, 3: 2, - 0: 3}) # alarmCategory:优先级 0代表优先级最高 + # self.stream_loader = OpenCVStreamLoad(camera_url=device.input_stream_url, camera_code=device.code, # device_thread_id=thread_id) @@ -607,14 +704,17 @@ self.health_device_codes = ['HWIH061000056395'] # 安全帽编号 self.eventController = EventController() - self.alarm = Alarm() - + self.alarm = Alarm(device, thread_id,tcp_manager, main_loop, self.eventController) self.laobao_check = Laobaocheck(self.eventController, self.alarm) self.yinhuan_check = YinHuanCheck(self.eventController, self.alarm) self.umd_pool = {} self.siHeyi = SiHeYi("862635063168165A") self.anQuanMao = AnQuanMao("HWIH061000056395") + + + + def addLog(self, pool, time, text): if time not in pool.keys(): pool[time] = [text] @@ -636,10 +736,10 @@ self.addLog(self.umd_pool, datetime.now().strftime("%H:%M:%S"), f"检测开机?") await loop.run_in_executor(executor, self.siHeyi.waitPowerOn, self.start_time) # 阻塞 uMDGasCheck_task 协程, 检测不到开机不往后进行 self.addLog(self.umd_pool, datetime.now().strftime("%H:%M:%S"), f"已开机!") - self.alarm_list.append("-------报警:检测到四合一已开机") + self.alarm.addAlarm(f"-------报警:上中下气体检测:检测到四合一已开机") for i in range(1000000): # 模拟循环检测气体 - if eventController.cancel_event.is_set(): # 超时退出 + if eventController.timeout_event.is_set(): # 超时退出 return # print(f"uMDGasCheck_task:{i}") @@ -648,33 +748,22 @@ if flag == False: tflag_pool.clear() self.umd_pool[datetime.now().strftime("%H:%M:%S")] = "报警:上中下气体" - self.addLog(self.umd_pool, datetime.now().strftime("%H:%M:%S"), f"报警:上中下气体异常") - + # self.addLog(self.umd_pool, datetime.now().strftime("%H:%M:%S"), f"报警:上中下气体异常") + self.alarm.addAlarm(f"-------报警:上中下气体检测:上中下气体异常") else: print(f"上中下气体检测正常次数:{tflag_pool}") tflag_pool.append(True) if len(tflag_pool) == 3: break # 退出检测 - self.alarm_list.append("-------报警:上中下气体检测通过") + self.alarm.addAlarm(f"-------报警:上中下气体检测:上中下气体检测通过") self.addLog(self.umd_pool, datetime.now().strftime("%H:%M:%S"), f"上中下气体检测通过") self.eventController.umd_complete.set() return async def alarm_task(self): - def fun(): - for i in range(1000000): # 检验中 - if self.eventController.laobao_complete.is_set(): - if "劳保物品 通过" in self.alarm_list: print("劳保物品 通过") - return - # print(f"alarm_task:{len(self.alarm_list)}") - if self.eventController.cancel_event.is_set(): # 超时退出 - return - if len(self.alarm_list) != 0: - print(f"{self.alarm_list.pop(0)},报警队列长度:{len(self.alarm_list)}") - time.sleep(1) executor = ThreadPoolExecutor(max_workers=3) loop = asyncio.get_running_loop() - await loop.run_in_executor(executor, fun) + await loop.run_in_executor(executor, self.alarm.main) async def logger_task(self): def fun(): @@ -713,7 +802,7 @@ blood_oxygen, heartrate = await loop.run_in_executor(executor, self.anQuanMao.getNewData) flag = self.anQuanMao.isDataNormal(blood_oxygen, heartrate) if flag == False: - self.alarm_list.append("-------报警:gasCheck:心率血氧数据异常") + self.alarm.addAlarm("-------报警:gasCheck:心率血氧数据异常") async def gasCheck(self): ''' 四合一气体检测 @@ -723,7 +812,7 @@ ch4, co, h2s, o2 = self.siHeyi.getNewData() flag = self.siHeyi.isDataNormal(ch4, co, h2s, o2) if flag == False: - self.alarm_list.append("-------报警:gasCheck:四合一气体异常") + self.alarm.addAlarm("------报警:gasCheck:四合一气体异常") executor = ThreadPoolExecutor(max_workers=3) loop = asyncio.get_running_loop() await loop.run_in_executor(executor, fun) @@ -731,25 +820,26 @@ def run(self): async def fun(): # 并行执行任务 - uMDGasCheck_task = asyncio.create_task( - self.uMDGasCheck_task(self.eventController)) - laobaoCheck_task = asyncio.create_task(self.laobaoCheck_task()) + # uMDGasCheck_task = asyncio.create_task( + # self.uMDGasCheck_task(self.eventController)) + # laobaoCheck_task = asyncio.create_task(self.laobaoCheck_task()) alarm_task = asyncio.create_task(self.alarm_task()) logger_task = asyncio.create_task(self.logger_task()) - done, pending = await asyncio.wait({uMDGasCheck_task, laobaoCheck_task}, timeout=300000.0) + # done, pending = await asyncio.wait({uMDGasCheck_task, laobaoCheck_task}, timeout=300000.0) - if uMDGasCheck_task in done and laobaoCheck_task in done: - await uMDGasCheck_task - await laobaoCheck_task - print("前置条件检查完成,退出") - - else: - # 如果超时,则取消未完成的任务 - self.eventController.cancel_event.set() - laobaoCheck_task.cancel() - uMDGasCheck_task.cancel() - print("前置条件检查时间过长,退出") + # if uMDGasCheck_task in done and laobaoCheck_task in done: + # await uMDGasCheck_task + # await laobaoCheck_task + # self.eventController.timeout_event.set() + # print("前置条件检查完成,退出") + # + # else: + # # 如果超时,则取消未完成的任务 + # self.eventController.timeout_event.set() + # laobaoCheck_task.cancel() + # uMDGasCheck_task.cancel() + # print("前置条件检查时间过长,退出") # 并行执行任务 print("开始工作") @@ -759,6 +849,7 @@ results = await asyncio.gather(yinhuanCheck_task, gasCheck, xinlvCheck) done1, pending1 = await asyncio.wait({alarm_task, logger_task}, timeout=300000.0) + asyncio.run(fun()) if __name__=='__main__': diff --git a/2025-01-21 14-42-00.mkv b/2025-01-21 14-42-00.mkv new file mode 100644 index 0000000..e5fc70a --- /dev/null +++ b/2025-01-21 14-42-00.mkv Binary files differ diff --git a/2025-02-25 15-25-48.mkv b/2025-02-25 15-25-48.mkv new file mode 100644 index 0000000..d978d93 --- /dev/null +++ b/2025-02-25 15-25-48.mkv Binary files differ diff --git a/2025-02-26 08-49-39.mkv b/2025-02-26 08-49-39.mkv new file mode 100644 index 0000000..255af95 --- /dev/null +++ b/2025-02-26 08-49-39.mkv Binary files differ diff --git a/scene_handler/zyn_limit_space_scene_handler.py b/scene_handler/zyn_limit_space_scene_handler.py index 1d243fa..e300098 100644 --- a/scene_handler/zyn_limit_space_scene_handler.py +++ b/scene_handler/zyn_limit_space_scene_handler.py @@ -41,6 +41,16 @@ 'logtime': '2025-01-14 15:40:49', 'o2': '15.90', 'uptime': '2026-01-14 15:40:52'}}, {"data":{'ch4': '0.00', 'co': '0.00', 'h2s': '0.00', 'id': '142913', 'logtime': '2025-01-14 15:40:49', 'o2': '15.90', 'uptime': '2026-01-14 15:40:53'}}, + {"data": {'ch4': '0.00', 'co': '0.00', 'h2s': '0.00', 'id': '142913', + 'logtime': '2025-01-14 15:40:49', 'o2': '15.90', 'uptime': '2026-01-14 15:40:53'}}, + {"data": {'ch4': '0.00', 'co': '0.00', 'h2s': '0.00', 'id': '142913', + 'logtime': '2025-01-14 15:40:49', 'o2': '15.90', 'uptime': '2026-01-14 15:40:53'}}, + {"data": {'ch4': '0.00', 'co': '0.00', 'h2s': '0.00', 'id': '142913', + 'logtime': '2025-01-14 15:40:49', 'o2': '15.90', 'uptime': '2026-01-14 15:40:53'}}, + {"data": {'ch4': '0.00', 'co': '0.00', 'h2s': '0.00', 'id': '142913', + 'logtime': '2025-01-14 15:40:49', 'o2': '15.90', 'uptime': '2026-01-14 15:40:53'}}, + {"data": {'ch4': '0.00', 'co': '0.00', 'h2s': '0.00', 'id': '142913', + 'logtime': '2025-01-14 15:40:49', 'o2': '15.90', 'uptime': '2026-01-14 15:40:53'}}, ] value_iterator = create_value_iterator(fake_list) @@ -89,7 +99,44 @@ return data - +ALARM_DICT = { + 'hat_and_mask': { + 'alarmType': '11', + 'alarmContent': '未佩戴呼吸防护设备', + 'alarmSoundMessage': b'\xaa\x01\x00\x93\x12\x00\xA6', + 'label': '未佩戴呼吸防护设备' + }, + 'no_jiandu': { + 'alarmType': '12', + 'alarmContent': '没有监护人员', + 'alarmSoundMessage': b'\xaa\x01\x00\x93\x12\x00\xA6', + 'label': '没有监护人员' + }, + 'break': { + 'alarmType': '3', + 'alarmContent': '非法闯入', + 'alarmSoundMessage': b'\xaa\x01\x00\x93\x00\x00\x94', + 'label': '非法闯入' + }, + 'smoke': { + 'alarmType': '6', + 'alarmContent': '吸烟', + 'alarmSoundMessage': b'\xaa\x01\x00\x93\x03\x00\x97', + 'label': '吸烟' + }, + 'no_blower': { + 'alarmType': '13', + 'alarmContent': '没有检测到通风设备', + 'alarmSoundMessage': b'\xaa\x01\x00\x93\x1A\x00\xAE', + 'label': '没有检测到通风设备' + }, + 'no_extinguisher': { + 'alarmType': '14', + 'alarmContent': '没有检测到灭火器', + 'alarmSoundMessage': b'\xaa\x01\x00\x93\x1B\x00\xAF', + 'label': '没有检测到灭火器' + } +} @@ -101,8 +148,9 @@ class EventController(): def __init__(self): - self.cancel_event = asyncio.Event() + self.timeout_event = asyncio.Event() self.umd_complete = asyncio.Event() + self.qianzhi_check_complete = asyncio.Event() self.laobao_complete = asyncio.Event() class SiHeYi(): @@ -308,11 +356,12 @@ :return: None ''' for pred_label in pred_labels: - # print(f"检测到{pred_label}") + print(f"检测到{pred_label}") self.target_flag[pred_label] = True self.jiaodi_flag = jiaodi_flag if self.jiaodi_flag == False and jiaodi_flag ==True: - self.alarm.addAlarm("-------检测到交底") + print(f"劳保检测:检测到交底") + self.alarm.addAlarm("-------劳保检测:检测到交底") def model_predict_fake(self, video_path): cap = cv2.VideoCapture(video_path) @@ -320,9 +369,7 @@ try: ret, frames = cap.read() frames = [frames] - # self.addLog(self.laobao_pool, datetime.now().strftime("%H:%M:%S"), "读取帧") if not ret: - # self.addLog(self.laobao_pool, datetime.now().strftime("%H:%M:%S"), "读取视频结束,退出") break # cv2.namedWindow("Video Frame", cv2.WINDOW_AUTOSIZE) # cv2.resizeWindow('Video Frame', 800, 600) # 宽度800像素,高度600像素 @@ -336,7 +383,7 @@ if cv2.waitKey(1) & 0xFF == ord('q'): break - if self.eventController != None and self.eventController.cancel_event.is_set(): # 超时退出 + if self.eventController != None and self.eventController.timeout_event.is_set(): # 超时退出 cap.release() cv2.destroyAllWindows() return @@ -352,21 +399,19 @@ if self.getUndetectedTarget() == []: # 如果全部检验到了 # print("劳保物品 通过") # self.addLog(self.laobao_pool, datetime.now().strftime("%H:%M:%S"), f"劳保物品 通过") - self.alarm.addAlarm("-------劳保物品 通过") + self.alarm.addAlarm("-------劳保检测:劳保物品 通过") self.eventController.laobao_complete.set() cap.release() cv2.destroyAllWindows() return # 退出检测 else: # 如果还有未检测到的 - undetectedTargets = self.getUndetectedTarget() - # print(f"报警:劳保物品缺失:{wrong_class_list}") - self.alarm.addAlarm(f"-------报警:劳保物品缺失:{undetectedTargets[0]}") + self.alarm.addAlarm(f"-------报警:劳保检测:劳保物品缺失:{undetectedTargets[0]}") cap.release() cv2.destroyAllWindows() def model_predict(self, stream_loader): for frames in stream_loader: # type : list (4),连续的4帧 - if self.eventController != None and self.eventController.cancel_event.is_set(): # 超时退出 + if self.eventController != None and self.eventController.timeout_event.is_set(): # 超时退出 return # 构造 要检测目标的 id_list(把之前检测的目标 从 要检测目标的集合移出) jiaodi_flag = self.predict_isJiaodi(frames) # bool, 检测 新收集的这几帧有无交底 @@ -379,28 +424,19 @@ if self.getUndetectedTarget() == []: # 如果全部检验到了 # print("劳保物品 通过") # self.addLog(self.laobao_pool, datetime.now().strftime("%H:%M:%S"), f"劳保物品 通过") - self.alarm_list.append("劳保物品 通过") + self.alarm.addAlarm(f"劳保检测:劳保物品 通过") self.eventController.laobao_complete.set() return # 退出检测 else: # 如果还有未检测到的 undetectedTargets = self.getUndetectedTarget() - # print(f"报警:劳保物品缺失:{wrong_class_list}") - - for undetectedTarget in undetectedTargets: - alarm_content = f"报警:劳保物品缺失:{undetectedTarget}" - if alarm_content not in self.alarm_list: # 不加入 重复的报警内容 - self.alarm_list.append(alarm_content) - # self.addLog(self.laobao_pool, datetime.now().strftime("%H:%M:%S"), - # f"报警:劳保物品缺失:{undetectedTarget}") - # self.alarm_list.remove(f"报警:劳保物品缺失:{wrong_class}") # 对于同样内容的报警,删除 早的报警 - # self.alarm_list.append(f"报警:劳保物品缺失:{wrong_class}") # 保留新的报警 + self.alarm.addAlarm(f"-------报警:劳保检测:劳保物品缺失:{undetectedTargets[0]}") class YinHuanCheck(): - def __init__(self, eventController=None, alarm_list=None): + def __init__(self, eventController=None, alarm=None): self.model = YOLO("weights/yinhuan.pt") self.eventController = eventController - self.alarm_list = alarm_list + self.alarm = alarm self.anquanmao_tolerate = [] @@ -445,20 +481,20 @@ :return: ''' for person_result in person_targets: # 每个人身上的物件 - if "吸烟" in person_result: + if "烟头" in person_result: # 有一个人抽烟 return False # 没有通过吸烟检测 return True # 通过吸烟检测 def judge_xiubiao(self, person_targets): ''' - 判定有没有 吸烟的人 + 判定有没有 袖标的人 param person_targets: [[label1,label2..], [label1...]] 每个人身上的目标 :return: ''' for person_result in person_targets: # 每个人身上的物件 - if "吸烟" in person_result: - return False # 没有通过吸烟检测 - return True # 通过吸烟检测 + if "袖标" in person_result: # 有一个人带袖标就通过 + return True # 通过袖标检测 + return False # 没有通过袖标检测 def judge_dadianhua(self, person_targets): ''' 判定有没有 打电话的人 @@ -466,10 +502,9 @@ :return: ''' for person_result in person_targets: # 每个人身上的物件 - if "打电话" in person_result: + if "电话" in person_result: # 有一个人打电话 return False # 没有通过打电话检测 return True # 通过打电话检测 - def judge_xianzaren(self, person_targets): ''' 判定有没有 打电话的人 @@ -500,10 +535,10 @@ return result def isAlarm(self): - def has_consecutive_true(bool_list, threshold=30): + def has_consecutive_false(bool_list, threshold=20): count = 0 # 计数器,用于记录连续 True 的次数 for value in bool_list: - if value: # 如果当前值为 True + if value == False: # 如果当前值为 False count += 1 # 增加计数器 if count > threshold: # 如果计数器超过阈值 return True @@ -511,11 +546,24 @@ count = 0 # 重置计数器 return False # 遍历完成后没有发现连续超过 threshold 次的 True - if has_consecutive_true(self.anquanmao_tolerate) == True: + if has_consecutive_false(self.anquanmao_tolerate) == True and self.alarm != None: self.anquanmao_tolerate.clear() - # print("安全帽报警") + self.alarm.addAlarm("-------报警:未带安全帽") + if has_consecutive_false(self.xiyan_tolerate) == True and self.alarm != None: + self.xiyan_tolerate.clear() + self.alarm.addAlarm("-------报警:吸烟") + if has_consecutive_false(self.xiubiao_tolerate) == True and self.alarm != None: + self.xiubiao_tolerate.clear() + self.alarm.addAlarm("-------报警:袖标") + if has_consecutive_false(self.dadianhua_tolerate) == True and self.alarm != None: + self.dadianhua_tolerate.clear() + self.alarm.addAlarm("-------报警:打电话") + + if has_consecutive_false(self.xianzaren_tolerate) == True and self.alarm != None: + self.xianzaren_tolerate.clear() + self.alarm.addAlarm("-------报警:闲杂人") def detect_person_targets(self,person_crops): ''' @@ -537,14 +585,10 @@ cap = cv2.VideoCapture(video_path) ret, frames = cap.read() while True: - # for frames in self.stream_loader: # type : list (4),连续的4帧 try: ret, frames = cap.read() - print(f"读取帧{ret}") frames = [frames] - # self.addLog(self.laobao_pool, datetime.now().strftime("%H:%M:%S"), "读取帧") if not ret: - # self.addLog(self.laobao_pool, datetime.now().strftime("%H:%M:%S"), "读取视频结束,退出") cap.release() cv2.destroyAllWindows() break @@ -560,8 +604,11 @@ break people_results = self.detect_person(frames) # 检测人 person_detect_targets = self.detect_person_targets(people_results) - print(person_detect_targets) self.anquanmao_tolerate.append(self.judge_anquanmao(person_detect_targets)) + self.xiubiao_tolerate.append(self.judge_xiubiao(person_detect_targets)) + self.xiyan_tolerate.append(self.judge_xiyan(person_detect_targets)) + self.xianzaren_tolerate.append(self.judge_xianzaren(person_detect_targets)) + self.dadianhua_tolerate.append(self.judge_dadianhua(person_detect_targets)) self.isAlarm() def main(self, stream_loader): @@ -569,14 +616,30 @@ people_results = self.detect_person(frames) # 检测人 person_detect_targets = self.detect_person_targets(people_results) self.anquanmao_tolerate.append(self.judge_anquanmao(person_detect_targets)) + self.xiubiao_tolerate.append(self.judge_xiubiao(person_detect_targets)) + self.xiyan_tolerate.append(self.judge_xiyan(person_detect_targets)) + self.xianzaren_tolerate.append(self.judge_xianzaren(person_detect_targets)) + self.dadianhua_tolerate.append(self.judge_dadianhua(person_detect_targets)) self.isAlarm() class Alarm(): - def __init__(self): + def __init__(self,device: Device, thread_id: str, tcp_manager: TcpManager, main_loop, eventController = None): self.pool = [] + self.device = device + self.thread_id = thread_id + self.tcp_manager =tcp_manager + self.main_loop = main_loop + self.eventController = eventController + + self.alarm_interval_dict = {} + self.alarm_interval = device.alarm_interval + + self.socket_interval_dict = {} + self.socket_interval = device.alarm_interval + self.socket_retry = 3 def addAlarm(self, content): ''' - + 添加一条报警到报警队列中 :param content: :return: ''' @@ -584,20 +647,54 @@ self.pool.remove(content) self.pool.append(content) + def deleteAlarmOfLaoBao(self): + ''' + 删除池子中有关劳保检测的报警 + :return: + ''' + self.pool = [item for item in self.pool if "劳保" not in item] + + def deleteAlaramOfUmdGas(self): + ''' + 删除池子中有关上中下气体的报警 + :return: + ''' + self.pool = [item for item in self.pool if "劳保" not in item] def main(self): for i in range(1000000): + if self.eventController.timeout_event.is_set(): # 前置条件检查超时 + self.deleteAlarmOfLaoBao() + self.deleteAlaramOfUmdGas() if len(self.pool) != 0: - print(f"{self.pool.pop(0)},报警队列长度:{len(self.pool)}") + content = self.pool.pop(0) + print(f"{content},报警队列长度:{len(self.pool)}") + # self.send_alarm_message("no_jiandu") time.sleep(1) + def send_tcp_message(self, message: bytes, have_response=False): + asyncio.run_coroutine_threadsafe( + self.tcp_manager.send_message_to_device(device_id=self.device.id, + message=message, + have_response=have_response), + self.main_loop) + + def send_alarm_message(self, type): + if self.tcp_manager: + # if self.socket_interval_dict.get(type) is None \ + # or (datetime.now() - self.socket_interval_dict.get(type)).total_seconds() > int(self.socket_interval): + logger.debug("send alarm message %s %s", ALARM_DICT[type]['alarmContent'], + ALARM_DICT[type]['alarmSoundMessage']) + self.send_tcp_message(ALARM_DICT[type]['alarmSoundMessage'], have_response=True) + self.socket_interval_dict[type] = datetime.now() + class ZynLimitSpaceSceneHandler(BaseSceneHandler): def __init__(self, device: Device, thread_id: str, tcp_manager: TcpManager, main_loop, range_points): super().__init__(device=device, thread_id=thread_id, tcp_manager=tcp_manager, main_loop=main_loop) + + self.start_time = time.time() # 脚本启动时间戳 - self.alarm_message_center = AlarmMessageCenter(device.id, main_loop=main_loop, tcp_manager=tcp_manager, - category_priority={2: 0, 1: 1, 3: 2, - 0: 3}) # alarmCategory:优先级 0代表优先级最高 + # self.stream_loader = OpenCVStreamLoad(camera_url=device.input_stream_url, camera_code=device.code, # device_thread_id=thread_id) @@ -607,14 +704,17 @@ self.health_device_codes = ['HWIH061000056395'] # 安全帽编号 self.eventController = EventController() - self.alarm = Alarm() - + self.alarm = Alarm(device, thread_id,tcp_manager, main_loop, self.eventController) self.laobao_check = Laobaocheck(self.eventController, self.alarm) self.yinhuan_check = YinHuanCheck(self.eventController, self.alarm) self.umd_pool = {} self.siHeyi = SiHeYi("862635063168165A") self.anQuanMao = AnQuanMao("HWIH061000056395") + + + + def addLog(self, pool, time, text): if time not in pool.keys(): pool[time] = [text] @@ -636,10 +736,10 @@ self.addLog(self.umd_pool, datetime.now().strftime("%H:%M:%S"), f"检测开机?") await loop.run_in_executor(executor, self.siHeyi.waitPowerOn, self.start_time) # 阻塞 uMDGasCheck_task 协程, 检测不到开机不往后进行 self.addLog(self.umd_pool, datetime.now().strftime("%H:%M:%S"), f"已开机!") - self.alarm_list.append("-------报警:检测到四合一已开机") + self.alarm.addAlarm(f"-------报警:上中下气体检测:检测到四合一已开机") for i in range(1000000): # 模拟循环检测气体 - if eventController.cancel_event.is_set(): # 超时退出 + if eventController.timeout_event.is_set(): # 超时退出 return # print(f"uMDGasCheck_task:{i}") @@ -648,33 +748,22 @@ if flag == False: tflag_pool.clear() self.umd_pool[datetime.now().strftime("%H:%M:%S")] = "报警:上中下气体" - self.addLog(self.umd_pool, datetime.now().strftime("%H:%M:%S"), f"报警:上中下气体异常") - + # self.addLog(self.umd_pool, datetime.now().strftime("%H:%M:%S"), f"报警:上中下气体异常") + self.alarm.addAlarm(f"-------报警:上中下气体检测:上中下气体异常") else: print(f"上中下气体检测正常次数:{tflag_pool}") tflag_pool.append(True) if len(tflag_pool) == 3: break # 退出检测 - self.alarm_list.append("-------报警:上中下气体检测通过") + self.alarm.addAlarm(f"-------报警:上中下气体检测:上中下气体检测通过") self.addLog(self.umd_pool, datetime.now().strftime("%H:%M:%S"), f"上中下气体检测通过") self.eventController.umd_complete.set() return async def alarm_task(self): - def fun(): - for i in range(1000000): # 检验中 - if self.eventController.laobao_complete.is_set(): - if "劳保物品 通过" in self.alarm_list: print("劳保物品 通过") - return - # print(f"alarm_task:{len(self.alarm_list)}") - if self.eventController.cancel_event.is_set(): # 超时退出 - return - if len(self.alarm_list) != 0: - print(f"{self.alarm_list.pop(0)},报警队列长度:{len(self.alarm_list)}") - time.sleep(1) executor = ThreadPoolExecutor(max_workers=3) loop = asyncio.get_running_loop() - await loop.run_in_executor(executor, fun) + await loop.run_in_executor(executor, self.alarm.main) async def logger_task(self): def fun(): @@ -713,7 +802,7 @@ blood_oxygen, heartrate = await loop.run_in_executor(executor, self.anQuanMao.getNewData) flag = self.anQuanMao.isDataNormal(blood_oxygen, heartrate) if flag == False: - self.alarm_list.append("-------报警:gasCheck:心率血氧数据异常") + self.alarm.addAlarm("-------报警:gasCheck:心率血氧数据异常") async def gasCheck(self): ''' 四合一气体检测 @@ -723,7 +812,7 @@ ch4, co, h2s, o2 = self.siHeyi.getNewData() flag = self.siHeyi.isDataNormal(ch4, co, h2s, o2) if flag == False: - self.alarm_list.append("-------报警:gasCheck:四合一气体异常") + self.alarm.addAlarm("------报警:gasCheck:四合一气体异常") executor = ThreadPoolExecutor(max_workers=3) loop = asyncio.get_running_loop() await loop.run_in_executor(executor, fun) @@ -731,25 +820,26 @@ def run(self): async def fun(): # 并行执行任务 - uMDGasCheck_task = asyncio.create_task( - self.uMDGasCheck_task(self.eventController)) - laobaoCheck_task = asyncio.create_task(self.laobaoCheck_task()) + # uMDGasCheck_task = asyncio.create_task( + # self.uMDGasCheck_task(self.eventController)) + # laobaoCheck_task = asyncio.create_task(self.laobaoCheck_task()) alarm_task = asyncio.create_task(self.alarm_task()) logger_task = asyncio.create_task(self.logger_task()) - done, pending = await asyncio.wait({uMDGasCheck_task, laobaoCheck_task}, timeout=300000.0) + # done, pending = await asyncio.wait({uMDGasCheck_task, laobaoCheck_task}, timeout=300000.0) - if uMDGasCheck_task in done and laobaoCheck_task in done: - await uMDGasCheck_task - await laobaoCheck_task - print("前置条件检查完成,退出") - - else: - # 如果超时,则取消未完成的任务 - self.eventController.cancel_event.set() - laobaoCheck_task.cancel() - uMDGasCheck_task.cancel() - print("前置条件检查时间过长,退出") + # if uMDGasCheck_task in done and laobaoCheck_task in done: + # await uMDGasCheck_task + # await laobaoCheck_task + # self.eventController.timeout_event.set() + # print("前置条件检查完成,退出") + # + # else: + # # 如果超时,则取消未完成的任务 + # self.eventController.timeout_event.set() + # laobaoCheck_task.cancel() + # uMDGasCheck_task.cancel() + # print("前置条件检查时间过长,退出") # 并行执行任务 print("开始工作") @@ -759,6 +849,7 @@ results = await asyncio.gather(yinhuanCheck_task, gasCheck, xinlvCheck) done1, pending1 = await asyncio.wait({alarm_task, logger_task}, timeout=300000.0) + asyncio.run(fun()) if __name__=='__main__': diff --git a/weights/jiaodi.pt b/weights/jiaodi.pt new file mode 100644 index 0000000..67c8ab2 --- /dev/null +++ b/weights/jiaodi.pt Binary files differ