SmartSceneController.py 69 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526
  1. # -*- coding: utf-8 -*-
  2. """
  3. @Author : Rocky
  4. @Time : 2022/6/29 9:31
  5. @File :SmartSceneController.py
  6. """
  7. import json
  8. import time
  9. import requests
  10. from django.core.exceptions import ObjectDoesNotExist
  11. from django.db import transaction
  12. from django.db.models import F, Q, Count
  13. from django.views import View
  14. from Ansjer.config import DETECT_PUSH_DOMAINS
  15. from Ansjer.Config.gatewaySensorConfig import SMART_SCENE_TOPIC, SENSOR_TYPE, EVENT_TYPE, SCENE_EVENT_CREATE, \
  16. SCENE_EVENT_EDIT, SCENE_EVENT_DELETE, SCENE_STATUS_ON, SCENE_STATUS_OFF, SCENE_EVENT_EDIT_STATUS, \
  17. VOICE_AUDITION_TOPIC, SMART_SOCKET_TOPIC, DEVICE_TYPE
  18. from Model.models import FamilyRoomDevice, GatewaySubDevice, FamilyRoom, SmartScene, EffectiveTime, Device_Info, \
  19. SceneLog
  20. from Object.ApschedulerObject import ApschedulerObject
  21. from Object.ResponseObject import ResponseObject
  22. from Service.CommonService import CommonService
  23. class SmartSceneView(View):
  24. def get(self, request, *args, **kwargs):
  25. request.encoding = 'utf-8'
  26. operation = kwargs.get('operation')
  27. return self.validation(request.GET, request, operation)
  28. def post(self, request, *args, **kwargs):
  29. request.encoding = 'utf-8'
  30. operation = kwargs.get('operation')
  31. return self.validation(request.POST, request, operation)
  32. def validation(self, request_dict, request, operation):
  33. if operation == 'get-scene': # 设备获取智能场景数据
  34. return self.get_scene_data(request_dict, ResponseObject('cn'))
  35. token_code, user_id, response = CommonService.verify_token_get_user_id(request_dict, request)
  36. if token_code != 0:
  37. return response.json(token_code)
  38. if operation == 'condition-devices': # 添加条件-查询设备
  39. return self.condition_devices(request_dict, response)
  40. elif operation == 'task-devices': # 添加任务-查询设备
  41. return self.task_devices(request_dict, user_id, response)
  42. elif operation == 'create': # 创建智能场景
  43. return self.create_smart_scene(request_dict, user_id, response)
  44. elif operation == 'scene-list': # 查询智能场景列表
  45. return self.scene_list(request_dict, user_id, response)
  46. elif operation == 'smart-button-scene-list': # 查询智能按钮场景列表
  47. return self.smart_button_scene_list(request_dict, user_id, response)
  48. elif operation == 'update-status': # 更新智能场景状态
  49. return self.update_status(request_dict, response)
  50. elif operation == 'detail': # 查询智能场景详情
  51. return self.scene_detail(request_dict, response)
  52. elif operation == 'edit': # 编辑智能场景
  53. return self.edit_smart_scene(request_dict, user_id, response)
  54. elif operation == 'delete': # 删除智能场景
  55. return self.delete_smart_scene(request_dict, response)
  56. elif operation == 'log': # 查询智能场景日志
  57. return self.scene_log(request_dict, response)
  58. elif operation == 'log-date': # 查询智能场景日志日期
  59. return self.scene_log_date(request_dict, response)
  60. elif operation == 'voice-audition': # 智能场景音频试听
  61. return self.voice_audition(request_dict, response)
  62. else:
  63. return response.json(414)
  64. @classmethod
  65. def condition_devices(cls, request_dict, response):
  66. """
  67. 添加条件-查询设备
  68. @param request_dict: 请求参数
  69. @request_dict deviceId: 网关设备id
  70. @request_dict subDeviceId: 子设备id
  71. @param response: 响应对象
  72. @return: response
  73. """
  74. device_id = request_dict.get('deviceId', None)
  75. sub_device_id = request_dict.get('subDeviceId', None)
  76. if not any([device_id, sub_device_id]):
  77. return response.json(444, {'error param': 'deviceId or subDeviceId'})
  78. try:
  79. if sub_device_id:
  80. device_id = GatewaySubDevice.objects.get(id=sub_device_id).device_id
  81. gateway_sub_device_qs = GatewaySubDevice.objects.filter(device_id=device_id)
  82. if not gateway_sub_device_qs.exists():
  83. return response.json(173)
  84. res = cls.get_sub_device_room_name(gateway_sub_device_qs)
  85. return response.json(0, res)
  86. except Exception as e:
  87. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  88. @classmethod
  89. def task_devices(cls, request_dict, user_id, response):
  90. """
  91. 添加任务-查询设备
  92. @param request_dict: 请求参数
  93. @request_dict deviceId: 网关设备id
  94. @param user_id: 用户id
  95. @param response: 响应对象
  96. @return: response
  97. """
  98. sub_device_id = request_dict.get('subDeviceId', None)
  99. device_id = request_dict.get('deviceId', None)
  100. if not any([device_id, sub_device_id]):
  101. return response.json(444, {'error param': 'deviceId or subDeviceId'})
  102. try:
  103. if device_id:
  104. res = [cls.get_gateway_data(device_id)]
  105. else:
  106. sub_device_qs = GatewaySubDevice.objects.filter(id=sub_device_id).values('device_id', 'device_type')
  107. device_id = sub_device_qs[0]['device_id']
  108. device_type = sub_device_qs[0]['device_type']
  109. if device_type != SENSOR_TYPE['smart_button']: # 非智能按钮只返回网关
  110. res = [cls.get_gateway_data(device_id)]
  111. else: # 智能按钮返回网关,门磁和人体传感器(如果存在)
  112. gateway_data = cls.get_gateway_data(device_id)
  113. sub_device_qs = GatewaySubDevice.objects.filter(
  114. Q(Q(device_id=device_id) & Q(device_type=SENSOR_TYPE['door_magnet'])) |
  115. Q(Q(device_id=device_id) & Q(device_type=SENSOR_TYPE['body_sensor']))
  116. ).values('id', 'nickname', 'status', 'device_type')
  117. if sub_device_qs.exists():
  118. res = cls.get_sub_device_room_name(sub_device_qs, gateway_data)
  119. else:
  120. res = [gateway_data]
  121. # 添加插座和开关数据
  122. res = cls.append_plug_and_switch_data(res, user_id)
  123. return response.json(0, res)
  124. except Exception as e:
  125. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  126. @staticmethod
  127. def get_sub_device_room_name(sub_device_qs, gateway_data=None):
  128. """
  129. 获取房间名称
  130. @param sub_device_qs: 子设备信息
  131. @param gateway_data: 网关参数
  132. @return: sub_device_list
  133. """
  134. sub_device_list = []
  135. if gateway_data:
  136. sub_device_list.append(gateway_data)
  137. sub_device_qs = sub_device_qs.annotate(gatewaySubId=F('id'),
  138. deviceType=F('device_type'),
  139. deviceNickName=F('nickname')). \
  140. values('gatewaySubId', 'deviceType', 'deviceNickName', 'status')
  141. for sub_device in sub_device_qs:
  142. family_room_device_qs = FamilyRoomDevice.objects.filter(sub_device=sub_device['gatewaySubId']). \
  143. values('room_id')
  144. if not family_room_device_qs.exists():
  145. sub_device['roomName'] = ''
  146. else:
  147. room_id = family_room_device_qs[0]['room_id']
  148. try:
  149. sub_device['roomName'] = FamilyRoom.objects.get(id=room_id).name
  150. except ObjectDoesNotExist:
  151. sub_device['roomName'] = ''
  152. sub_device_list.append(sub_device)
  153. return sub_device_list
  154. @staticmethod
  155. def get_gateway_data(device_id):
  156. """
  157. 获取网关数据
  158. @param device_id: 网关设备id
  159. @return: res
  160. """
  161. device_info_qs = Device_Info.objects.filter(id=device_id).values('NickName', 'Type', 'serial_number')
  162. nickname = device_info_qs[0]['NickName']
  163. device_type = device_info_qs[0]['Type']
  164. serial_number = device_info_qs[0]['serial_number']
  165. room_id = FamilyRoomDevice.objects.filter(device_id=device_id).values('room_id')[0]['room_id']
  166. room_id_qs = FamilyRoom.objects.filter(id=room_id).values('name')
  167. room_name = room_id_qs.first()['name'] if room_id_qs.exists() else ''
  168. res = {
  169. 'serialNumber': serial_number,
  170. 'deviceNickName': nickname,
  171. 'deviceType': device_type,
  172. 'roomName': room_name,
  173. 'status': 1,
  174. }
  175. return res
  176. @staticmethod
  177. def append_plug_and_switch_data(res, user_id):
  178. """
  179. 添加插座和开关数据
  180. @param res: 网关等设备数据
  181. @param user_id: 用户id
  182. @return: res
  183. """
  184. device_info_qs = Device_Info.objects.filter(userID_id=user_id, Type__in=[DEVICE_TYPE['socket']]).\
  185. values('id', 'NickName', 'Type', 'serial_number')
  186. if device_info_qs.exists():
  187. for device_info in device_info_qs:
  188. nickname = device_info['NickName']
  189. device_type = device_info['Type']
  190. serial_number = device_info['serial_number']
  191. device_id = device_info['id']
  192. room_id = FamilyRoomDevice.objects.filter(device_id=device_id).values('room_id')[0]['room_id']
  193. room_id_qs = FamilyRoom.objects.filter(id=room_id).values('name')
  194. room_name = room_id_qs.first()['name'] if room_id_qs.exists() else ''
  195. data = {
  196. 'serialNumber': serial_number,
  197. 'deviceNickName': nickname,
  198. 'deviceType': device_type,
  199. 'roomName': room_name,
  200. 'status': 1,
  201. }
  202. res.append(data)
  203. return res
  204. @classmethod
  205. def create_smart_scene(cls, request_dict, user_id, response):
  206. """
  207. 创建智能场景
  208. @param request_dict: 请求参数
  209. @param user_id: 用户id
  210. @request_dict deviceId: 网关设备id
  211. @request_dict subDeviceId: 子设备id
  212. @request_dict sceneName: 场景名称
  213. @request_dict conditions: 条件
  214. @request_dict tasks: 任务
  215. @request_dict isAllDay: 是否全天执行
  216. @request_dict startTime: 开始时间
  217. @request_dict endTime: 结束时间
  218. @request_dict repeat: 重复周期
  219. @param response: 响应对象
  220. @return: response
  221. """
  222. device_id = request_dict.get('deviceId', None)
  223. sub_device_id = request_dict.get('subDeviceId', None)
  224. scene_name = request_dict.get('sceneName', None)
  225. conditions = request_dict.get('conditions', None)
  226. tasks = request_dict.get('tasks', None)
  227. is_all_day = request_dict.get('isAllDay', None)
  228. if not all([scene_name, conditions, tasks]):
  229. return response.json(444, {'error param': 'scene_name and conditions and tasks'})
  230. now_time = int(time.time())
  231. conditions_dict = eval(conditions)
  232. tasks_list = eval(tasks)
  233. try:
  234. # 判断是否已存在该场景名
  235. smart_scene_qs = SmartScene.objects.filter(user_id=user_id, scene_name=scene_name)
  236. if smart_scene_qs.exists():
  237. return response.json(179)
  238. tz = CommonService.get_user_tz(user_id)
  239. smart_scene_dict = {
  240. 'user_id': user_id,
  241. 'scene_name': scene_name,
  242. 'conditions': conditions,
  243. 'tasks': tasks,
  244. 'tz': tz,
  245. 'created_time': now_time,
  246. 'updated_time': now_time,
  247. }
  248. msg = {
  249. 'scene_event': SCENE_EVENT_CREATE,
  250. 'scene_status': SCENE_STATUS_ON
  251. }
  252. # 处理设置时间
  253. if is_all_day is not None:
  254. is_all_day = int(is_all_day)
  255. smart_scene_dict['is_all_day'] = is_all_day
  256. # 判断条件是否为设置时间
  257. is_set_time, minutes, repeat = False, 0, 0
  258. if conditions_dict['type'] == 1:
  259. is_set_time = True
  260. minutes = conditions_dict['time']['minutes']
  261. repeat = conditions_dict['time']['repeat']
  262. # 条件为设置时间
  263. if is_set_time:
  264. if not device_id:
  265. return response.json(444, {'error param': 'deviceId'})
  266. smart_scene_dict['device_id'] = device_id
  267. device_info_qs = Device_Info.objects.filter(id=device_id).values('serial_number')
  268. if not device_info_qs.exists():
  269. return response.json(173)
  270. serial_number = device_info_qs[0]['serial_number']
  271. # 网关数据
  272. msg['sensor_type'] = DEVICE_TYPE['gateway']
  273. msg['sensor_status'] = 2002
  274. msg['sensor_ieee_addr'] = 'FFFFFFFFFFFFFFFF'
  275. # 条件为传感器设备
  276. else:
  277. if not sub_device_id:
  278. return response.json(444, {'error param': 'subDeviceId'})
  279. # 查询数据
  280. sub_device_qs = GatewaySubDevice.objects.filter(id=sub_device_id).\
  281. values('device__serial_number', 'ieee_addr', 'is_tampered')
  282. if not sub_device_qs.exists():
  283. return response.json(173)
  284. if cls.time_conflict(sub_device_id, conditions, is_all_day, request_dict):
  285. return response.json(182)
  286. device_type = int(conditions_dict['sensor']['device_type'])
  287. # 智能按钮不能创建触发条件相同的场景
  288. if device_type == SENSOR_TYPE['smart_button']:
  289. event_type = conditions_dict['sensor']['eventValues'][0]['event_type']
  290. smart_scene_qs = SmartScene.objects.filter(sub_device_id=sub_device_id,
  291. conditions__contains=event_type)
  292. if smart_scene_qs.exists():
  293. return response.json(180)
  294. # 紧急按钮打开时,创建的场景状态默认为关闭
  295. if sub_device_qs[0]['is_tampered'] == 1:
  296. smart_scene_dict['is_enable'] = False
  297. # 温湿度传感器返回温湿度
  298. elif device_type == SENSOR_TYPE['tem_hum_sensor']:
  299. event_values = conditions_dict['sensor']['eventValues'][0]
  300. if '≥' in event_values['value']:
  301. replace_str = '≥ '
  302. msg['sensor_symbol'] = 2
  303. else:
  304. replace_str = '≤ '
  305. msg['sensor_symbol'] = 1
  306. value = event_values['value'].replace(replace_str, '')
  307. msg['sensor_data'] = float(value)
  308. smart_scene_dict['sub_device_id'] = sub_device_id
  309. serial_number = sub_device_qs[0]['device__serial_number']
  310. msg['sensor_type'] = int(conditions_dict['sensor']['device_type'])
  311. msg['sensor_ieee_addr'] = sub_device_qs[0]['ieee_addr']
  312. msg['sensor_status'] = int(conditions_dict['sensor']['eventValues'][0]['event_type'])
  313. with transaction.atomic():
  314. if is_all_day is None: # 不设置时间
  315. smart_scene_qs = SmartScene.objects.create(**smart_scene_dict)
  316. # 设备的time数据,分钟转为秒
  317. time_dict = {
  318. 'start_time': conditions_dict['time']['minutes'] * 60,
  319. 'repeat': conditions_dict['time']['repeat']
  320. }
  321. elif is_all_day == 1: # 全天
  322. smart_scene_qs = SmartScene.objects.create(**smart_scene_dict)
  323. # 设备的time数据
  324. time_dict = {
  325. 'is_all_day': is_all_day
  326. }
  327. elif is_all_day == 2: # 非全天
  328. start_time = int(request_dict.get('startTime', None))
  329. end_time = int(request_dict.get('endTime', None))
  330. repeat = int(request_dict.get('repeat', None))
  331. effective_time_qs = EffectiveTime.objects.filter(start_time=start_time, end_time=end_time,
  332. repeat=repeat).values('id')
  333. if effective_time_qs.exists():
  334. effective_time_id = effective_time_qs[0]['id']
  335. else:
  336. effective_time_id = EffectiveTime.objects.create(start_time=start_time, end_time=end_time,
  337. repeat=repeat).id
  338. smart_scene_dict['effective_time_id'] = effective_time_id
  339. smart_scene_qs = SmartScene.objects.create(**smart_scene_dict)
  340. # 设备的time数据,分钟转为秒
  341. time_dict = {
  342. 'is_all_day': is_all_day,
  343. 'start_time': start_time * 60,
  344. 'end_time': end_time * 60,
  345. 'repeat': repeat
  346. }
  347. else:
  348. return response.json(444, {'error param': 'invalid isAllDay'})
  349. msg['time'] = time_dict
  350. scene_id = smart_scene_qs.id
  351. msg['scene_id'] = scene_id
  352. # 获取设备任务数据
  353. msg['task'], scene_data = cls.get_task_list_and_scene_data(
  354. conditions_dict, is_set_time, minutes, repeat, tz, now_time, tasks_list, scene_id)
  355. smart_scene_qs.device_data = json.dumps(msg)
  356. smart_scene_qs.scene_data = scene_data
  357. smart_scene_qs.save()
  358. # 设备任务列表不为空,发布MQTT消息通知网关设备
  359. if msg['task']:
  360. thing_name = serial_number
  361. topic_name = SMART_SCENE_TOPIC.format(serial_number)
  362. success = CommonService.req_publish_mqtt_msg(thing_name, topic_name, msg)
  363. try:
  364. assert success
  365. except AssertionError:
  366. return response.json(10044)
  367. return response.json(0)
  368. except Exception as e:
  369. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  370. @staticmethod
  371. def scene_list(request_dict, user_id, response):
  372. """
  373. 查询智能场景列表
  374. @param request_dict: 请求参数
  375. @param user_id: 用户id
  376. @request_dict deviceId: 网关设备id
  377. @request_dict subDeviceId: 子设备id
  378. @param response: 响应对象
  379. @return: response
  380. """
  381. device_id = request_dict.get('deviceId', None)
  382. sub_device_id = request_dict.get('subDeviceId', None)
  383. if not any([device_id, sub_device_id]):
  384. return response.json(444, {'error param': 'deviceId or subDeviceId'})
  385. try:
  386. if device_id:
  387. sub_device_id = GatewaySubDevice.objects.filter(device_id=device_id).values('id')
  388. smart_scene_qs = SmartScene.objects.filter(
  389. Q(user_id=user_id) & Q(device_id=device_id) | Q(sub_device_id__in=sub_device_id))
  390. else:
  391. smart_scene_qs = SmartScene.objects.filter(user_id=user_id, sub_device_id=sub_device_id)
  392. if not smart_scene_qs.exists():
  393. return response.json(173)
  394. smart_scene_qs = smart_scene_qs.values('id', 'scene_name', 'is_enable', 'device_id', 'sub_device_id')
  395. smart_scene_list = []
  396. for item in smart_scene_qs:
  397. smart_scene_dict = {
  398. 'id': item['id'],
  399. 'scene_name': item['scene_name'],
  400. 'is_enable': item['is_enable']
  401. }
  402. if item['device_id']:
  403. device_qs = Device_Info.objects.filter(id=item['device_id'], userID=user_id).values('NickName',
  404. 'Type')
  405. smart_scene_dict['device_type'] = device_qs[0]['Type'] if device_qs.exists() else ''
  406. smart_scene_dict['device_nickname'] = device_qs[0]['NickName'] if device_qs.exists() else ''
  407. else:
  408. device_qs = GatewaySubDevice.objects.filter(id=item['sub_device_id']).values('device_type',
  409. 'nickname')
  410. smart_scene_dict['device_type'] = device_qs[0]['device_type'] if device_qs.exists() else ''
  411. smart_scene_dict['device_nickname'] = device_qs[0]['nickname'] if device_qs.exists() else ''
  412. smart_scene_list.append(smart_scene_dict)
  413. return response.json(0, smart_scene_list)
  414. except Exception as e:
  415. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  416. @staticmethod
  417. def smart_button_scene_list(request_dict, user_id, response):
  418. """
  419. 查询智能按钮场景列表
  420. @param request_dict: 请求参数
  421. @param user_id: 用户id
  422. @request_dict subDeviceId: 子设备id
  423. @param response: 响应对象
  424. @return: response
  425. """
  426. sub_device_id = request_dict.get('subDeviceId', None)
  427. if not sub_device_id:
  428. return response.json(444, {'error param': 'subDeviceId'})
  429. try:
  430. click_scene_qs = SmartScene.objects.filter(user_id=user_id, sub_device_id=sub_device_id,
  431. conditions__contains=str(
  432. EVENT_TYPE['smart_button_click'])).values('id', 'scene_name',
  433. 'is_enable')
  434. double_click_scene_qs = SmartScene.objects.filter(user_id=user_id, sub_device_id=sub_device_id,
  435. conditions__contains=str(
  436. EVENT_TYPE['smart_button_double_click'])). \
  437. values('id', 'scene_name', 'is_enable')
  438. three_click_scene_qs = SmartScene.objects.filter(user_id=user_id, sub_device_id=sub_device_id,
  439. conditions__contains=str(
  440. EVENT_TYPE['smart_button_three_click'])). \
  441. values('id', 'scene_name', 'is_enable')
  442. scene_list = []
  443. if click_scene_qs.exists():
  444. scene_list.append({
  445. 'trigger_type': 1,
  446. 'id': click_scene_qs[0]['id'],
  447. 'scene_name': click_scene_qs[0]['scene_name'],
  448. 'is_enable': click_scene_qs[0]['is_enable']
  449. })
  450. if double_click_scene_qs.exists():
  451. scene_list.append({
  452. 'trigger_type': 2,
  453. 'id': double_click_scene_qs[0]['id'],
  454. 'scene_name': double_click_scene_qs[0]['scene_name'],
  455. 'is_enable': double_click_scene_qs[0]['is_enable']
  456. })
  457. if three_click_scene_qs.exists():
  458. scene_list.append({
  459. 'trigger_type': 3,
  460. 'id': three_click_scene_qs[0]['id'],
  461. 'scene_name': three_click_scene_qs[0]['scene_name'],
  462. 'is_enable': three_click_scene_qs[0]['is_enable']
  463. })
  464. return response.json(0, scene_list)
  465. except Exception as e:
  466. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  467. @classmethod
  468. def update_status(cls, request_dict, response):
  469. """
  470. 更新智能场景状态
  471. @param request_dict: 请求参数
  472. @request_dict smartSceneId: 智能场景id
  473. @request_dict isEnable: 状态,True or False
  474. @param response: 响应对象
  475. @return: response
  476. """
  477. smart_scene_id = request_dict.get('smartSceneId', None)
  478. is_enable = request_dict.get('isEnable', None)
  479. if not all([smart_scene_id, is_enable]):
  480. return response.json(444, {'error param': 'smartSceneId and status'})
  481. try:
  482. smart_scene_id = int(smart_scene_id)
  483. scene_status = SCENE_STATUS_ON if is_enable == 'True' else SCENE_STATUS_OFF
  484. # 查询序列号
  485. smart_scene_qs = SmartScene.objects.filter(id=smart_scene_id).\
  486. values('device_id', 'sub_device_id', 'scene_data')
  487. device_id = smart_scene_qs[0]['device_id']
  488. if device_id:
  489. serial_number = Device_Info.objects.filter(id=device_id).values('serial_number')[0]['serial_number']
  490. else:
  491. sub_device_id = smart_scene_qs[0]['sub_device_id']
  492. serial_number = GatewaySubDevice.objects.filter(id=sub_device_id).values('device__serial_number')[0][
  493. 'device__serial_number']
  494. smart_scene_data = {
  495. 'is_enable': is_enable
  496. }
  497. no_device_task = False
  498. # 如果存在定时任务,暂停或恢复任务
  499. scene_data = smart_scene_qs[0]['scene_data']
  500. if scene_data:
  501. scene_data_dict = eval(scene_data)
  502. no_device_task = scene_data_dict.get('no_device_task')
  503. if no_device_task is not None:
  504. # 无设备任务,需要scene_id上报场景日志
  505. scene_id = smart_scene_id if no_device_task else 0
  506. new_scene_data_dict = cls.pause_or_resume_job(scene_data_dict, scene_status, scene_id)
  507. if new_scene_data_dict:
  508. smart_scene_data['scene_data'] = new_scene_data_dict
  509. with transaction.atomic():
  510. SmartScene.objects.filter(id=smart_scene_id).update(**smart_scene_data)
  511. # 存在设备任务,通过mqtt发送设备数据
  512. if not no_device_task:
  513. topic_name = SMART_SCENE_TOPIC.format(serial_number)
  514. msg = {
  515. 'scene_event': SCENE_EVENT_EDIT_STATUS,
  516. 'scene_id': smart_scene_id,
  517. 'scene_status': scene_status
  518. }
  519. success = CommonService.req_publish_mqtt_msg(serial_number, topic_name, msg)
  520. try:
  521. assert success
  522. except AssertionError:
  523. return response.json(10044)
  524. return response.json(0)
  525. except Exception as e:
  526. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  527. @staticmethod
  528. def scene_detail(request_dict, response):
  529. """
  530. 查询智能场景详情
  531. @param request_dict: 请求参数
  532. @request_dict smartSceneId: 智能场景id
  533. @param response: 响应对象
  534. @return: response
  535. """
  536. smart_scene_id = request_dict.get('smartSceneId', None)
  537. if not smart_scene_id:
  538. return response.json(444, {'error param': 'smartSceneId'})
  539. try:
  540. smart_scene_qs = SmartScene.objects.filter(id=smart_scene_id).values('id', 'scene_name', 'conditions',
  541. 'tasks', 'effective_time_id',
  542. 'is_all_day')
  543. if not smart_scene_qs.exists():
  544. return response.json(173)
  545. res = {
  546. 'scene_name': smart_scene_qs[0]['scene_name'],
  547. 'condition': eval(smart_scene_qs[0]['conditions']),
  548. 'task': eval(smart_scene_qs[0]['tasks']),
  549. }
  550. # 如果存在关联的时间数据,组织时间数据
  551. is_all_day = smart_scene_qs[0]['is_all_day']
  552. effectiveTime = {}
  553. if is_all_day != 0:
  554. effectiveTime['isAllDay'] = is_all_day
  555. if is_all_day == 2:
  556. try:
  557. effective_time_qs = EffectiveTime.objects.get(id=smart_scene_qs[0]['effective_time_id'])
  558. effectiveTime['startTime'] = effective_time_qs.start_time
  559. effectiveTime['endTime'] = effective_time_qs.end_time
  560. effectiveTime['repeat'] = effective_time_qs.repeat
  561. except ObjectDoesNotExist:
  562. return response.json(0, res)
  563. res['effectiveTime'] = effectiveTime
  564. return response.json(0, res)
  565. except Exception as e:
  566. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  567. @classmethod
  568. def edit_smart_scene(cls, request_dict, user_id, response):
  569. """
  570. 编辑智能场景
  571. @param request_dict: 请求参数
  572. @param user_id: 用户id
  573. @request_dict smartSceneId: 智能场景id
  574. @param response: 响应对象
  575. @return: response
  576. """
  577. smart_scene_id = int(request_dict.get('smartSceneId', None))
  578. device_id = request_dict.get('deviceId', None)
  579. sub_device_id = request_dict.get('subDeviceId', None)
  580. scene_name = request_dict.get('sceneName', None)
  581. conditions = request_dict.get('conditions', None)
  582. tasks = request_dict.get('tasks', None)
  583. is_all_day = request_dict.get('isAllDay', None)
  584. conditions_dict = eval(conditions)
  585. tasks_list = eval(tasks)
  586. now_time = int(time.time())
  587. smart_scene_qs = SmartScene.objects.filter(user_id=user_id, scene_name=scene_name).filter(~Q(id=smart_scene_id))
  588. if smart_scene_qs.exists():
  589. return response.json(179)
  590. res = {
  591. 'scene_name': scene_name,
  592. 'conditions': conditions_dict,
  593. 'tasks': tasks_list
  594. }
  595. effective_time = {}
  596. if is_all_day:
  597. is_all_day = int(is_all_day)
  598. effective_time['is_all_day'] = is_all_day
  599. if not all([smart_scene_id, scene_name, conditions, tasks]):
  600. return response.json(444, {'error param': 'smartSceneId,sceneName,conditions or tasks'})
  601. try:
  602. smart_scene_qs = SmartScene.objects.filter(id=smart_scene_id)
  603. if not smart_scene_qs.exists():
  604. return response.json(173)
  605. tz = smart_scene_qs[0].tz
  606. scene_data = smart_scene_qs[0].scene_data
  607. scene_data_dict = eval(scene_data) if scene_data else None
  608. scene_status = 1 if smart_scene_qs[0].is_enable else 0
  609. msg = {
  610. 'scene_id': smart_scene_id,
  611. 'scene_event': SCENE_EVENT_EDIT,
  612. 'scene_status': scene_status
  613. }
  614. # 判断条件是否为设置时间
  615. is_set_time, minutes, repeat = False, 0, 0
  616. if conditions_dict['type'] == 1:
  617. is_set_time = True
  618. minutes = conditions_dict['time']['minutes']
  619. repeat = conditions_dict['time']['repeat']
  620. # 条件为设置时间
  621. if is_set_time:
  622. if not device_id:
  623. return response.json(444, {'error param': 'deviceId'})
  624. sub_device_id = 0
  625. device_qs = Device_Info.objects.filter(id=device_id).values('serial_number')
  626. if not device_qs.exists():
  627. return response.json(173)
  628. serial_number = device_qs[0]['serial_number']
  629. # 网关数据
  630. msg['sensor_type'] = DEVICE_TYPE['gateway']
  631. msg['sensor_status'] = 2002
  632. msg['sensor_ieee_addr'] = 'FFFFFFFFFFFFFFFF'
  633. # 条件为选择子设备
  634. else:
  635. if not sub_device_id:
  636. return response.json(444, {'error param': 'subDeviceId'})
  637. if cls.time_conflict(sub_device_id, conditions, is_all_day, request_dict, smart_scene_id):
  638. return response.json(182)
  639. device_type = int(conditions_dict['sensor']['device_type'])
  640. # 智能按钮不能创建触发条件相同的场景
  641. if device_type == SENSOR_TYPE['smart_button']:
  642. event_type = conditions_dict['sensor']['eventValues'][0]['event_type']
  643. smart_scene_temp_qs = SmartScene.objects.filter(Q(sub_device_id=sub_device_id),
  644. ~Q(id=smart_scene_id),
  645. conditions__contains=event_type)
  646. if smart_scene_temp_qs.exists():
  647. return response.json(180)
  648. # 温湿度传感器返回温湿度
  649. elif device_type == SENSOR_TYPE['tem_hum_sensor']:
  650. event_values = conditions_dict['sensor']['eventValues'][0]
  651. if '≥' in event_values['value']:
  652. replace_str = '≥ '
  653. msg['sensor_symbol'] = 2
  654. else:
  655. replace_str = '≤ '
  656. msg['sensor_symbol'] = 1
  657. value = event_values['value'].replace(replace_str, '')
  658. msg['sensor_data'] = float(value)
  659. device_id = ''
  660. sub_device_qs = GatewaySubDevice.objects.filter(id=sub_device_id).values('ieee_addr',
  661. 'device__serial_number')
  662. if not sub_device_qs.exists():
  663. return response.json(173)
  664. serial_number = sub_device_qs[0]['device__serial_number']
  665. msg['sensor_type'] = int(conditions_dict['sensor']['device_type'])
  666. msg['sensor_ieee_addr'] = sub_device_qs[0]['ieee_addr']
  667. msg['sensor_status'] = int(conditions_dict['sensor']['eventValues'][0]['event_type'])
  668. # 获取设备任务数据
  669. msg['task'], scene_data = cls.get_task_list_and_scene_data(
  670. conditions_dict, is_set_time, minutes, repeat, tz, now_time, tasks_list, smart_scene_id, scene_data_dict
  671. )
  672. with transaction.atomic():
  673. smart_scene_qs.update(scene_name=scene_name, conditions=conditions, tasks=tasks, scene_data=scene_data,
  674. device_data=json.dumps(msg), updated_time=now_time, device_id=device_id,
  675. sub_device_id=sub_device_id)
  676. if is_all_day is None: # 不设置时间或全天
  677. smart_scene_qs.update(effective_time_id=0, is_all_day=0)
  678. time_dict = {
  679. 'start_time': conditions_dict['time']['minutes'] * 60,
  680. 'repeat': conditions_dict['time']['repeat']
  681. }
  682. elif is_all_day == 1:
  683. smart_scene_qs.update(effective_time_id=0, is_all_day=is_all_day)
  684. time_dict = {
  685. 'is_all_day': is_all_day
  686. }
  687. else:
  688. start_time = int(request_dict.get('startTime', None))
  689. end_time = int(request_dict.get('endTime', None))
  690. repeat = int(request_dict.get('repeat', None))
  691. effective_time_qs = EffectiveTime.objects.filter(start_time=start_time, end_time=end_time,
  692. repeat=repeat).values('id')
  693. if effective_time_qs.exists():
  694. effective_time_id = effective_time_qs[0]['id']
  695. else:
  696. effective_time_id = EffectiveTime.objects.create(start_time=start_time, end_time=end_time,
  697. repeat=repeat).id
  698. smart_scene_qs.update(effective_time_id=effective_time_id, is_all_day=is_all_day)
  699. time_dict = {
  700. 'is_all_day': is_all_day,
  701. 'start_time': start_time * 60,
  702. 'end_time': end_time * 60,
  703. 'repeat': repeat
  704. }
  705. effective_time = {
  706. 'isAllDay': is_all_day,
  707. 'startTime': start_time,
  708. 'endTime': end_time,
  709. 'repeat': repeat
  710. }
  711. msg['time'] = time_dict
  712. # 设备任务列表不为空,发布MQTT消息通知网关设备
  713. if msg['task']:
  714. thing_name = serial_number
  715. topic_name = SMART_SCENE_TOPIC.format(serial_number)
  716. success = CommonService.req_publish_mqtt_msg(thing_name, topic_name, msg)
  717. try:
  718. assert success
  719. except AssertionError:
  720. return response.json(10044)
  721. res['effectiveTime'] = effective_time
  722. return response.json(0, res)
  723. except Exception as e:
  724. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  725. @classmethod
  726. def delete_smart_scene(cls, request_dict, response):
  727. """
  728. 删除智能场景
  729. @param request_dict: 请求参数
  730. @request_dict smartSceneIds: 智能场景id
  731. @param response: 响应对象
  732. @return: response
  733. """
  734. smart_scene_ids = request_dict.get('smartSceneIds', None)
  735. if not smart_scene_ids:
  736. return response.json(444, {'error param': 'smartSceneIds'})
  737. try:
  738. smart_scene_id_list = smart_scene_ids.split(',')
  739. # 获取序列号
  740. smart_scene_id = smart_scene_id_list[0]
  741. smart_scene_qs = SmartScene.objects.filter(id=smart_scene_id).values('device_id', 'sub_device_id')
  742. device_id = smart_scene_qs[0]['device_id']
  743. if device_id:
  744. serial_number = Device_Info.objects.filter(id=device_id).values('serial_number')[0]['serial_number']
  745. else:
  746. serial_number = GatewaySubDevice.objects.filter(id=smart_scene_qs[0]['sub_device_id']). \
  747. values('device__serial_number')[0]['device__serial_number']
  748. topic_name = SMART_SCENE_TOPIC.format(serial_number)
  749. with transaction.atomic():
  750. smart_scene_qs = SmartScene.objects.filter(id__in=smart_scene_id_list)
  751. # 删除定时任务
  752. smart_scene_data = smart_scene_qs.values('scene_data')
  753. for smart_scene in smart_scene_data:
  754. scene_data = smart_scene['scene_data']
  755. if scene_data:
  756. scene_data_dict = eval(scene_data)
  757. cls.del_aps_job(scene_data_dict)
  758. smart_scene_qs.delete()
  759. for smart_scene_id in smart_scene_id_list:
  760. # 通知设备删除场景id
  761. msg = {
  762. 'scene_event': SCENE_EVENT_DELETE,
  763. 'scene_id': int(smart_scene_id)
  764. }
  765. success = CommonService.req_publish_mqtt_msg(serial_number, topic_name, msg)
  766. try:
  767. assert success
  768. except AssertionError:
  769. return response.json(10044)
  770. time.sleep(0.3)
  771. return response.json(0)
  772. except Exception as e:
  773. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  774. @staticmethod
  775. def scene_log(request_dict, response):
  776. """
  777. 查询场景日志
  778. @param request_dict: 请求参数
  779. @request_dict deviceId: 网关id
  780. @request_dict subDeviceId: 子设备id
  781. @request_dict page: 页数
  782. @request_dict size: 条数
  783. @request_dict startTime: 开始时间
  784. @request_dict endTime: 结束时间
  785. @param response: 响应对象
  786. @return: response
  787. """
  788. family_id = request_dict.get('familyId', None)
  789. device_id = request_dict.get('deviceId', None)
  790. sub_device_id = request_dict.get('subDeviceId', None)
  791. page = request_dict.get('page', None)
  792. size = request_dict.get('size', None)
  793. start_time = request_dict.get('startTime', None)
  794. end_time = request_dict.get('endTime', None)
  795. if not all([family_id, page, size]):
  796. return response.json(444, {'error param': 'familyId or page or size'})
  797. device_list = []
  798. sub_device_list = []
  799. if not device_id and not sub_device_id:
  800. family_room_device_qs = FamilyRoomDevice.objects.filter(family_id=family_id).values('device', 'sub_device')
  801. for device in family_room_device_qs:
  802. if device['device'] not in device_list:
  803. device_list.append(device['device'])
  804. if device['sub_device']:
  805. sub_device_list.append(device['sub_device'])
  806. elif sub_device_id: # 查询子设备
  807. family_room_device_qs = FamilyRoomDevice.objects.filter(family_id=family_id,
  808. sub_device=sub_device_id).values('device_id')
  809. for device in family_room_device_qs:
  810. device_list.append(device['device_id'])
  811. sub_device_list.append(sub_device_id)
  812. else: # 查询网关
  813. family_room_device_qs = FamilyRoomDevice.objects.filter(Q(family_id=family_id) & Q(device=device_id) &
  814. ~Q(sub_device=0)).values(
  815. 'sub_device')
  816. device_list.append(device_id)
  817. for device in family_room_device_qs:
  818. sub_device_list.append(device['sub_device'])
  819. try:
  820. page, size = int(page), int(size)
  821. scene_log_qs = SceneLog.objects.filter(Q(device_id__in=device_list) | Q(sub_device_id__in=sub_device_list))
  822. if start_time and end_time:
  823. scene_log_qs = scene_log_qs.filter(created_time__range=(start_time, end_time)).values(
  824. 'status',
  825. 'created_time',
  826. 'device_id',
  827. 'sub_device_id',
  828. 'scene_name',
  829. 'tasks').order_by(
  830. '-created_time')[(page - 1) * size:page * size]
  831. else:
  832. scene_log_qs = scene_log_qs.values('status', 'created_time', 'device_id', 'sub_device_id', 'scene_name',
  833. 'tasks').order_by(
  834. '-created_time')[(page - 1) * size:page * size]
  835. if not scene_log_qs.exists():
  836. return response.json(0, [])
  837. for item in scene_log_qs:
  838. if not device_id and not sub_device_id:
  839. if not item['sub_device_id']:
  840. device_qs = Device_Info.objects.filter(id=item['device_id']).values('Type')
  841. item['device_type'] = device_qs[0]['Type'] if device_qs.exists() else ''
  842. else:
  843. device_qs = GatewaySubDevice.objects.filter(id=item['sub_device_id']).values('device_type')
  844. item['device_type'] = device_qs[0]['device_type'] if device_qs.exists() else ''
  845. elif sub_device_id:
  846. device_qs = GatewaySubDevice.objects.filter(id=item['sub_device_id']).values('device_type')
  847. item['device_type'] = device_qs[0]['device_type'] if device_qs.exists() else ''
  848. else:
  849. device_qs = Device_Info.objects.filter(id=item['device_id']).values('Type')
  850. item['device_type'] = device_qs[0]['Type'] if device_qs.exists() else ''
  851. if item['tasks'] != '':
  852. item['tasks'] = eval(item['tasks'])
  853. scene_log_list = list(scene_log_qs)
  854. return response.json(0, scene_log_list)
  855. except Exception as e:
  856. print('error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  857. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  858. @staticmethod
  859. def scene_log_date(request_dict, response):
  860. """
  861. 查询场景日志日期
  862. @param request_dict: 请求参数
  863. @request_dict deviceId: 网关id
  864. @request_dict subDeviceId: 子设备id
  865. @param response: 响应对象
  866. @return: response
  867. """
  868. family_id = request_dict.get('familyId', None)
  869. device_id = request_dict.get('deviceId', None)
  870. sub_device_id = request_dict.get('subDeviceId', None)
  871. if not family_id:
  872. return response.json(444, {'error param': 'familyId'})
  873. device_list = []
  874. sub_device_list = []
  875. if not device_id and not sub_device_id:
  876. family_room_device_qs = FamilyRoomDevice.objects.filter(family_id=family_id).values('device', 'sub_device')
  877. for device in family_room_device_qs:
  878. if device['device'] not in device_list:
  879. device_list.append(device['device'])
  880. if device['sub_device']:
  881. sub_device_list.append(device['sub_device'])
  882. elif sub_device_id:
  883. family_room_device_qs = FamilyRoomDevice.objects.filter(family_id=family_id, sub_device=sub_device_id)
  884. sub_device_list.append(sub_device_id)
  885. else:
  886. family_room_device_qs = FamilyRoomDevice.objects.filter(family_id=family_id, device=device_id).values(
  887. 'sub_device')
  888. device_list.append(device_id)
  889. for device in family_room_device_qs:
  890. sub_device_list.append(device['sub_device'])
  891. if not family_room_device_qs.exists():
  892. return response.json(173)
  893. try:
  894. scene_log_qs = SceneLog.objects.extra(
  895. select={'date': "FROM_UNIXTIME(created_time,'%%Y-%%m-%%d')"}).values('date'). \
  896. filter(Q(device_id__in=device_list) | Q(sub_device_id__in=sub_device_list)). \
  897. annotate(count=Count('created_time')). \
  898. order_by('-date')[:31]
  899. log_date_list = []
  900. for scene_log in scene_log_qs:
  901. log_date_list.append({
  902. 'timestamp': CommonService.str_to_timestamp(scene_log['date'], '%Y-%m-%d'),
  903. 'count': scene_log['count'],
  904. 'format': scene_log['date'],
  905. })
  906. return response.json(0, log_date_list)
  907. except Exception as e:
  908. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  909. @staticmethod
  910. def get_scene_data(request_dict, response):
  911. """
  912. 设备获取智能场景数据
  913. @param request_dict: 请求参数
  914. @request_dict serial_number: 序列号
  915. @param response: 响应对象
  916. @return: response
  917. """
  918. serial_number = request_dict.get('serial_number', None)
  919. if not serial_number:
  920. return response.json(444, {'error param': 'serial_number'})
  921. try:
  922. device_info_qs = Device_Info.objects.filter(serial_number=serial_number).values('id')
  923. if not device_info_qs.exists():
  924. return response.json(173)
  925. device_id = device_info_qs[0]['id']
  926. sub_device_id_list = GatewaySubDevice.objects.filter(device_id=device_id).values_list('id', flat=True)
  927. if sub_device_id_list:
  928. smart_scene_qs = SmartScene.objects.filter(
  929. Q(device_id=device_id) | Q(sub_device_id__in=sub_device_id_list))
  930. else:
  931. smart_scene_qs = SmartScene.objects.filter(device_id=device_id)
  932. if not smart_scene_qs.exists():
  933. return response.json(173)
  934. # 下发智能场景数据
  935. smart_scene_qs = smart_scene_qs.values('device_data')
  936. topic_name = SMART_SCENE_TOPIC.format(serial_number)
  937. for smart_scene in smart_scene_qs:
  938. msg = eval(smart_scene['device_data'])
  939. success = CommonService.req_publish_mqtt_msg(serial_number, topic_name, msg)
  940. try:
  941. assert success
  942. except AssertionError:
  943. return response.json(10044)
  944. time.sleep(2)
  945. # 下发智能按钮数据
  946. smart_button_qs = GatewaySubDevice.objects.filter(device_id=device_id,
  947. device_type=SENSOR_TYPE['smart_button']).values(
  948. 'ieee_addr', 'is_tampered')
  949. if smart_button_qs.exists():
  950. sos_count = smart_button_qs.count()
  951. for index, smart_button in enumerate(smart_button_qs):
  952. msg = {
  953. 'sos_count': sos_count, # 该网关下的智能按钮数量
  954. 'sos_num': index + 1, # 第几个按钮
  955. 'sensor_ieee_addr': smart_button['ieee_addr'],
  956. 'sos_select': smart_button['is_tampered']
  957. }
  958. success = CommonService.req_publish_mqtt_msg(serial_number, topic_name, msg)
  959. try:
  960. assert success
  961. except AssertionError:
  962. return response.json(10044)
  963. time.sleep(2)
  964. return response.json(0)
  965. except Exception as e:
  966. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  967. @staticmethod
  968. def voice_audition(request_dict, response):
  969. """
  970. 智能场景音频试听
  971. @param request_dict: 请求参数
  972. @request_dict serial_number: 序列号
  973. @request_dict voiceId: 音频id
  974. @param response: 响应对象
  975. @return: response
  976. """
  977. serial_number = request_dict.get('serial_number', None)
  978. voice_id = request_dict.get('voiceId', None)
  979. if not all([serial_number, voice_id]):
  980. return response.json(444)
  981. try:
  982. topic_name = VOICE_AUDITION_TOPIC.format(serial_number)
  983. msg = {'voice_id': int(voice_id)}
  984. success = CommonService.req_publish_mqtt_msg(serial_number, topic_name, msg)
  985. try:
  986. assert success
  987. except AssertionError:
  988. return response.json(10044)
  989. return response.json(0)
  990. except Exception as e:
  991. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  992. @classmethod
  993. def get_task_list_and_scene_data(
  994. cls, conditions_dict, is_set_time, minutes, repeat, tz, now_time, tasks_list, scene_id,
  995. scene_data_dict=None):
  996. """
  997. 获取设备任务数据和场景数据
  998. @param tasks_list: app任务列表
  999. @param conditions_dict: 条件
  1000. @param is_set_time: 条件是否为设置时间
  1001. @param minutes: 时间分钟数
  1002. @param repeat: 重复星期周期的十进制
  1003. @param tz: 时区
  1004. @param now_time: 当前时间
  1005. @param scene_id: 场景id
  1006. @param scene_data_dict: 场景数据
  1007. @return: task_list, scene_data
  1008. """
  1009. # 删除旧的定时任务
  1010. cls.del_aps_job(scene_data_dict)
  1011. task_list = []
  1012. scene_task_list = []
  1013. total_delay_time = 0
  1014. no_device_task = True
  1015. is_last_task = False
  1016. tasks_len = len(tasks_list)
  1017. # 组织条件数据
  1018. condition = cls.get_condition(conditions_dict, is_set_time, minutes, repeat, now_time, tz)
  1019. for index, task in enumerate(tasks_list):
  1020. # 判断是否为列表的最后一个元素
  1021. if index == tasks_len - 1:
  1022. is_last_task = True
  1023. sensor_type = int(task['device_type'])
  1024. total_delay_time += task['delay_time']
  1025. # 处理插座数据
  1026. # 不用添加到设备的任务列表,添加到mqtt任务列表
  1027. if sensor_type == DEVICE_TYPE['socket']:
  1028. serial_number = task['serial_number']
  1029. event_type = int(task['event_type'])
  1030. delay_time = task['delay_time']
  1031. task_temp = {
  1032. 'device_type': sensor_type,
  1033. 'event_type': event_type,
  1034. 'delay_time': delay_time,
  1035. 'serial_number': serial_number
  1036. }
  1037. # 如果条件为设置时间,创建定时任务
  1038. if is_set_time:
  1039. smart_scene_id = 0
  1040. # 无设备任务,且是最后一个任务,需要通过scene_id上报场景日志
  1041. if no_device_task and is_last_task:
  1042. smart_scene_id = scene_id
  1043. task_temp['task_id'] = cls.create_aps_job(
  1044. condition, minutes, total_delay_time, tz, repeat, sensor_type, event_type, serial_number,
  1045. smart_scene_id)
  1046. scene_task_list.append(task_temp)
  1047. else:
  1048. no_device_task = False
  1049. task_temp = {
  1050. 'sensor_type': sensor_type,
  1051. 'sensor_delay': 0
  1052. }
  1053. # 延时
  1054. if 'delay_time' in task and task['delay_time'] != 0:
  1055. task_temp['sensor_delay'] = task['delay_time']
  1056. # 不为-1时需要其他数据
  1057. if sensor_type != -1:
  1058. task_temp['sensor_action'] = int(task['event_type'])
  1059. # 子设备返回长地址
  1060. sub_device_id = task.get('subDeviceId', None)
  1061. if sub_device_id:
  1062. sub_device_qs = GatewaySubDevice.objects.filter(id=sub_device_id).values('ieee_addr').first()
  1063. task_temp['sensor_ieee_addr'] = sub_device_qs['ieee_addr']
  1064. # 网关添加报警类型数据
  1065. else:
  1066. task_temp['voice_type'] = task.get('voice_type')
  1067. task_temp['voice_id'] = task.get('voice_id')
  1068. task_temp['count'] = task.get('count')
  1069. task_temp['delay_time'] = task.get('delay_time')
  1070. task_temp['duration'] = task.get('duration')
  1071. task_temp['value_type'] = task.get('value_type')
  1072. task_list.append(task_temp)
  1073. # scene_task_list不为空,组织完整场景数据
  1074. scene_data = ''
  1075. if scene_task_list:
  1076. scene_data = {
  1077. 'condition': condition,
  1078. 'task_list': scene_task_list,
  1079. 'no_device_task': no_device_task
  1080. }
  1081. return task_list, scene_data
  1082. @classmethod
  1083. def get_condition(cls, conditions_dict, is_set_time, minutes, repeat, now_time, tz):
  1084. """
  1085. 获取场景条件
  1086. @param conditions_dict: 条件数据
  1087. @param is_set_time: 条件是否为设置时间
  1088. @param minutes: 时间分钟数
  1089. @param repeat: 重复星期周期的十进制
  1090. @param now_time: 当前时间
  1091. @param tz: 时区
  1092. @return: condition
  1093. """
  1094. condition = {}
  1095. # 条件为设置时间
  1096. if is_set_time:
  1097. hour, minute = divmod(minutes, 60)
  1098. # 一次性任务
  1099. if repeat == 0:
  1100. condition['time'] = 'date'
  1101. # 根据时间戳和时区获取年月日,拼接由分钟转换出来的时间
  1102. time_string = CommonService.get_date_from_timestamp(now_time, tz)
  1103. time_string += ' {:02d}:{:02d}:00'.format(hour, minute)
  1104. time_stamp = CommonService.convert_to_timestamp(tz, time_string)
  1105. if time_stamp < now_time:
  1106. time_stamp += 24 * 60 * 60
  1107. time_dict = {
  1108. 'time_stamp': time_stamp
  1109. }
  1110. condition['time_dict'] = time_dict
  1111. else:
  1112. condition['time'] = 'cron'
  1113. weeks = cls.int_to_weeks(repeat)
  1114. time_dict = {
  1115. 'weeks': weeks,
  1116. 'hour': hour,
  1117. 'minute': minute
  1118. }
  1119. condition['time_dict'] = time_dict
  1120. else:
  1121. device_type = int(conditions_dict['sensor']['device_type'])
  1122. event_type = conditions_dict['sensor']['eventValues'][0]['event_type']
  1123. condition['event_type'] = event_type
  1124. # 温湿度传感器,取值
  1125. if device_type == SENSOR_TYPE['tem_hum_sensor']:
  1126. condition['value'] = event_type = conditions_dict['sensor']['eventValues'][0]['value']
  1127. return condition
  1128. @staticmethod
  1129. def time_conflict(sub_device_id, conditions, is_all_day, request_dict, smart_scene_id=None):
  1130. """
  1131. 判断传感器是否创建过条件相同且生效时间冲突的场景
  1132. @param sub_device_id: 传感器设备id
  1133. @param conditions: 场景条件
  1134. @param is_all_day: 全天标识
  1135. @param request_dict:
  1136. @param smart_scene_id: 场景id,编辑场景时传
  1137. @return: bool, True: 冲突, False: 不冲突
  1138. """
  1139. # 不设置时间不会冲突
  1140. if is_all_day is None:
  1141. return False
  1142. # 查询设置过时间的数据
  1143. if smart_scene_id is None: # 创建场景
  1144. smart_scene_qs = SmartScene.objects.filter(
  1145. ~Q(is_all_day=0),
  1146. sub_device_id=sub_device_id,
  1147. conditions=conditions).values('effective_time_id')
  1148. else: # 编辑场景,过滤本身场景数据
  1149. smart_scene_qs = SmartScene.objects.filter(
  1150. ~Q(id=smart_scene_id),
  1151. ~Q(is_all_day=0),
  1152. sub_device_id=sub_device_id,
  1153. conditions=conditions).values('effective_time_id')
  1154. if not smart_scene_qs.exists():
  1155. return False
  1156. # 再设置全天必冲突
  1157. if is_all_day == 1:
  1158. return True
  1159. # 非全天
  1160. elif is_all_day == 2:
  1161. start_time = int(request_dict.get('startTime'))
  1162. end_time = int(request_dict.get('endTime'))
  1163. repeat = int(request_dict.get('repeat'))
  1164. for smart_scene in smart_scene_qs:
  1165. effective_time_id = smart_scene['effective_time_id']
  1166. effective_time_qs = EffectiveTime.objects.filter(id=effective_time_id).\
  1167. values('start_time', 'end_time', 'repeat')
  1168. if effective_time_qs.exists():
  1169. old_start_time = effective_time_qs[0]['start_time']
  1170. old_end_time = effective_time_qs[0]['end_time']
  1171. old_repeat = effective_time_qs[0]['repeat']
  1172. # 每天重复
  1173. if repeat == 127:
  1174. # 判断时间是否在已设置过的时间范围之内
  1175. if old_start_time <= start_time <= old_end_time or \
  1176. old_start_time <= end_time <= old_end_time:
  1177. return True
  1178. else:
  1179. # 有相同的重复天
  1180. if repeat & old_repeat != 0:
  1181. # 判断时间是否在已设置过的时间范围之内
  1182. if old_start_time <= start_time <= old_end_time or \
  1183. old_start_time <= end_time <= old_end_time:
  1184. return True
  1185. return False
  1186. @classmethod
  1187. def create_aps_job(
  1188. cls, condition, minutes, total_delay_time, tz, repeat, device_type, event_type, serial_number, scene_id):
  1189. """
  1190. 创建定时任务
  1191. 返回任务id和时间
  1192. @param condition: 条件数据
  1193. @param minutes: 分钟时间
  1194. @param total_delay_time: 总延迟时间
  1195. @param tz: 时区
  1196. @param repeat: 星期周期的十进制数
  1197. @param device_type: 设备类型
  1198. @param event_type: 事件类型
  1199. @param serial_number: 序列号
  1200. @param scene_id: 场景id
  1201. @return: task_id
  1202. """
  1203. task_id = serial_number + '_'
  1204. apscheduler_obj = ApschedulerObject(tz)
  1205. # 一次性任务
  1206. if repeat == 0:
  1207. time_stamp = condition['time_dict']['time_stamp'] + total_delay_time
  1208. task_id += str(time_stamp)
  1209. apscheduler_obj.create_date_job(func=cls.pub_mqtt, task_id=task_id, time_stamp=time_stamp,
  1210. args=(device_type, event_type, serial_number, scene_id))
  1211. # 周期任务
  1212. else:
  1213. hour, minute, second, is_next_day = cls.handle_delay_time(minutes, total_delay_time)
  1214. # 加上延时,如果执行时间超过23:59,隔天执行
  1215. weeks = cls.int_to_weeks(repeat, is_next_day)
  1216. time_str = weeks + '_{:02d}{:02d}{:02d}'.format(hour, minute, second)
  1217. task_id += time_str
  1218. apscheduler_obj.create_cron_job(func=cls.pub_mqtt, task_id=task_id, day_of_week=weeks,
  1219. hour=hour, minute=minute,
  1220. args=(device_type, event_type, serial_number, scene_id))
  1221. return task_id
  1222. @staticmethod
  1223. def handle_delay_time(minutes, delay_time):
  1224. """
  1225. 处理延迟时间
  1226. @param minutes: 时间分钟数,如1439代表23:59
  1227. @param delay_time: 延迟时间,单位:秒
  1228. @return: hour, minute, second, is_next_day
  1229. """
  1230. is_next_day = False
  1231. hour, minute = divmod(minutes, 60)
  1232. # 延迟时间转为分钟,如果加上时间分钟数大于1439,隔天执行
  1233. minute, second = divmod(delay_time, 60)
  1234. total_minutes = minutes + minute
  1235. ex_min = total_minutes - 1439
  1236. if ex_min <= 0:
  1237. hour, minute = divmod(total_minutes, 60)
  1238. else:
  1239. hour, minute = divmod(ex_min, 60)
  1240. is_next_day = True
  1241. return hour, minute, second, is_next_day
  1242. @staticmethod
  1243. def int_to_weeks(repeat, is_next_day=False):
  1244. """
  1245. 十进制转星期周期
  1246. @param repeat: 星期周期的十进制数,如127 -> 0,1,2,3,4,5,6
  1247. @param is_next_day: 是否隔天
  1248. @return: weeks
  1249. """
  1250. # 十进制转为7位的二进制并倒序
  1251. bin_str = bin(repeat)[2:].zfill(7)[::-1]
  1252. # 生成星期周期字符串
  1253. weeks = ''
  1254. next_day = 1 if is_next_day else 0
  1255. for i, bit in enumerate(bin_str):
  1256. if bit == '1':
  1257. # 7 -> 0
  1258. week = i + next_day
  1259. if week == 7:
  1260. week = 0
  1261. weeks += str(week) + ','
  1262. # 删除最后一个逗号并返回结果
  1263. return weeks[:-1]
  1264. @staticmethod
  1265. def pub_mqtt(device_type, event_type, serial_number, scene_id=0):
  1266. """
  1267. 发布mqtt消息
  1268. @param device_type: 设备类型
  1269. @param event_type: 事件类型
  1270. @param serial_number: 序列号
  1271. @param scene_id: 场景id
  1272. @return:
  1273. """
  1274. if device_type == DEVICE_TYPE['socket']:
  1275. topic_name = SMART_SOCKET_TOPIC.format(serial_number)
  1276. status = 1 if event_type == EVENT_TYPE['socket_power_on'] else 0
  1277. msg = {
  1278. 'type': 1,
  1279. 'data': {'deviceSwitch': status}
  1280. }
  1281. CommonService.req_publish_mqtt_msg(serial_number, topic_name, msg)
  1282. # 没有设备任务时,最后一个任务上报场景日志
  1283. if scene_id:
  1284. data = {
  1285. 'sceneId': scene_id,
  1286. 'status': 1
  1287. }
  1288. url = DETECT_PUSH_DOMAINS + 'gatewayService/sceneLogPush'
  1289. req = requests.post(url=url, data=data, timeout=8)
  1290. @staticmethod
  1291. def del_aps_job(scene_data_dict):
  1292. """
  1293. 删除定时任务
  1294. @param scene_data_dict: 场景数据
  1295. @return:
  1296. """
  1297. if scene_data_dict is not None:
  1298. if scene_data_dict['condition'].get('time'):
  1299. apscheduler_obj = ApschedulerObject()
  1300. time_task_list = scene_data_dict['task_list']
  1301. for time_task in time_task_list:
  1302. # 存在任务则删除
  1303. task_id = time_task.get('task_id')
  1304. if task_id:
  1305. apscheduler_obj.del_job(task_id)
  1306. @classmethod
  1307. def pause_or_resume_job(cls, scene_data_dict, scene_status, scene_id):
  1308. """
  1309. 暂停或恢复定时任务
  1310. @param scene_data_dict: 场景数据
  1311. @param scene_status: 场景状态: SCENE_STATUS_ON, SCENE_STATUS_OFF
  1312. @param scene_id: 场景id
  1313. @return: None or scene_data_dict
  1314. """
  1315. # 判断条件是否为设置时间
  1316. time_type = scene_data_dict['condition'].get('time')
  1317. if time_type:
  1318. apscheduler_obj = ApschedulerObject()
  1319. # 关闭: 暂停任务, 打开: 恢复任务
  1320. if scene_status == SCENE_STATUS_OFF:
  1321. cls.pause_time_job(apscheduler_obj, scene_data_dict)
  1322. else:
  1323. return cls.resume_time_job(apscheduler_obj, time_type, scene_data_dict, scene_id)
  1324. @staticmethod
  1325. def pause_time_job(apscheduler_obj, scene_data_dict):
  1326. """
  1327. 暂停定时任务
  1328. @param apscheduler_obj: apscheduler对象
  1329. @param scene_data_dict: 场景数据
  1330. @return:
  1331. """
  1332. time_task_list = scene_data_dict['task_list']
  1333. for time_task in time_task_list:
  1334. task_id = time_task.get('task_id')
  1335. if task_id:
  1336. try:
  1337. apscheduler_obj.pause_job(task_id)
  1338. except Exception:
  1339. continue
  1340. @classmethod
  1341. def resume_time_job(cls, apscheduler_obj, time_type, scene_data_dict, scene_id):
  1342. """
  1343. 恢复定时任务
  1344. @param apscheduler_obj: apscheduler对象
  1345. @param time_type: 时间类型: date, cron
  1346. @param scene_data_dict: 场景数据
  1347. @param scene_id: 场景id
  1348. @return: None or time_stamp
  1349. """
  1350. time_task_list = scene_data_dict['task_list']
  1351. if time_type == 'cron':
  1352. for time_task in time_task_list:
  1353. task_id = time_task.get('task_id')
  1354. if task_id:
  1355. try:
  1356. apscheduler_obj.resume_job(task_id)
  1357. except Exception:
  1358. continue
  1359. return None
  1360. else:
  1361. now_time = int(time.time())
  1362. time_stamp = scene_data_dict['condition']['time_dict']['time_stamp']
  1363. # 恢复定时任务
  1364. if time_stamp > now_time:
  1365. for time_task in time_task_list:
  1366. task_id = time_task.get('task_id')
  1367. if task_id:
  1368. try:
  1369. apscheduler_obj.resume_job(task_id)
  1370. except Exception:
  1371. continue
  1372. return None
  1373. else:
  1374. # 创建新的定时任务,时间+24小时
  1375. time_stamp += 24 * 60 * 60
  1376. task_list_len = len(time_task_list)
  1377. for index, time_task in enumerate(time_task_list):
  1378. device_type = time_task['device_type']
  1379. event_type = time_task['event_type']
  1380. serial_number = time_task['serial_number']
  1381. task_id = serial_number + '_' + str(time_stamp)
  1382. # 最后一个任务使用传入的scene_id
  1383. smart_scene_id = scene_id if index == task_list_len-1 else 0
  1384. apscheduler_obj.create_date_job(func=cls.pub_mqtt, task_id=task_id, time_stamp=time_stamp,
  1385. args=(device_type, event_type, serial_number, smart_scene_id))
  1386. # 更新task_id
  1387. time_task['task_id'] = task_id
  1388. # 更新场景数据的时间戳
  1389. scene_data_dict['condition']['time_dict']['time_stamp'] = time_stamp
  1390. return scene_data_dict
  1391. #
  1392. # ___====-_ _-====___
  1393. # _--^^^#####// \\#####^^^--_
  1394. # _-^##########// ( ) \\##########^-_
  1395. # -############// |\^^/| \\############-
  1396. # _/############// (@::@) \\############\_
  1397. # /#############(( \\// ))#############\
  1398. # -###############\\ (oo) //###############-
  1399. # -#################\\ / VV \ //#################-
  1400. # -###################\\/ \//###################-
  1401. # _#/|##########/\######( /\ )######/\##########|\#_
  1402. # |/ |#/\#/\#/\/ \#/\##\ | | /##/\#/ \/\#/\#/\#| \|
  1403. # ` |/ V V ` V \#\| | | |/#/ V ' V V \| '
  1404. # ` ` ` ` / | | | | \ ' ' ' '
  1405. # ( | | | | )
  1406. # __\ | | | | /__
  1407. # (vvv(VVV)(VVV)vvv)
  1408. # 神兽保佑
  1409. # 代码无BUG!
  1410. #