# -*- coding: utf-8 -*- """ @Author : Rocky @Time : 2022/5/9 10:51 @File :gatewayController.py """ import logging import time from django.views.generic.base import View from AnsjerPush.Config.gatewaySensorConfig import SENSOR_TYPE, EVENT_TYPE from AnsjerPush.config import LOGGER from Model.models import SensorRecord, GatewaySubDevice, GatewayPush, Device_Info, SceneLog, SmartScene, CountryModel from Object.RedisObject import RedisObject from Object.ResponseObject import ResponseObject from Object.utils import LocalDateTimeUtil from Service.CommonService import CommonService from Service.EquipmentInfoService import EquipmentInfoService from Service.HuaweiPushService.HuaweiPushService import HuaweiPushObject from Service.PushService import PushObject class GatewayView(View): def get(self, request, *args, **kwargs): request.encoding = 'utf-8' operation = kwargs.get('operation') return self.validation(request.GET, operation) def post(self, request, *args, **kwargs): request.encoding = 'utf-8' operation = kwargs.get('operation') return self.validation(request.POST, operation) def validation(self, request_dict, operation): response = ResponseObject() if operation == 'gatewayPush': # 网关推送 return self.gateway_push(request_dict, response) elif operation == 'sceneLogPush': # 场景日志推送 return self.scene_log_push(request_dict, response) elif operation == 'socketPush': # 插座推送 return self.socket_msg_push(request_dict, response) else: return response.json(414) @classmethod def gateway_push(cls, request_dict, response): """ 网关推送 @param request_dict: 请求参数 @request_dict serial_number: 序列号 @request_dict dev_class: 设备大类 @request_dict dev_type: 设备小类 @request_dict ieee_addr: 长地址 @request_dict param: 事件参数 @request_dict defense: 防御状态,0:撤防,1:布防 @param response: 响应对象 @return: response """ LOGGER.info('---调用网关推送接口--- request_dict:{}'.format(request_dict)) serial_number = request_dict.get('serial_number', None) dev_class = int(request_dict.get('dev_class', None)) dev_type = int(request_dict.get('dev_type', None)) ieee_addr = request_dict.get('ieee_addr', None) param = eval(request_dict.get('param', None)) defense = int(request_dict.get('defense', None)) if not all([serial_number, dev_class, dev_type, ieee_addr, param]): return response.json(444) n_time = int(time.time()) try: # 根据dev_class和dev_type确定sensor_type,param确定event_type列表 sensor_type, event_type_list = cls.confirm_sensor_type_and_event_type(dev_class, dev_type, param) # 查询子设备表id gateway_sub_device_qs = GatewaySubDevice.objects.filter(device__serial_number=serial_number, device_type=sensor_type, ieee_addr=ieee_addr). \ values('id', 'nickname', 'device__userID__region_country') if not gateway_sub_device_qs.exists(): return response.json(173) country_id = gateway_sub_device_qs[0]['device__userID__region_country'] lang = cls.confirm_lang(country_id) event_type_and_alarm_dict = cls.get_event_type_and_alarm_dict(lang, event_type_list) gateway_sub_device_id = gateway_sub_device_qs[0]['id'] nickname = gateway_sub_device_qs[0]['nickname'] for_times = 0 dict_len = len(event_type_and_alarm_dict) for event_type, alarm in event_type_and_alarm_dict.items(): for_times += 1 sensor_record_dict = { 'gateway_sub_device_id': gateway_sub_device_id, 'alarm': alarm, 'event_type': event_type, 'created_time': n_time, } # 处理温湿度,不推送 if sensor_type == SENSOR_TYPE['tem_hum_sensor'] and ( event_type == EVENT_TYPE['temperature'] or event_type == EVENT_TYPE['humidity']): num = request_dict.get('num', None) num = str(int(num) / 100) sensor_record_dict['alarm'] = num SensorRecord.objects.create(**sensor_record_dict) return response.json(0) SensorRecord.objects.create(**sensor_record_dict) # 门磁传感器被拆动/拆动恢复,修改拆动状态 if event_type == 2152: gateway_sub_device_qs.update(is_tampered=1) elif event_type == 2156: gateway_sub_device_qs.update(is_tampered=0) # 撤防状态,且完成遍历,不推送 if defense == 0 and for_times == dict_len: return response.json(0) device_info_qs = Device_Info.objects.filter(serial_number=serial_number).values('userID_id') if not device_info_qs.exists(): return response.json(173) equipment_info_list = [] # 推送到每个添加了网关的账号 for device_info in device_info_qs: user_id = device_info['userID_id'] # 组织存储数据 local_date_time = CommonService.get_now_time_str(n_time=n_time, tz=0, lang='cn')[:10] equipment_info_list.append(EquipmentInfoService.get_equipment_info_obj( local_date_time, add_time=n_time, event_time=n_time, receive_time=n_time, device_uid=serial_number, device_nick_name=nickname, alarm=alarm, event_type=event_type, device_user_id=user_id, )) if equipment_info_list: # 根据日期获得星期几 week = LocalDateTimeUtil.date_to_week(local_date_time) EquipmentInfoService.equipment_info_bulk_create(week, equipment_info_list) # 查询推送配置数据 gateway_push_qs = GatewayPush.objects.filter(user_id=user_id, logout=False). \ values('user_id', 'app_bundle_id', 'app_type', 'push_type', 'token_val', 'm_code', 'lang', 'm_code', 'tz') if not gateway_push_qs.exists(): continue kwargs = { 'n_time': n_time, 'event_type': event_type, 'nickname': nickname, } # 推送到每台登录账号的手机 for gateway_push in gateway_push_qs: app_bundle_id = gateway_push['app_bundle_id'] push_type = gateway_push['push_type'] token_val = gateway_push['token_val'] lang = gateway_push['lang'] tz = gateway_push['tz'] if gateway_push['tz'] else 0 # 获取推送所需数据 msg_title = PushObject.get_msg_title(nickname) msg_text = PushObject.get_gateway_msg_text(n_time, tz, lang, alarm) kwargs['msg_title'] = msg_title kwargs['msg_text'] = msg_text kwargs['app_bundle_id'] = app_bundle_id kwargs['token_val'] = token_val try: # 推送消息 cls.push_msg(push_type, **kwargs) except Exception as e: LOGGER.info('网关推送消息异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e))) continue return response.json(0) except Exception as e: LOGGER.info('---网关推送接口异常--- {}'.format(repr(e))) return response.json(500, repr(e)) @staticmethod def confirm_sensor_type_and_event_type(dev_class, dev_type, param): """ 根据dev_class和dev_type确定sensor_type,param确定event_type @param dev_class: 设备大类(开关量传感器、温湿度、灯) @param dev_type: 设备小类(传感器类型、灯类型、温湿度类型) @param param: 事件参数 @return: sensor_type, event_type_list """ sensor_type, event_type_list = 0, [] if dev_class == 0: # 灯,待定 sensor_type = 0 elif dev_class == 1: # 网关 sensor_type = 200 elif dev_class == 2: # 开关类传感器 if dev_type == 13: # 人体红外 sensor_type = 219 elif dev_type == 22: # 门磁 sensor_type = 215 elif dev_type == 42: # 水浸 sensor_type = 217 elif dev_type == 44: # 智能按钮 sensor_type = 216 elif dev_class == 3: # 测量类传感器 if dev_type == 1: # 温湿度 sensor_type = 220 elif dev_type == 2: # 亮度,待定 sensor_type = 0 elif dev_class == 5: # 智能锁 if dev_type == 1: # 门锁,待定 sensor_type = 0 elif dev_class == 6: # 电机类设备 if dev_type == 1: # 窗帘,待定 sensor_type = 0 if sensor_type == 215: # 门磁 if param['alarm'] == 1: # 门磁开 event_type_list.append(2150) elif param['alarm'] == 0: # 门磁关 event_type_list.append(2151) if param['tamper'] == 1: # 拆动 event_type_list.append(2152) if param['tamper'] == 0: # 拆动恢复 event_type_list.append(2156) if param['battery'] == 1: # 低电量 event_type_list.append(2153) elif sensor_type == 216: # 智能按钮 if param['alarm'] == 1: # 按下 event_type_list.append(2160) if param['smrt_btn'] == 1: # 单击 event_type_list.append(2161) elif param['smrt_btn'] == 2: # 双击 event_type_list.append(2162) elif param['smrt_btn'] == 3: # 三击 event_type_list.append(2163) if param['battery'] == 1: # 低电量 event_type_list.append(2164) elif sensor_type == 217: # 水浸 if param['alarm'] == 1: # 水浸触发 event_type_list.append(2170) elif param['alarm'] == 0: # 水浸恢复 event_type_list.append(2171) if param['battery'] == 1: # 低电量 event_type_list.append(2172) elif sensor_type == 219: # 人体红外 if param['alarm'] == 1: # 有人移动 event_type_list.append(2190) elif param['alarm'] == 0: # 无人移动 event_type_list.append(2191) if param['battery'] == 1: # 低电量 event_type_list.append(2193) return sensor_type, event_type_list @staticmethod def confirm_lang(country_id): """ 根据country_id确定语言 @param country_id: 国家id @return lang: 语言 """ country_qs = CountryModel.objects.filter(id=country_id).values('country_code') if not country_qs.exists(): lang = 'NA' else: lang = country_qs[0]['country_code'] return lang @staticmethod def get_event_type_and_alarm_dict(lang, event_type_list): """ 获取事件类型和提示字典数据 @param lang: 语言 @param event_type_list: 事件类型列表 @return event_type_and_alarm_dict: 事件类型字典 """ alarm = '' event_type_and_alarm_dict = {} if lang == 'CN': for event_type in event_type_list: # 门磁 if event_type == 2150: alarm = '门磁开' elif event_type == 2151: alarm = '门磁关' elif event_type == 2152: alarm = '被拆动' elif event_type == 2156: alarm = '拆动恢复' # 智能按钮 elif event_type == 2160: alarm = '紧急按钮按下' elif event_type == 2161: alarm = '按钮已按1下' elif event_type == 2162: alarm = '按钮已按2下' elif event_type == 2163: alarm = '按钮已按3下' # 水浸 elif event_type == 2170: alarm = '水浸触发' elif event_type == 2171: alarm = '水浸恢复' # 烟雾 elif event_type == 2180: alarm = '烟雾触发' elif event_type == 2181: alarm = '烟雾恢复' # 人体红外 elif event_type == 2190: alarm = '有人移动' elif event_type == 2191: alarm = '无人移动' # 低电量 elif event_type in (2153, 2164, 2172, 2182, 2193): alarm = '低电量' event_type_and_alarm_dict[event_type] = alarm else: for event_type in event_type_list: # 门磁 if event_type == 2150: alarm = 'Door magnetic opening' elif event_type == 2151: alarm = 'Door magnetic closing' elif event_type == 2152: alarm = 'Be dismantled' elif event_type == 2156: alarm = 'Dismantling recovery' # 智能按钮 elif event_type == 2160: alarm = 'Emergency button pressed' elif event_type == 2161: alarm = 'Button pressed once' elif event_type == 2162: alarm = 'The button has been pressed twice' elif event_type == 2163: alarm = 'The button has been pressed 3 times' # 水浸 elif event_type == 2170: alarm = 'Water immersion trigger' elif event_type == 2171: alarm = 'Water immersion recovery' # 烟雾 elif event_type == 2180: alarm = 'Smoke triggering' elif event_type == 2181: alarm = 'Smoke recovery' # 人体红外 elif event_type == 2190: alarm = 'Someone moving' elif event_type == 2191: alarm = 'Unmanned movement' # 低电量 elif event_type in (2153, 2164, 2172, 2182, 2193): alarm = 'LOW BATTERY' event_type_and_alarm_dict[event_type] = alarm return event_type_and_alarm_dict @classmethod def scene_log_push(cls, request_dict, response): """ 网关智能场景日志推送 @param request_dict: 请求参数 @request_dict sceneId: 场景id @request_dict status: 状态 @param response: 响应对象 @return: response """ logger = logging.getLogger('info') scene_id = request_dict.get('sceneId', None) status = request_dict.get('status', None) logger.info('---场景日志推送接口--- request_dict:{}'.format(request_dict)) if not all([scene_id, status]): return response.json(444) smart_scene_qs = SmartScene.objects.filter(id=scene_id).values('scene_name', 'conditions', 'tasks', 'device_id', 'sub_device_id', 'user_id') if not smart_scene_qs.exists(): return response.json(173) scene_name = smart_scene_qs[0]['scene_name'] tasks = smart_scene_qs[0]['tasks'] device_id = smart_scene_qs[0]['device_id'] sub_device_id = smart_scene_qs[0]['sub_device_id'] n_time = int(time.time()) user_id = smart_scene_qs[0]['user_id'] if sub_device_id: gateway_sub_device_qs = GatewaySubDevice.objects.filter(id=sub_device_id).values('nickname') nickname = gateway_sub_device_qs[0]['nickname'] if gateway_sub_device_qs.exists() else '' else: device_qs = Device_Info.objects.filter(id=device_id).values('NickName') nickname = device_qs[0]['NickName'] if device_qs.exists() else '' log_dict = { 'scene_id': scene_id, 'scene_name': scene_name, 'tasks': tasks, 'status': status, 'device_id': device_id, 'sub_device_id': sub_device_id, 'created_time': n_time, } tasks = eval(tasks) try: SceneLog.objects.create(**log_dict) # 推送日志 gateway_push_qs = GatewayPush.objects.filter(user_id=user_id, logout=False). \ values('user_id', 'app_bundle_id', 'app_type', 'push_type', 'token_val', 'm_code', 'lang', 'm_code', 'tz') if not gateway_push_qs.exists(): return response.json(174) for task in tasks: event_type = task['event_type'] if event_type == '1001': kwargs = { 'n_time': n_time, 'event_type': event_type, 'nickname': nickname, } event_info = task['value'] # 推送到每台登录账号的手机 for gateway_push in gateway_push_qs: app_bundle_id = gateway_push['app_bundle_id'] push_type = gateway_push['push_type'] token_val = gateway_push['token_val'] kwargs['msg_title'] = PushObject.get_msg_title(nickname) kwargs['msg_text'] = event_info kwargs['app_bundle_id'] = app_bundle_id kwargs['token_val'] = token_val try: # 推送消息 cls.push_msg(push_type, **kwargs) except Exception as e: logger.info('场景日志推送消息异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e))) continue return response.json(0) except Exception as e: logger.info('---场景日志推送接口异常--- {}'.format(repr(e))) return response.json(500, repr(e)) @staticmethod def push_msg(push_type, **kwargs): """ 发送推送消息 @param push_type: 推送类型 @param kwargs: 推送参数 @return: None """ if push_type == 0: # ios apns PushObject.ios_apns_push(**kwargs) elif push_type == 1: # android gcm PushObject.android_fcm_push(**kwargs) elif push_type == 2: # android 极光推送 PushObject.android_jpush(**kwargs) elif push_type == 3: huawei_push_object = HuaweiPushObject() huawei_push_object.send_push_notify_message(**kwargs) elif push_type == 4: # android 小米推送 channel_id = 104551 PushObject.android_xmpush(channel_id=channel_id, **kwargs) elif push_type == 5: # android vivo推送 PushObject.android_vivopush(**kwargs) elif push_type == 6: # android oppo推送 channel_id = 'DEVICE_REMINDER' PushObject.android_oppopush(channel_id=channel_id, **kwargs) elif push_type == 7: # android 魅族推送 PushObject.android_meizupush(**kwargs) @classmethod def socket_msg_push(cls, request_dict, response): """ 智能插座开关状态推送 """ logger = logging.getLogger('info') try: switch_key = 'LOOCAM:SOCKET:SERIAL:NUMBER:{}' redis_obj = RedisObject(db=7) serial_number = request_dict.get('serialNumber', None) status = request_dict.get('status', None) if not all([serial_number, status]): return response.json(444) status = int(status) switch_key = switch_key.format(serial_number) switch = redis_obj.get_data(switch_key) if switch and int(switch) == status: return response.json(0, "电源开关状态重复上报") now_time = int(time.time()) LOGGER.info('已订阅成功接收:事件类型{},状态:{}'.format(serial_number, status)) # 获取主用户设备id log_dict = { 'status': status, 'device_id': serial_number, 'created_time': now_time, } SceneLog.objects.create(**log_dict) redis_obj.set_data(switch_key, status, 60 * 3) return response.json(0) except Exception as e: logger.info('---插座开关日志推送接口异常--- {}'.format(repr(e))) return response.json(500, repr(e))