From 61c8e6ab988b3ef35ca6eda391720a5152adb7a1 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 1 Mar 2024 18:49:40 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20ecm=E6=8F=90=E5=87=BAcheck=5Fsame=5Fall?= =?UTF-8?q?ow=5Fminute=5Fand=5Fraise=5Fevent=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/ecm/service.py | 127 ++++++++++++++++++++++++++++---------------- 1 file changed, 82 insertions(+), 45 deletions(-) diff --git a/apps/ecm/service.py b/apps/ecm/service.py index 9f4aa02b..5d681a2d 100644 --- a/apps/ecm/service.py +++ b/apps/ecm/service.py @@ -62,6 +62,7 @@ def save_dahua_pic(pic_url: str, save_path: str = '/media/'): f.write(res.content) return path + file_name + def compress_global_img(path_file): full_path_file = settings.BASE_DIR + path_file try: @@ -71,12 +72,13 @@ def compress_global_img(path_file): myLogger.error(f'图片压缩失败-{full_path_file}-{traceback.format_exc()}') return None + def get_ep_default(): """返回人员默认位置信息 """ return { 'area_fix_id': None, # 当前所在固定区域ID - 'area_fix_name': None, # 当前所在固定区域Name + 'area_fix_name': None, # 当前所在固定区域Name 'area_temp_id': None, # 当前所在临时区域ID 'xx_detail': {}, # 寻息定位的详细信息 'time0': None, # 定位首次出现时间戳 @@ -84,6 +86,7 @@ def get_ep_default(): "time2": int(time.time()), # 当前时间戳 } + def gen_params(event: Event): """ 生成短信模板发送参数 @@ -112,7 +115,7 @@ def gen_params(event: Event): cats_list.append(i.name) params['event'] = ','.join(cats_list) return params - + def notify_event(event: Event): """事件后续处理: @@ -127,9 +130,11 @@ def notify_event(event: Event): else: params = gen_params(event) if params['employee']: - event.voice_msg = '位于{}的{},{},请及时处理'.format(params['area'], params['employee'], params['event']) + event.voice_msg = '位于{}的{},{},请及时处理'.format( + params['area'], params['employee'], params['event']) else: - event.voice_msg = '在{}下,发生{},请及时处理'.format(params['area'], params['event']) + event.voice_msg = '在{}下,发生{},请及时处理'.format( + params['area'], params['event']) event.save() # 喇叭播放(任何情况下) Thread(target=save_voice_and_speak, args=(event,), daemon=True).start() @@ -165,7 +170,8 @@ def save_voice_and_speak(event: Event): sps = list(TDevice.objects.filter(areas=event.area, type=TDevice.DEVICE_SPEAKER).values_list('code', flat=True)) # 查找固定喇叭 - sps2 = list(TDevice.objects.filter(ec_speakers__event_cates=event).values_list('code', flat=True)) + sps2 = list(TDevice.objects.filter( + ec_speakers__event_cates=event).values_list('code', flat=True)) for i in sps2: if i not in sps: sps.append(i) @@ -186,7 +192,8 @@ def create_remind(event: Event, params: dict): # t_sms = Thread(target=send_sms, args=(event.employee.phone, '1001', {'code': '5678'}), daemon=True) # t_sms.start() # 查找所有提醒配置 - n_s = NotifySetting.objects.filter(event_cate__in=event.cates.all()).order_by('sort') + n_s = NotifySetting.objects.filter( + event_cate__in=event.cates.all()).order_by('sort') area_level = event.area.level if event.area else Area.AREA_4 for i in n_s: if i.user and area_level >= i.filter_area_level: @@ -200,11 +207,13 @@ def create_remind(event: Event, params: dict): elif i.post and area_level >= i.filter_area_level: qs = User.objects.filter(posts=i.post) if i.filter_recipient == 20 and event.employee and event.employee.user: - qs = qs.filter(depts__in=get_parent_queryset(event.employee.user.belong_dept)) + qs = qs.filter(depts__in=get_parent_queryset( + event.employee.user.belong_dept)) elif i.filter_recipient == 10 and event.employee and event.employee.user: qs = qs.filter(depts=event.employee.user.belong_dept) elif i.filter_recipient == 40 and event.area.belong_dept: - qs = qs.filter(depts__in=get_parent_queryset(event.area.belong_dept)) + qs = qs.filter(depts__in=get_parent_queryset( + event.area.belong_dept)) elif i.filter_recipient == 30 and event.area.belong_dept: qs = qs.filter(depts=event.area.belong_dept) else: @@ -238,7 +247,8 @@ def create_remind(event: Event, params: dict): }) elif i.variable == 'visit_receptionist': if event.employee and event.employee.type == 'visitor': # 确定是访客 - visit = Visit.objects.filter(visitors__employee=event.employee, state=Visit.V_WORKING).first() + visit = Visit.objects.filter( + visitors__employee=event.employee, state=Visit.V_WORKING).first() if visit: Remind.objects.get_or_create(event=event, recipient=visit.receptionist, defaults={ @@ -272,13 +282,15 @@ def check_not_in_place(opl: Opl): "railId": railId, "type": "" } - is_ok, res = xxClient.request(**xxapis['rail_ibeacon_list'], json=json, raise_exception=False) + is_ok, res = xxClient.request( + **xxapis['rail_ibeacon_list'], json=json, raise_exception=False) if is_ok == 'success': blt_list = res['recordList'] macs = [] # 所有该区域在线标签 for i in blt_list: macs.append(i['userId']) - tds = TDevice.objects.filter(type=TDevice.DEVICE_BLT, employee__user__opl_worker__opl=opl) # 所有工作人员的定位标签 + tds = TDevice.objects.filter( + type=TDevice.DEVICE_BLT, employee__user__opl_worker__opl=opl) # 所有工作人员的定位标签 for i in tds: if i.code not in macs: # 触发作业人员未就位事件 @@ -306,13 +318,15 @@ def check_miss_lcard(ep: Employee, area: Area): "railId": railId, "type": "" } - is_ok, res = xxClient.request(**xxapis['rail_ibeacon_list'], json=json, raise_exception=False) + is_ok, res = xxClient.request( + **xxapis['rail_ibeacon_list'], json=json, raise_exception=False) if is_ok == 'success': blt_list = res['recordList'] macs = [] # 所有该区域在线标签 for i in blt_list: macs.append(i['userId']) - td = TDevice.objects.filter(type=TDevice.DEVICE_BLT, employee=ep).first() + td = TDevice.objects.filter( + type=TDevice.DEVICE_BLT, employee=ep).first() if td and td.code in macs: return False return True @@ -335,7 +349,8 @@ def dispatch_dahua_event(data: dict): if alarm_type in [1001003, 1001000]: obj_cate = 'people' face_img_o = dhClient.get_full_pic(data['info']['alarmPicture']) - global_img_o = dhClient.get_full_pic(data['info']['extend']['globalScenePicUrl']) + global_img_o = dhClient.get_full_pic( + data['info']['extend']['globalScenePicUrl']) else: global_img_o = dhClient.get_full_pic(data['info']['alarmPicture']) happen_time = timestamp_to_time(int(data['info']['alarmDate'])) @@ -350,21 +365,26 @@ def dispatch_dahua_event(data: dict): else: algo_codes.append(i['algo__code']) if algo_codes: - ec_codes = ai_analyse_2(algo_codes, global_img=global_img_o, face_img=face_img_o) # 算法处理 + ec_codes = ai_analyse_2( + algo_codes, global_img=global_img_o, face_img=face_img_o) # 算法处理 for m in ec_codes.keys(): for n in algo_channels: if m == n['algo__code']: cates.append(n['algo']) if alarm_type == 1001003 and area: # 内部人员需要执行未带定位卡算法 - ep = Employee.objects.filter(id_number=data['info']['extend']['candidateInfo'][0]['id']).first() + ep = Employee.objects.filter( + id_number=data['info']['extend']['candidateInfo'][0]['id']).first() # 检查是否携带定位卡只针对内部员工和相关方 if 'miss_lcard' in algo_codes and ep: is_happend = check_miss_lcard(ep=ep, area=area) if is_happend: - cates.append(EventCate.objects.filter(code='miss_lcard').first().id) + cate_obj = EventCate.objects.filter(code='miss_lcard').first() + if cate_obj and check_same_allow_minute_and_raise_event(cate_obj, ep): + cates.append(cate_obj.id) if cates: event = Event() - event.global_img = ec_codes['global_img'] if ec_codes.get('global_img', None) else save_dahua_pic(global_img_o) + event.global_img = ec_codes['global_img'] if ec_codes.get( + 'global_img', None) else save_dahua_pic(global_img_o) event.global_img_compressed = compress_global_img(event.global_img) if face_img_o: event.face_img = save_dahua_pic(face_img_o) @@ -377,7 +397,7 @@ def dispatch_dahua_event(data: dict): current_level = 10 for i in cates: cate = EventCate.objects.get(id=i) - if cate.origin_level>current_level: + if cate.origin_level > current_level: event.current_level = current_level Eventdo.objects.get_or_create(cate=cate, event=event, defaults={ 'cate': cate, @@ -452,12 +472,14 @@ def loc_change(data): ep_loc_dict['time2'] = int(time.time()) ep_loc_dict['xx_detail'] = data - area_fix, area_temp = get_area_from_point(data['longitude'], data['latitude'], data['floorNo'], ep_loc_dict['area_fix_id']) + area_fix, area_temp = get_area_from_point( + data['longitude'], data['latitude'], data['floorNo'], ep_loc_dict['area_fix_id']) time2 = int(time.time()) ep_loc_dict['area_temp_id'] = area_temp['id'] if area_temp else None ep_loc_dict['time2'] = time2 if area_fix and ep_loc_dict['area_fix_id'] == area_fix['id']: - ep_loc_dict['area_fix_name'] = area_fix.get('name', None) # 兼容性处理,后续可去除 + ep_loc_dict['area_fix_name'] = area_fix.get( + 'name', None) # 兼容性处理,后续可去除 # 如果停留在该区域 cache.set(key_str, ep_loc_dict, timeout=None) # 在该固定区域停留时间(分钟) @@ -473,15 +495,36 @@ def loc_change(data): # 触发超时滞留事件 code_name = 'stand_area' if code_name: - handle_xx_event_2(code_name, ep=blts.employee, area=Area.objects.get(id=area_fix['id'])) + handle_xx_event_2(code_name, ep=blts.employee, + area=Area.objects.get(id=area_fix['id'])) else: ep_loc_dict['time1'] = time2 ep_loc_dict['area_fix_id'] = area_fix['id'] if area_fix else None - ep_loc_dict['area_fix_name'] = area_fix.get('name', None) if area_fix else None + ep_loc_dict['area_fix_name'] = area_fix.get( + 'name', None) if area_fix else None cache.set(key_str, ep_loc_dict, timeout=None) return ep_loc_dict +def check_same_allow_minute_and_raise_event(cate: EventCate, employee: Employee = None, area: Area = None, obj_cate: str = None): + """ + 根据配置告警间隔判断是否需要报出事件 + """ + filters = {'cate': cate} + if employee: + filters['employee'] = employee + if area: + filters['area'] = area + if obj_cate: + filters['obj_cate'] = obj_cate + last_event = Event.objects.filter( + **filters).order_by('-create_time').first() + minutes = cate.same_allow_minute + if minutes > 0 and last_event and last_event.create_time + timedelta(minutes=minutes) > timezone.now(): + return True + return False + + def handle_xx_event(name: str, data: dict): # 有绑定对象再提示事件(包括一键报警事件/低电量) blts = TDevice.objects.filter(code=data['mac']).first() @@ -491,9 +534,7 @@ def handle_xx_event(name: str, data: dict): cate = EventCate.objects.filter(code=name).first() # 找到最近未处理同一人发生的事件 if cate: # 5分钟内不再次触发 - last_event = Event.objects.filter(cates__code=name, employee=blts.employee).order_by('-create_time').first() - same_allow_minute = cate.same_allow_minute - if same_allow_minute >0 and last_event and last_event.create_time + timedelta(minutes=cate.same_allow_minute) > timezone.now(): + if check_same_allow_minute_and_raise_event(cate, blts.employee) is False: return event = Event() # 查询定位信息 @@ -523,12 +564,10 @@ def handle_xx_event_2(name: str, ep: Employee, area: Area): cate = EventCate.objects.filter(code=name).first() if cate: if name == 'i_enter' and ep.type in ['employee', 'remployee']: - last_event = Event.objects.filter( - cates__code='i_enter', employee=ep, area=area).order_by('-create_time').first() - same_allow_minute = cate.same_allow_minute - if same_allow_minute>0 and last_event and last_event.create_time + timedelta(minutes=same_allow_minute) > timezone.now(): # 2分钟不再次触发 + if check_same_allow_minute_and_raise_event(cate, ep, area) is False: return - ops = Operation.objects.filter(area=area, state__in=[Operation.OP_AUDIT, Operation.OP_WAIT, Operation.OP_WORK]) + ops = Operation.objects.filter(area=area, state__in=[ + Operation.OP_AUDIT, Operation.OP_WAIT, Operation.OP_WORK]) if OplWorker.objects.filter(opl__operation__in=ops, worker__employee=ep).exists(): # 如果是作业人员 return @@ -646,7 +685,8 @@ def snap_and_analyse(vchannel: TDevice, algo_codes: list, opl: Opl = None): if global_img_o is None: # 说明视频抓拍失败 if cvalue: try: - cvalue.update({'snap': 'fail', 'snap_time': datetime.now().strftime("%Y-%m-%d %H:%M:%S")}) + cvalue.update( + {'snap': 'fail', 'snap_time': datetime.now().strftime("%Y-%m-%d %H:%M:%S")}) cache.set(ckey, cvalue, timeout=60) except: pass @@ -654,7 +694,8 @@ def snap_and_analyse(vchannel: TDevice, algo_codes: list, opl: Opl = None): else: if cvalue: try: - cvalue.update({'snap': 'success', 'snap_time': datetime.now().strftime("%Y-%m-%d %H:%M:%S")}) + cvalue.update( + {'snap': 'success', 'snap_time': datetime.now().strftime("%Y-%m-%d %H:%M:%S")}) cache.set(ckey, cvalue, timeout=60) except: pass @@ -675,13 +716,11 @@ def snap_and_analyse(vchannel: TDevice, algo_codes: list, opl: Opl = None): # ep = Employee.objects.filter(id_number=res[0]['identity']).first() pass - last_event = Event.objects.filter(cates__in=ecs, employee=ep, obj_cate=obj_cate).order_by('-create_time').first() - same_allow_minute = ecs.order_by('same_allow_minute').first().same_allow_minute - if same_allow_minute>0 and last_event and last_event.create_time + timedelta(minutes=same_allow_minute) > timezone.now(): # 告警间隔范围内不再次触发 - return - + ecs = [cate for cate in ecs if check_same_allow_minute_and_raise_event( + cate, ep, None, obj_cate) is True] event = Event() - event.global_img = ec_codes['global_img'] if ec_codes.get('global_img', None) else save_dahua_pic(global_img_o) + event.global_img = ec_codes['global_img'] if ec_codes.get( + 'global_img', None) else save_dahua_pic(global_img_o) event.global_img_compressed = compress_global_img(event.global_img) event.vchannel = vchannel event.area = vchannel.area @@ -702,10 +741,7 @@ def snap_and_analyse(vchannel: TDevice, algo_codes: list, opl: Opl = None): def handle_xx_event_3(name: str, area: Area): cate = EventCate.objects.filter(code=name).first() if cate: - # 告警间隔内不触发 - last_event = Event.objects.filter(cates=cate, area=area, obj_cate='area').order_by('-create_time').first() - same_allow_minute = cate.same_allow_minute - if same_allow_minute >0 and last_event and last_event.create_time + timedelta(minutes=cate.same_allow_minute) > timezone.now(): + if check_same_allow_minute_and_raise_event(cate, None, area) is False: return event = Event() event.area = area @@ -716,5 +752,6 @@ def handle_xx_event_3(name: str, area: Area): 'cate': cate, 'event': event }) - voice_msg = area.name + '下有' + str(area.count_people) + '人,' + cate.name + ',请及时处理' - notify_event(event, voice_msg=voice_msg) \ No newline at end of file + voice_msg = area.name + '下有' + \ + str(area.count_people) + '人,' + cate.name + ',请及时处理' + notify_event(event, voice_msg=voice_msg)