gatewayController.py 22 KB

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