gatewayController.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. # -*- coding: utf-8 -*-
  2. """
  3. @Author : Rocky
  4. @Time : 2022/5/9 10:51
  5. @File :gatewayController.py
  6. """
  7. import logging
  8. import time
  9. from django.views.generic.base import View
  10. from AnsjerPush.Config.gatewaySensorConfig import SENSOR_TYPE, EVENT_TYPE
  11. from AnsjerPush.config import LOGGER
  12. from Model.models import SensorRecord, GatewaySubDevice, GatewayPush, Device_Info, SceneLog, SmartScene, CountryModel
  13. from Object.RedisObject import RedisObject
  14. from Object.ResponseObject import ResponseObject
  15. from Object.utils import LocalDateTimeUtil
  16. from Service.CommonService import CommonService
  17. from Service.EquipmentInfoService import EquipmentInfoService
  18. from Service.HuaweiPushService.HuaweiPushService import HuaweiPushObject
  19. from Service.PushService import PushObject
  20. class GatewayView(View):
  21. def get(self, request, *args, **kwargs):
  22. request.encoding = 'utf-8'
  23. operation = kwargs.get('operation')
  24. return self.validation(request.GET, operation)
  25. def post(self, request, *args, **kwargs):
  26. request.encoding = 'utf-8'
  27. operation = kwargs.get('operation')
  28. return self.validation(request.POST, operation)
  29. def validation(self, request_dict, operation):
  30. response = ResponseObject()
  31. if operation == 'gatewayPush': # 网关推送
  32. return self.gateway_push(request_dict, response)
  33. elif operation == 'sceneLogPush': # 场景日志推送
  34. return self.scene_log_push(request_dict, response)
  35. elif operation == 'socketPush': # 插座推送
  36. return self.socket_msg_push(request_dict, response)
  37. else:
  38. return response.json(414)
  39. @classmethod
  40. def gateway_push(cls, request_dict, response):
  41. """
  42. 网关推送
  43. @param request_dict: 请求参数
  44. @request_dict serial_number: 序列号
  45. @request_dict dev_class: 设备大类
  46. @request_dict dev_type: 设备小类
  47. @request_dict ieee_addr: 长地址
  48. @request_dict param: 事件参数
  49. @request_dict defense: 防御状态,0:撤防,1:布防
  50. @param response: 响应对象
  51. @return: response
  52. """
  53. LOGGER.info('---调用网关推送接口--- request_dict:{}'.format(request_dict))
  54. serial_number = request_dict.get('serial_number', None)
  55. dev_class = int(request_dict.get('dev_class', None))
  56. dev_type = int(request_dict.get('dev_type', None))
  57. ieee_addr = request_dict.get('ieee_addr', None)
  58. param = eval(request_dict.get('param', None))
  59. defense = int(request_dict.get('defense', None))
  60. if not all([serial_number, dev_class, dev_type, ieee_addr, param]):
  61. return response.json(444)
  62. n_time = int(time.time())
  63. try:
  64. # 根据dev_class和dev_type确定sensor_type,param确定event_type列表
  65. sensor_type, event_type_list = cls.confirm_sensor_type_and_event_type(dev_class, dev_type, param)
  66. # 查询子设备表id
  67. gateway_sub_device_qs = GatewaySubDevice.objects.filter(device__serial_number=serial_number,
  68. device_type=sensor_type, ieee_addr=ieee_addr). \
  69. values('id', 'nickname', 'device__userID__region_country')
  70. if not gateway_sub_device_qs.exists():
  71. return response.json(173)
  72. country_id = gateway_sub_device_qs[0]['device__userID__region_country']
  73. lang = cls.confirm_lang(country_id)
  74. event_type_and_alarm_dict = cls.get_event_type_and_alarm_dict(lang, event_type_list)
  75. gateway_sub_device_id = gateway_sub_device_qs[0]['id']
  76. nickname = gateway_sub_device_qs[0]['nickname']
  77. for_times = 0
  78. dict_len = len(event_type_and_alarm_dict)
  79. for event_type, alarm in event_type_and_alarm_dict.items():
  80. for_times += 1
  81. sensor_record_dict = {
  82. 'gateway_sub_device_id': gateway_sub_device_id,
  83. 'alarm': alarm,
  84. 'event_type': event_type,
  85. 'created_time': n_time,
  86. }
  87. # 处理温湿度,不推送
  88. if sensor_type == SENSOR_TYPE['tem_hum_sensor'] and (
  89. event_type == EVENT_TYPE['temperature'] or event_type == EVENT_TYPE['humidity']):
  90. num = request_dict.get('num', None)
  91. num = str(int(num) / 100)
  92. sensor_record_dict['alarm'] = num
  93. SensorRecord.objects.create(**sensor_record_dict)
  94. return response.json(0)
  95. SensorRecord.objects.create(**sensor_record_dict)
  96. # 门磁传感器被拆动/拆动恢复,修改拆动状态
  97. if event_type == 2152:
  98. gateway_sub_device_qs.update(is_tampered=1)
  99. elif event_type == 2156:
  100. gateway_sub_device_qs.update(is_tampered=0)
  101. # 撤防状态,且完成遍历,不推送
  102. if defense == 0 and for_times == dict_len:
  103. return response.json(0)
  104. device_info_qs = Device_Info.objects.filter(serial_number=serial_number).values('userID_id')
  105. if not device_info_qs.exists():
  106. return response.json(173)
  107. equipment_info_list = []
  108. # 推送到每个添加了网关的账号
  109. for device_info in device_info_qs:
  110. user_id = device_info['userID_id']
  111. # 组织存储数据
  112. local_date_time = CommonService.get_now_time_str(n_time=n_time, tz=0, lang='cn')[:10]
  113. equipment_info_list.append(EquipmentInfoService.get_equipment_info_obj(
  114. local_date_time,
  115. add_time=n_time,
  116. event_time=n_time,
  117. receive_time=n_time,
  118. device_uid=serial_number,
  119. device_nick_name=nickname,
  120. alarm=alarm,
  121. event_type=event_type,
  122. device_user_id=user_id,
  123. ))
  124. if equipment_info_list:
  125. # 根据日期获得星期几
  126. week = LocalDateTimeUtil.date_to_week(local_date_time)
  127. EquipmentInfoService.equipment_info_bulk_create(week, equipment_info_list)
  128. # 查询推送配置数据
  129. gateway_push_qs = GatewayPush.objects.filter(user_id=user_id, logout=False). \
  130. values('user_id', 'app_bundle_id', 'app_type', 'push_type', 'token_val', 'm_code', 'lang',
  131. 'm_code', 'tz')
  132. if not gateway_push_qs.exists():
  133. continue
  134. kwargs = {
  135. 'n_time': n_time,
  136. 'event_type': event_type,
  137. 'nickname': nickname,
  138. }
  139. # 推送到每台登录账号的手机
  140. for gateway_push in gateway_push_qs:
  141. app_bundle_id = gateway_push['app_bundle_id']
  142. push_type = gateway_push['push_type']
  143. token_val = gateway_push['token_val']
  144. lang = gateway_push['lang']
  145. tz = gateway_push['tz'] if gateway_push['tz'] else 0
  146. # 获取推送所需数据
  147. msg_title = PushObject.get_msg_title(nickname)
  148. msg_text = PushObject.get_gateway_msg_text(n_time, tz, lang, alarm)
  149. kwargs['msg_title'] = msg_title
  150. kwargs['msg_text'] = msg_text
  151. kwargs['app_bundle_id'] = app_bundle_id
  152. kwargs['token_val'] = token_val
  153. try:
  154. # 推送消息
  155. cls.push_msg(push_type, **kwargs)
  156. except Exception as e:
  157. LOGGER.info('网关推送消息异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  158. continue
  159. return response.json(0)
  160. except Exception as e:
  161. LOGGER.info('---网关推送接口异常--- {}'.format(repr(e)))
  162. return response.json(500, repr(e))
  163. @staticmethod
  164. def confirm_sensor_type_and_event_type(dev_class, dev_type, param):
  165. """
  166. 根据dev_class和dev_type确定sensor_type,param确定event_type
  167. @param dev_class: 设备大类(开关量传感器、温湿度、灯)
  168. @param dev_type: 设备小类(传感器类型、灯类型、温湿度类型)
  169. @param param: 事件参数
  170. @return: sensor_type, event_type_list
  171. """
  172. sensor_type, event_type_list = 0, []
  173. if dev_class == 0: # 灯,待定
  174. sensor_type = 0
  175. elif dev_class == 1: # 网关
  176. sensor_type = 200
  177. elif dev_class == 2: # 开关类传感器
  178. if dev_type == 13: # 人体红外
  179. sensor_type = 219
  180. elif dev_type == 22: # 门磁
  181. sensor_type = 215
  182. elif dev_type == 42: # 水浸
  183. sensor_type = 217
  184. elif dev_type == 44: # 智能按钮
  185. sensor_type = 216
  186. elif dev_class == 3: # 测量类传感器
  187. if dev_type == 1: # 温湿度
  188. sensor_type = 220
  189. elif dev_type == 2: # 亮度,待定
  190. sensor_type = 0
  191. elif dev_class == 5: # 智能锁
  192. if dev_type == 1: # 门锁,待定
  193. sensor_type = 0
  194. elif dev_class == 6: # 电机类设备
  195. if dev_type == 1: # 窗帘,待定
  196. sensor_type = 0
  197. if sensor_type == 215: # 门磁
  198. if param['alarm'] == 1: # 门磁开
  199. event_type_list.append(2150)
  200. elif param['alarm'] == 0: # 门磁关
  201. event_type_list.append(2151)
  202. if param['tamper'] == 1: # 拆动
  203. event_type_list.append(2152)
  204. if param['tamper'] == 0: # 拆动恢复
  205. event_type_list.append(2156)
  206. if param['battery'] == 1: # 低电量
  207. event_type_list.append(2153)
  208. elif sensor_type == 216: # 智能按钮
  209. if param['alarm'] == 1: # 按下
  210. event_type_list.append(2160)
  211. if param['smrt_btn'] == 1: # 单击
  212. event_type_list.append(2161)
  213. elif param['smrt_btn'] == 2: # 双击
  214. event_type_list.append(2162)
  215. elif param['smrt_btn'] == 3: # 三击
  216. event_type_list.append(2163)
  217. if param['battery'] == 1: # 低电量
  218. event_type_list.append(2164)
  219. elif sensor_type == 217: # 水浸
  220. if param['alarm'] == 1: # 水浸触发
  221. event_type_list.append(2170)
  222. elif param['alarm'] == 0: # 水浸恢复
  223. event_type_list.append(2171)
  224. if param['battery'] == 1: # 低电量
  225. event_type_list.append(2172)
  226. elif sensor_type == 219: # 人体红外
  227. if param['alarm'] == 1: # 有人移动
  228. event_type_list.append(2190)
  229. elif param['alarm'] == 0: # 无人移动
  230. event_type_list.append(2191)
  231. if param['battery'] == 1: # 低电量
  232. event_type_list.append(2193)
  233. return sensor_type, event_type_list
  234. @staticmethod
  235. def confirm_lang(country_id):
  236. """
  237. 根据country_id确定语言
  238. @param country_id: 国家id
  239. @return lang: 语言
  240. """
  241. country_qs = CountryModel.objects.filter(id=country_id).values('country_code')
  242. if not country_qs.exists():
  243. lang = 'NA'
  244. else:
  245. lang = country_qs[0]['country_code']
  246. return lang
  247. @staticmethod
  248. def get_event_type_and_alarm_dict(lang, event_type_list):
  249. """
  250. 获取事件类型和提示字典数据
  251. @param lang: 语言
  252. @param event_type_list: 事件类型列表
  253. @return event_type_and_alarm_dict: 事件类型字典
  254. """
  255. alarm = ''
  256. event_type_and_alarm_dict = {}
  257. if lang == 'CN':
  258. for event_type in event_type_list:
  259. # 门磁
  260. if event_type == 2150:
  261. alarm = '门磁开'
  262. elif event_type == 2151:
  263. alarm = '门磁关'
  264. elif event_type == 2152:
  265. alarm = '被拆动'
  266. elif event_type == 2156:
  267. alarm = '拆动恢复'
  268. # 智能按钮
  269. elif event_type == 2160:
  270. alarm = '紧急按钮按下'
  271. elif event_type == 2161:
  272. alarm = '按钮已按1下'
  273. elif event_type == 2162:
  274. alarm = '按钮已按2下'
  275. elif event_type == 2163:
  276. alarm = '按钮已按3下'
  277. # 水浸
  278. elif event_type == 2170:
  279. alarm = '水浸触发'
  280. elif event_type == 2171:
  281. alarm = '水浸恢复'
  282. # 烟雾
  283. elif event_type == 2180:
  284. alarm = '烟雾触发'
  285. elif event_type == 2181:
  286. alarm = '烟雾恢复'
  287. # 人体红外
  288. elif event_type == 2190:
  289. alarm = '有人移动'
  290. elif event_type == 2191:
  291. alarm = '无人移动'
  292. # 低电量
  293. elif event_type in (2153, 2164, 2172, 2182, 2193):
  294. alarm = '低电量'
  295. event_type_and_alarm_dict[event_type] = alarm
  296. else:
  297. for event_type in event_type_list:
  298. # 门磁
  299. if event_type == 2150:
  300. alarm = 'Door magnetic opening'
  301. elif event_type == 2151:
  302. alarm = 'Door magnetic closing'
  303. elif event_type == 2152:
  304. alarm = 'Be dismantled'
  305. elif event_type == 2156:
  306. alarm = 'Dismantling recovery'
  307. # 智能按钮
  308. elif event_type == 2160:
  309. alarm = 'Emergency button pressed'
  310. elif event_type == 2161:
  311. alarm = 'Button pressed once'
  312. elif event_type == 2162:
  313. alarm = 'The button has been pressed twice'
  314. elif event_type == 2163:
  315. alarm = 'The button has been pressed 3 times'
  316. # 水浸
  317. elif event_type == 2170:
  318. alarm = 'Water immersion trigger'
  319. elif event_type == 2171:
  320. alarm = 'Water immersion recovery'
  321. # 烟雾
  322. elif event_type == 2180:
  323. alarm = 'Smoke triggering'
  324. elif event_type == 2181:
  325. alarm = 'Smoke recovery'
  326. # 人体红外
  327. elif event_type == 2190:
  328. alarm = 'Someone moving'
  329. elif event_type == 2191:
  330. alarm = 'Unmanned movement'
  331. # 低电量
  332. elif event_type in (2153, 2164, 2172, 2182, 2193):
  333. alarm = 'LOW BATTERY'
  334. event_type_and_alarm_dict[event_type] = alarm
  335. return event_type_and_alarm_dict
  336. @classmethod
  337. def scene_log_push(cls, request_dict, response):
  338. """
  339. 网关智能场景日志推送
  340. @param request_dict: 请求参数
  341. @request_dict sceneId: 场景id
  342. @request_dict status: 状态
  343. @param response: 响应对象
  344. @return: response
  345. """
  346. logger = logging.getLogger('info')
  347. scene_id = request_dict.get('sceneId', None)
  348. status = request_dict.get('status', None)
  349. logger.info('---场景日志推送接口--- request_dict:{}'.format(request_dict))
  350. if not all([scene_id, status]):
  351. return response.json(444)
  352. smart_scene_qs = SmartScene.objects.filter(id=scene_id).values('scene_name', 'conditions', 'tasks', 'device_id',
  353. 'sub_device_id', 'user_id')
  354. if not smart_scene_qs.exists():
  355. return response.json(173)
  356. scene_name = smart_scene_qs[0]['scene_name']
  357. tasks = smart_scene_qs[0]['tasks']
  358. device_id = smart_scene_qs[0]['device_id']
  359. sub_device_id = smart_scene_qs[0]['sub_device_id']
  360. n_time = int(time.time())
  361. user_id = smart_scene_qs[0]['user_id']
  362. if sub_device_id:
  363. gateway_sub_device_qs = GatewaySubDevice.objects.filter(id=sub_device_id).values('nickname')
  364. nickname = gateway_sub_device_qs[0]['nickname'] if gateway_sub_device_qs.exists() else ''
  365. else:
  366. device_qs = Device_Info.objects.filter(id=device_id).values('NickName')
  367. nickname = device_qs[0]['NickName'] if device_qs.exists() else ''
  368. log_dict = {
  369. 'scene_id': scene_id,
  370. 'scene_name': scene_name,
  371. 'tasks': tasks,
  372. 'status': status,
  373. 'device_id': device_id,
  374. 'sub_device_id': sub_device_id,
  375. 'created_time': n_time,
  376. }
  377. tasks = eval(tasks)
  378. try:
  379. SceneLog.objects.create(**log_dict)
  380. # 推送日志
  381. gateway_push_qs = GatewayPush.objects.filter(user_id=user_id, logout=False). \
  382. values('user_id', 'app_bundle_id', 'app_type', 'push_type', 'token_val', 'm_code', 'lang', 'm_code',
  383. 'tz')
  384. if not gateway_push_qs.exists():
  385. return response.json(174)
  386. for task in tasks:
  387. event_type = task['event_type']
  388. if event_type == '1001':
  389. kwargs = {
  390. 'n_time': n_time,
  391. 'event_type': event_type,
  392. 'nickname': nickname,
  393. }
  394. event_info = task['value']
  395. # 推送到每台登录账号的手机
  396. for gateway_push in gateway_push_qs:
  397. app_bundle_id = gateway_push['app_bundle_id']
  398. push_type = gateway_push['push_type']
  399. token_val = gateway_push['token_val']
  400. kwargs['msg_title'] = PushObject.get_msg_title(nickname)
  401. kwargs['msg_text'] = event_info
  402. kwargs['app_bundle_id'] = app_bundle_id
  403. kwargs['token_val'] = token_val
  404. try:
  405. # 推送消息
  406. cls.push_msg(push_type, **kwargs)
  407. except Exception as e:
  408. logger.info('场景日志推送消息异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  409. continue
  410. return response.json(0)
  411. except Exception as e:
  412. logger.info('---场景日志推送接口异常--- {}'.format(repr(e)))
  413. return response.json(500, repr(e))
  414. @staticmethod
  415. def push_msg(push_type, **kwargs):
  416. """
  417. 发送推送消息
  418. @param push_type: 推送类型
  419. @param kwargs: 推送参数
  420. @return: None
  421. """
  422. if push_type == 0: # ios apns
  423. PushObject.ios_apns_push(**kwargs)
  424. elif push_type == 1: # android gcm
  425. PushObject.android_fcm_push(**kwargs)
  426. elif push_type == 2: # android 极光推送
  427. PushObject.android_jpush(**kwargs)
  428. elif push_type == 3:
  429. huawei_push_object = HuaweiPushObject()
  430. huawei_push_object.send_push_notify_message(**kwargs)
  431. elif push_type == 4: # android 小米推送
  432. channel_id = 104551
  433. PushObject.android_xmpush(channel_id=channel_id, **kwargs)
  434. elif push_type == 5: # android vivo推送
  435. PushObject.android_vivopush(**kwargs)
  436. elif push_type == 6: # android oppo推送
  437. channel_id = 'DEVICE_REMINDER'
  438. PushObject.android_oppopush(channel_id=channel_id, **kwargs)
  439. elif push_type == 7: # android 魅族推送
  440. PushObject.android_meizupush(**kwargs)
  441. @classmethod
  442. def socket_msg_push(cls, request_dict, response):
  443. """
  444. 智能插座开关状态推送
  445. """
  446. logger = logging.getLogger('info')
  447. try:
  448. switch_key = 'LOOCAM:SOCKET:SERIAL:NUMBER:{}'
  449. redis_obj = RedisObject(db=7)
  450. serial_number = request_dict.get('serialNumber', None)
  451. status = request_dict.get('status', None)
  452. if not all([serial_number, status]):
  453. return response.json(444)
  454. status = int(status)
  455. switch_key = switch_key.format(serial_number)
  456. switch = redis_obj.get_data(switch_key)
  457. if switch and int(switch) == status:
  458. return response.json(0, "电源开关状态重复上报")
  459. now_time = int(time.time())
  460. LOGGER.info('已订阅成功接收:事件类型{},状态:{}'.format(serial_number, status))
  461. # 获取主用户设备id
  462. log_dict = {
  463. 'status': status,
  464. 'device_id': serial_number,
  465. 'created_time': now_time,
  466. }
  467. SceneLog.objects.create(**log_dict)
  468. redis_obj.set_data(switch_key, status, 60 * 3)
  469. return response.json(0)
  470. except Exception as e:
  471. logger.info('---插座开关日志推送接口异常--- {}'.format(repr(e)))
  472. return response.json(500, repr(e))