gatewayController.py 18 KB

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