SmartSwitchController.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. # -*- coding: utf-8 -*-
  2. """
  3. # @Author : cheng
  4. # @Time : 2023/7/10 11:20
  5. # @File: SmartSwitchController.py
  6. """
  7. import datetime
  8. import time
  9. from django.views import View
  10. from Model.models import SwitchInfo, SwitchDimmingSettings, SwitchChronopher, Device_Info, SceneLog
  11. from Service.CommonService import CommonService
  12. from Object.ApschedulerObject import ApschedulerObject
  13. from django.db import transaction
  14. from Ansjer.config import LOGGER
  15. APSCHEDULER_TOPIC_NAME = 'loocam/switch/time_scheduling/{}' # 排程主题
  16. class SmartSwitchView(View):
  17. def get(self, request, *args, **kwargs):
  18. request.encoding = 'utf-8'
  19. operation = kwargs.get('operation')
  20. return self.validation(request.GET, request, operation)
  21. def post(self, request, *args, **kwargs):
  22. request.encoding = 'utf-8'
  23. operation = kwargs.get('operation')
  24. return self.validation(request.POST, request, operation)
  25. def validation(self, request_dict, request, operation):
  26. token_code, user_id, response = CommonService.verify_token_get_user_id(request_dict, request)
  27. if token_code != 0:
  28. return response.json(token_code)
  29. if operation == 'get-switch-info': # 设备获取智能开关数据
  30. return self.get_switch_info(request_dict, response)
  31. elif operation == 'get-dimming-setting': # 获取智能开关调光设置
  32. return self.get_dimming_setting(request_dict, response)
  33. elif operation == 'get-chronopher-setting': # 获取定时计划
  34. return self.get_chronopher_setting(request_dict, response)
  35. elif operation == 'add-or-edit-chronopher': # 添加/编辑定时计划
  36. return self.add_or_edit_chronopher(request_dict, response)
  37. elif operation == 'delete-chronopher': # 删除定时计划
  38. return self.delete_chronopher(request_dict, response)
  39. elif operation == 'edit-dimming-correction': # 设置调光校正
  40. return self.edit_dimming_correction(request_dict, response)
  41. elif operation == 'edit-dimming-setting': # 修改智能开关调光设置
  42. return self.edit_dimming_setting(request_dict, response)
  43. elif operation == 'reset': # 设备重置
  44. return self.reset(request_dict, response)
  45. elif operation == 'switch-report-log': # 设备上报执行日志
  46. return self.create_log(request_dict, response)
  47. else:
  48. return response.json(414)
  49. @staticmethod
  50. def get_switch_info(request_dict, response):
  51. """
  52. 获取智能开关设备信息
  53. @param request_dict: 请求参数
  54. @request_dict deviceId: 设备id
  55. @param response: 响应对象
  56. @return: response
  57. """
  58. device_id = request_dict.get('deviceId', None)
  59. if not device_id:
  60. return response.json(444)
  61. try:
  62. switch_info_qs = SwitchInfo.objects.filter(device_id=device_id).values()
  63. if not switch_info_qs.exists():
  64. return response.json(173)
  65. res = {
  66. 'model': switch_info_qs[0]['model'],
  67. 'hardwareVersion': switch_info_qs[0]['hardware_version'],
  68. 'firmwareVersion': switch_info_qs[0]['firmware_version'],
  69. 'mac': switch_info_qs[0]['mac'],
  70. }
  71. return response.json(0, res)
  72. except Exception as e:
  73. print(e)
  74. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  75. @staticmethod
  76. def get_dimming_setting(request_dict, response):
  77. """
  78. 获取智能开关调光设置信息
  79. @param request_dict: 请求参数
  80. @param user_id: 用戶user_id
  81. @request_dict deviceId: 设备id
  82. @param response: 响应对象
  83. @return: response
  84. """
  85. device_id = request_dict.get('deviceId', None)
  86. if not device_id:
  87. return response.json(444)
  88. try:
  89. switch_setting_info_qs = SwitchDimmingSettings.objects.filter(device_id=device_id).values()
  90. if not switch_setting_info_qs.exists():
  91. return response.json(173)
  92. res = {
  93. 'clickTurnOnSpeed': switch_setting_info_qs[0]['click_turn_on_speed'],
  94. 'clickTurnOffSpeed': switch_setting_info_qs[0]['click_turn_off_speed'],
  95. 'doubleClick': switch_setting_info_qs[0]['double_click'],
  96. 'press': switch_setting_info_qs[0]['press'],
  97. 'doublePressClickTurnOnSpeed': switch_setting_info_qs[0]['double_press_click_turn_on_speed'],
  98. 'doublePressClickTurnOffSpeed': switch_setting_info_qs[0]['double_press_click_turn_off_speed'],
  99. 'dimmingCorrection': switch_setting_info_qs[0]['dimming_correction'],
  100. }
  101. return response.json(0, res)
  102. except Exception as e:
  103. print(e)
  104. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  105. @staticmethod
  106. def edit_dimming_correction(request_dict, response):
  107. """
  108. 修改智能开关调光校正
  109. @param request_dict: 请求参数
  110. @request_dict deviceId: 设备id
  111. @request_dict dimmingCorrection: 调光校正
  112. @param response: 响应对象
  113. @return: response
  114. """
  115. device_id = request_dict.get('deviceId', None)
  116. dimming_correction = request_dict.get('dimmingCorrection', None)
  117. if not device_id:
  118. return response.json(444)
  119. try:
  120. SwitchDimmingSettings.objects.filter(device_id=device_id).update(dimming_correction=dimming_correction)
  121. return response.json(0)
  122. except Exception as e:
  123. print(e)
  124. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  125. @staticmethod
  126. def edit_dimming_setting(request_dict, response):
  127. """
  128. 修改智能开关调光设置
  129. @param request_dict: 请求参数
  130. @request_dict deviceId: 设备id
  131. @request_dict clickTurnOnSpeed: 单击开启速度
  132. @request_dict clickTurnOffSpeed: 单击关闭速度
  133. @request_dict doubleClick: 双击
  134. @request_dict press: 长按
  135. @request_dict doublePressClickTurnOnSpeed: 双击/长按开启速度
  136. @request_dict doublePressClickTurnOffSpeed: 双击/长按单击关闭速度
  137. @param response: 响应对象
  138. @return: response
  139. """
  140. device_id = request_dict.get('deviceId', None)
  141. click_turn_on_speed = request_dict.get('clickTurnOnSpeed', None)
  142. click_turn_off_speed = request_dict.get('clickTurnOffSpeed', None)
  143. double_click = request_dict.get('doubleClick', None)
  144. press = request_dict.get('press', None)
  145. double_press_click_turn_on_speed = request_dict.get('doublePressClickTurnOnSpeed', None)
  146. double_press_click_turn_off_speed = request_dict.get('doublePressClickTurnOffSpeed', None)
  147. if not device_id:
  148. return response.json(444)
  149. try:
  150. dimming_setting_data = {
  151. 'device_id': device_id,
  152. 'click_turn_on_speed': click_turn_on_speed,
  153. 'click_turn_off_speed': click_turn_off_speed,
  154. 'double_click': double_click,
  155. 'press': press,
  156. 'double_press_click_turn_on_speed': double_press_click_turn_on_speed,
  157. 'double_press_click_turn_off_speed': double_press_click_turn_off_speed
  158. }
  159. SwitchDimmingSettings.objects.filter(device_id=device_id).update(**dimming_setting_data)
  160. return response.json(0)
  161. except Exception as e:
  162. print(e)
  163. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  164. @staticmethod
  165. def get_chronopher_setting(request_dict, response):
  166. """
  167. 获取定时计划设置
  168. @param request_dict: 请求参数
  169. @request_dict deviceId: 设备id
  170. @param response: 响应对象
  171. @return: response
  172. """
  173. device_id = request_dict.get('deviceId', None)
  174. if not device_id:
  175. return response.json(444)
  176. try:
  177. switch_chronopher_qs = SwitchChronopher.objects.filter(device_id=device_id).values()
  178. if not switch_chronopher_qs.exists():
  179. return response.json(173)
  180. switch_chronopher_list = []
  181. for item in switch_chronopher_qs:
  182. switch_chronopher_list.append({
  183. 'chronopherId': item['id'],
  184. 'timeTypeRadio': item['time_type_radio'],
  185. 'timePoint': item['time_point'],
  186. 'timeQuantumStartTime': item['time_quantum_start_time'],
  187. 'timeQuantumEndTime': item['time_quantum_end_time'],
  188. 'timePointDeviceWillDoing': item['time_point_device_will_doing'],
  189. 'timeQuantumDeviceWillDoing': item['time_quantum_device_will_doing'],
  190. 'slowOpenOrCloseSpeed': item['slow_open_or_close_speed'],
  191. 'repeat': item['repeat'],
  192. })
  193. return response.json(0, {'list': switch_chronopher_list})
  194. except Exception as e:
  195. print(e)
  196. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  197. @staticmethod
  198. def add_or_edit_chronopher(request_dict, response):
  199. """
  200. 添加/编辑定时计划
  201. @param request_dict: 请求参数
  202. @request_dict deviceId: 设备id
  203. @request_dict chronopherId: 定时计划id
  204. @request_dict timeTypeRadio: 切换时间点/时间段
  205. @request_dict timePoint: 时间点
  206. @request_dict timeQuantumStartTime: 时间段开始时间
  207. @request_dict timeQuantumEndTime: 时间段结束时间
  208. @request_dict timePointDeviceWillDoing: 设备将会
  209. @request_dict timeQuantumDeviceWillDoing: 设备将会
  210. @request_dict slowOpenOrCloseSpeed: 缓慢开/关速度
  211. @request_dict repeat: 重复周期
  212. @param response: 响应对象
  213. @return: response
  214. """
  215. is_edit = request_dict.get('isEdit', None)
  216. device_id = request_dict.get('deviceId', None)
  217. chronopher_id = request_dict.get('chronopherId', None)
  218. time_type_radio = int(request_dict.get('timeTypeRadio', 0))
  219. time_point = request_dict.get('timePoint', None)
  220. time_quantum_start_time = request_dict.get('timeQuantumStartTime', None)
  221. time_quantum_end_time = request_dict.get('timeQuantumEndTime', None)
  222. time_point_device_will_doing = request_dict.get('timePointDeviceWillDoing', None)
  223. time_quantum_device_will_doing = request_dict.get('timeQuantumDeviceWillDoing', None)
  224. slow_open_or_close_speed = request_dict.get('slowOpenOrCloseSpeed', None)
  225. repeat = request_dict.get('repeat', None)
  226. if not all([device_id, repeat]):
  227. return response.json(444, {'param': 'deviceId,repeat'})
  228. device_qs = Device_Info.objects.filter(id=device_id).values('serial_number')
  229. if not device_qs.exists():
  230. return response.json(174)
  231. if time_type_radio == 1: # 时间点
  232. if not all([time_point, slow_open_or_close_speed]):
  233. return response.json(444, {'param': 'timePoint,slowOpenOrCloseSpeed'})
  234. chronopher_data = {
  235. 'device_id': device_id,
  236. 'time_type_radio': time_type_radio,
  237. 'time_point': time_point,
  238. 'time_point_device_will_doing': time_point_device_will_doing,
  239. 'slow_open_or_close_speed': slow_open_or_close_speed,
  240. 'repeat': repeat
  241. }
  242. elif time_type_radio == 2: # 时间段
  243. if not all([time_quantum_start_time, time_quantum_end_time]):
  244. return response.json(444, {'param': 'timeQuantumStartTime,timeQuantumEndTime'})
  245. time_quantum_start_time = int(time_quantum_start_time)
  246. time_quantum_end_time = int(time_quantum_end_time)
  247. chronopher_data = {
  248. 'device_id': device_id,
  249. 'time_type_radio': time_type_radio,
  250. 'time_quantum_start_time': time_quantum_start_time,
  251. 'time_quantum_end_time': time_quantum_end_time,
  252. 'time_quantum_device_will_doing': time_quantum_device_will_doing,
  253. 'repeat': repeat
  254. }
  255. else:
  256. return response.json(444, {'param': 'timeTypeRadio'})
  257. try:
  258. with transaction.atomic():
  259. apscheduler_obj = ApschedulerObject()
  260. if is_edit:
  261. if not chronopher_id:
  262. return response.json(444, {'param': 'timeTypeRadio'})
  263. update_flag = SwitchChronopher.objects.filter(device_id=device_id, id=chronopher_id).update(
  264. **chronopher_data)
  265. if not update_flag:
  266. return response.json(173)
  267. apscheduler_obj.del_job('switchchronopher_{}'.format(chronopher_id))
  268. apscheduler_obj.del_job('switchchronopher_{}_1'.format(chronopher_id))
  269. apscheduler_obj.del_job('switchchronopher_{}_2'.format(chronopher_id))
  270. else:
  271. switch_qs = SwitchChronopher.objects.create(**chronopher_data)
  272. chronopher_id = switch_qs.id
  273. # 设置定时任务
  274. serial_number = device_qs[0]['serial_number']
  275. topic_name = APSCHEDULER_TOPIC_NAME.format(serial_number)
  276. if time_type_radio == 1:
  277. task_id = 'switchchronopher_{}'.format(chronopher_id)
  278. if time_point_device_will_doing in ['0', '1']: # 开启或关闭
  279. msg = {
  280. "taskId": chronopher_id,
  281. "deviceSwitch": int(time_point_device_will_doing), # 设备开关0:关,1:开
  282. "slowTime": slow_open_or_close_speed
  283. }
  284. else: # 开启且设置亮度
  285. msg = {
  286. "taskId": chronopher_id,
  287. "deviceSwitch": 1, # 设备开关0:关,1:开
  288. "pwmControl": int(time_point_device_will_doing),
  289. 'slowTime': slow_open_or_close_speed
  290. }
  291. time_str = datetime.datetime.fromtimestamp(int(time_point))
  292. apscheduler_obj.create_cron_job(SmartSwitchView.send_mqtt, task_id, repeat, time_str.hour,
  293. time_str.minute, (serial_number, topic_name, msg, task_id))
  294. else:
  295. start_hour = int(time_quantum_start_time / 60 // 60)
  296. start_minute = int(time_quantum_start_time / 60 % 60)
  297. end_hour = int(time_quantum_end_time / 60 // 60)
  298. end_minute = int(time_quantum_end_time / 60 % 60)
  299. if time_quantum_device_will_doing in ['0', '1']:
  300. begin_task_id = 'switchchronopher_{}_1'.format(chronopher_id) # 开始任务id
  301. end_task_id = 'switchchronopher_{}_2'.format(chronopher_id) # 结束任务id
  302. msg = {"taskId": chronopher_id,
  303. "deviceSwitch": int(time_quantum_device_will_doing)}
  304. apscheduler_obj.create_cron_job(SmartSwitchView.send_mqtt, begin_task_id, repeat, start_hour,
  305. start_minute, (serial_number, topic_name, msg, begin_task_id))
  306. msg = {"taskId": chronopher_id,
  307. "deviceSwitch": 0 if int(time_quantum_device_will_doing) == 1 else 1}
  308. apscheduler_obj.create_cron_job(SmartSwitchView.send_mqtt, end_task_id, repeat, end_hour,
  309. end_minute, (serial_number, topic_name, msg, end_task_id))
  310. else: # 间隔任务
  311. minute = int(time_quantum_device_will_doing)
  312. task_id = 'switchchronopher_{}'.format(chronopher_id) # 开始任务id
  313. msg = {"taskId": chronopher_id,
  314. "deviceSwitch": -1}
  315. if minute >= 60:
  316. hour = '{}-{}/{}'.format(start_hour, end_hour, minute // 60)
  317. minute = start_minute
  318. else:
  319. hour = '{}-{}'.format(start_hour, end_hour)
  320. minute = '*/{}'.format(minute)
  321. apscheduler_obj.create_cron_job(SmartSwitchView.send_mqtt, task_id, repeat, hour, minute,
  322. (serial_number, topic_name, msg, task_id))
  323. return response.json(0)
  324. except Exception as e:
  325. print(e)
  326. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  327. @staticmethod
  328. def delete_chronopher(request_dict, response):
  329. """
  330. 删除定时计划
  331. @param request_dict: 请求参数
  332. @request_dict deviceId: 设备id
  333. @request_dict chronopherId: 定时计划id
  334. @param response: 响应对象
  335. @return: response
  336. """
  337. device_id = request_dict.get('deviceId', None)
  338. chronopher_id = request_dict.get('chronopherId', None)
  339. if not chronopher_id:
  340. return response.json(444, {'error param': 'deviceId or chronopherId'})
  341. try:
  342. delete_flag = SwitchChronopher.objects.filter(device_id=device_id, id=chronopher_id).delete()
  343. if not delete_flag[0]:
  344. return response.json(173)
  345. apscheduler_obj = ApschedulerObject()
  346. apscheduler_obj.del_job('switchchronopher_{}'.format(chronopher_id)) # 删除定时任务
  347. apscheduler_obj.del_job('switchchronopher_{}_1'.format(chronopher_id))
  348. apscheduler_obj.del_job('switchchronopher_{}_2'.format(chronopher_id))
  349. return response.json(0)
  350. except Exception as e:
  351. print(e)
  352. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  353. @staticmethod
  354. def send_mqtt(serial_number, topic_name, msg, task_id):
  355. """
  356. 定时发送mqtt, (不要随意更改,否则定时任务不执行)
  357. @param serial_number: 设备序列号
  358. @param topic_name: 主题
  359. @param msg: 消息
  360. @param task_id: 任务id
  361. @return: response
  362. """
  363. result = CommonService.req_publish_mqtt_msg(serial_number, topic_name, msg)
  364. LOGGER.info(
  365. '定时发送mqtt结果:{},参数:{},{},{},{},{}'.format(result, serial_number, topic_name, msg, int(time.time()), task_id))
  366. @staticmethod
  367. def create_log(request_dict, response):
  368. """
  369. 生成执行日志
  370. @param request_dict: 请求参数
  371. @request_dict serialNumber: 设备序列号
  372. @request_dict chronopherId: 排程id
  373. @request_dict status: 执行状态
  374. @param response: 响应对象
  375. @return: response
  376. """
  377. serial_number = request_dict.get('serialNumber', None)
  378. chronopher_id = request_dict.get('taskId', None)
  379. status = request_dict.get('status', None)
  380. implement_time = request_dict.get('implementTime', None)
  381. if not all([serial_number, chronopher_id, status, implement_time]):
  382. return response.json(444, {'error param': 'deviceId or chronopherId'})
  383. device_qs = Device_Info.objects.filter(serial_number=serial_number).values('id')
  384. if not device_qs.exists():
  385. return response.json(173)
  386. device_id = device_qs[0]['id']
  387. chronopher_qs = SwitchChronopher.objects.filter(device_id=device_id, id=chronopher_id)
  388. if not chronopher_qs.exists():
  389. return response.json(173)
  390. try:
  391. scene_log = {
  392. 'scene_id': chronopher_id,
  393. 'device_id': device_id,
  394. 'tasks': '',
  395. 'status': status,
  396. 'created_time': implement_time,
  397. }
  398. scene_qs = SceneLog.objects.filter(created_time=implement_time, device_id=device_id,
  399. scene_id=chronopher_id)
  400. if not scene_qs.exists():
  401. SceneLog.objects.create(**scene_log)
  402. return response.json(0)
  403. except Exception as e:
  404. print(e)
  405. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  406. @staticmethod
  407. def get_log(request_dict, response):
  408. """
  409. 查询执行日志
  410. @param request_dict: 请求参数
  411. @request_dict deviceId: 设备id
  412. @param response: 响应对象
  413. @return: response
  414. """
  415. device_id = request_dict.get('deviceId', None)
  416. if not device_id:
  417. return response.json(444, {'error param': 'deviceId'})
  418. try:
  419. scene_qs = SceneLog.objects.filter(device_id=device_id).values('tasks', 'status', 'created_time', 'id')
  420. return response.json(0, list(scene_qs))
  421. except Exception as e:
  422. print(e)
  423. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  424. @staticmethod
  425. def reset(request_dict, response):
  426. """
  427. 查询执行日志
  428. @param request_dict: 请求参数
  429. @request_dict serialNumber: 设备序列号
  430. @param response: 响应对象
  431. @return: response
  432. """
  433. serial_number = request_dict.get('serialNumber', None)
  434. if not serial_number:
  435. return response.json(444, {'error param': 'serialNumber'})
  436. device_qs = Device_Info.objects.filter(serial_number=serial_number)
  437. if not device_qs.exists():
  438. return response.json(173)
  439. device_id_list = list(device_qs.values_list('id', flat=True))
  440. try:
  441. # 删除智能开关数据
  442. SwitchDimmingSettings.objects.filter(device_id__in=device_id_list).delete()
  443. SwitchChronopher.objects.filter(device_id__in=device_id_list).delete()
  444. SceneLog.objects.filter(device_id__in=device_id_list).delete()
  445. except Exception as e:
  446. print(e)
  447. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))