# -*- coding: utf-8 -*- """ @Author : Rocky @Time : 2022/6/29 9:31 @File :SmartSceneController.py """ import json import time from django.core.exceptions import ObjectDoesNotExist from django.db import transaction from django.db.models import F, Q, Count from django.views import View from Model.models import FamilyRoomDevice, GatewaySubDevice, FamilyRoom, SmartScene, EffectiveTime, Device_Info, \ SceneLog from Service.CommonService import CommonService class SmartSceneView(View): def get(self, request, *args, **kwargs): request.encoding = 'utf-8' operation = kwargs.get('operation') return self.validation(request.GET, request, operation) def post(self, request, *args, **kwargs): request.encoding = 'utf-8' operation = kwargs.get('operation') return self.validation(request.POST, request, operation) def validation(self, request_dict, request, operation): token_code, user_id, response = CommonService.verify_token_get_user_id(request_dict, request) if token_code != 0: return response.json(token_code) if operation == 'condition-devices': # 添加条件-查询设备 return self.condition_devices(request_dict, response) elif operation == 'task-devices': # 添加任务-查询设备 return self.task_devices(request_dict, response) elif operation == 'create': # 创建智能场景 return self.create_smart_scene(request_dict, user_id, response) elif operation == 'scene-list': # 查询智能场景列表 return self.scene_list(request_dict, user_id, response) elif operation == 'smart-button-scene-list': # 查询智能按钮场景列表 return self.smart_button_scene_list(request_dict, user_id, response) elif operation == 'update-status': # 更新智能场景状态 return self.update_status(request_dict, response) elif operation == 'detail': # 查询智能场景详情 return self.scene_detail(request_dict, response) elif operation == 'edit': # 编辑智能场景 return self.edit_smart_scene(request_dict, user_id, response) elif operation == 'delete': # 删除智能场景 return self.delete_smart_scene(request_dict, response) elif operation == 'log': # 查询智能场景日志 return self.scene_log(request_dict, response) elif operation == 'log-date': return self.scene_log_date(request_dict, response) else: return response.json(414) @classmethod def condition_devices(cls, request_dict, response): """ 添加条件-查询设备 @param request_dict: 请求参数 @request_dict deviceId: 网关设备id @request_dict subDeviceId: 子设备id @param response: 响应对象 @return: response """ device_id = request_dict.get('deviceId', None) sub_device_id = request_dict.get('subDeviceId', None) if not any([device_id, sub_device_id]): return response.json(444, {'error param': 'deviceId or subDeviceId'}) try: if sub_device_id: device_id = GatewaySubDevice.objects.get(id=sub_device_id).device_id gateway_sub_device_qs = GatewaySubDevice.objects.filter(device_id=device_id) if not gateway_sub_device_qs.exists(): return response.json(173) res = cls.get_sub_device_room_name(gateway_sub_device_qs) return response.json(0, res) except Exception as e: return response.json(500, repr(e)) @classmethod def task_devices(cls, request_dict, response): """ 添加任务-查询设备 @param request_dict: 请求参数 @request_dict deviceId: 网关设备id @param response: 响应对象 @return: response """ sub_device_id = request_dict.get('subDeviceId', None) device_id = request_dict.get('deviceId', None) if not any([device_id, sub_device_id]): return response.json(444, {'error param': 'deviceId or subDeviceId'}) try: if device_id: res = [cls.get_gateway_data(device_id)] else: sub_device_qs = GatewaySubDevice.objects.filter(id=sub_device_id).values('device_id', 'device_type') device_id = sub_device_qs[0]['device_id'] device_type = sub_device_qs[0]['device_type'] if device_type != 216: # 非智能按钮只返回网关 res = [cls.get_gateway_data(device_id)] else: gateway_data = cls.get_gateway_data(device_id) sub_device_qs = GatewaySubDevice.objects.filter( Q(device_id=device_id) & Q(device_type=215) | Q(device_type=219)).values('id', 'nickname', 'status', 'device_type') if not sub_device_qs.exists(): return response.json(173) res = cls.get_sub_device_room_name(sub_device_qs, gateway_data) return response.json(0, res) except Exception as e: return response.json(500, repr(e)) @staticmethod def get_sub_device_room_name(sub_device_qs, gateway_data=None): """ 获取房间名称 @param sub_device_qs: 子设备信息 @param gateway_data: 网关参数 @return: sub_device_list """ sub_device_list = [] if gateway_data: sub_device_list.append(gateway_data) sub_device_qs = sub_device_qs.annotate(gatewaySubId=F('id'), deviceType=F('device_type'), deviceNickName=F('nickname')). \ values('gatewaySubId', 'deviceType', 'deviceNickName', 'status') for sub_device in sub_device_qs: family_room_device_qs = FamilyRoomDevice.objects.filter(sub_device=sub_device['gatewaySubId']). \ values('room_id') if not family_room_device_qs.exists(): sub_device['roomName'] = '' else: room_id = family_room_device_qs[0]['room_id'] try: sub_device['roomName'] = FamilyRoom.objects.get(id=room_id).name except ObjectDoesNotExist: sub_device['roomName'] = '' sub_device_list.append(sub_device) return sub_device_list @staticmethod def get_gateway_data(device_id): """ 获取网关数据 @param device_id: 网关设备id @return: res """ device_info_qs = Device_Info.objects.filter(id=device_id).values('NickName', 'Type') nickname = device_info_qs[0]['NickName'] device_type = device_info_qs[0]['Type'] room_id = FamilyRoomDevice.objects.filter(device_id=device_id).values('room_id')[0]['room_id'] room_id_qs = FamilyRoom.objects.filter(id=room_id).values('name') room_name = room_id_qs.first()['name'] if room_id_qs.exists() else '' res = { 'deviceNickName': nickname, 'deviceType': device_type, 'roomName': room_name, 'status': 1, } return res @staticmethod def create_smart_scene(request_dict, user_id, response): """ 创建智能场景 @param request_dict: 请求参数 @param user_id: 用户id @request_dict deviceId: 网关设备id @request_dict subDeviceId: 子设备id @request_dict sceneName: 场景名称 @request_dict conditions: 条件 @request_dict tasks: 任务 @request_dict isAllDay: 是否全天执行 @request_dict startTime: 开始时间 @request_dict endTime: 结束时间 @request_dict repeat: 重复周期 @param response: 响应对象 @return: response """ device_id = request_dict.get('deviceId', None) sub_device_id = request_dict.get('subDeviceId', None) scene_name = request_dict.get('sceneName', None) conditions = request_dict.get('conditions', None) tasks = request_dict.get('tasks', None) is_all_day = request_dict.get('isAllDay', None) if not all([scene_name, conditions, tasks]): return response.json(444, {'error param': 'scene_name and conditions and tasks'}) now_time = int(time.time()) conditions_dict = eval(conditions) tasks_list = eval(tasks) try: # 判断是否已存在该场景名 smart_scene_qs = SmartScene.objects.filter(user_id=user_id, scene_name=scene_name) if smart_scene_qs.exists(): return response.json(179) smart_scene_dict = { 'user_id': user_id, 'scene_name': scene_name, 'conditions': conditions, 'tasks': tasks, 'created_time': now_time, 'updated_time': now_time, } msg = { 'scene_status': 1 } # 处理设置时间 if is_all_day is not None: is_all_day = int(is_all_day) smart_scene_dict['is_all_day'] = is_all_day # 处理传网关设备id和子设备id的情况 if conditions_dict['type'] == 1: # 网关设置时间 if not device_id: return response.json(444, {'error param': 'deviceId'}) smart_scene_dict['device_id'] = device_id device_info_qs = Device_Info.objects.filter(id=device_id).values('serial_number') if not device_info_qs.exists(): return response.json(173) serial_number = device_info_qs[0]['serial_number'] else: # 子设备设置场景 if not sub_device_id: return response.json(444, {'error param': 'subDeviceId'}) # 智能按钮不能创建触发条件相同的场景 device_type = conditions_dict['sensor']['device_type'] if device_type == '216': event_type = conditions_dict['sensor']['eventValues'][0]['event_type'] smart_scene_qs = SmartScene.objects.filter(sub_device_id=sub_device_id, conditions__contains=event_type) if smart_scene_qs.exists(): return response.json(180) smart_scene_dict['sub_device_id'] = sub_device_id sub_device_qs = GatewaySubDevice.objects.filter(id=sub_device_id).values('device__serial_number', 'src_addr') if not sub_device_qs.exists(): return response.json(173) serial_number = sub_device_qs[0]['device__serial_number'] msg['sensor_type'] = int(conditions_dict['sensor']['device_type']) msg['sensor_src'] = int(sub_device_qs[0]['src_addr'], 16) msg['sensor_status'] = int(conditions_dict['sensor']['eventValues'][0]['event_type']) with transaction.atomic(): if is_all_day is None: # 不设置时间 smart_scene_qs = SmartScene.objects.create(**smart_scene_dict) # 设备的time数据,分钟转为秒 time_dict = { 'start_time': conditions_dict['time']['minutes'] * 60, 'repeat': conditions_dict['time']['repeat'] } elif is_all_day == 1: # 全天 smart_scene_qs = SmartScene.objects.create(**smart_scene_dict) # 设备的time数据 time_dict = { 'is_all_day': is_all_day } elif is_all_day == 2: # 非全天 start_time = int(request_dict.get('startTime', None)) end_time = int(request_dict.get('endTime', None)) repeat = int(request_dict.get('repeat', None)) effective_time_qs = EffectiveTime.objects.filter(start_time=start_time, end_time=end_time, repeat=repeat).values('id') if effective_time_qs.exists(): effective_time_id = effective_time_qs[0]['id'] else: effective_time_id = EffectiveTime.objects.create(start_time=start_time, end_time=end_time, repeat=repeat).id smart_scene_dict['effective_time_id'] = effective_time_id smart_scene_qs = SmartScene.objects.create(**smart_scene_dict) # 设备的time数据,分钟转为秒 time_dict = { 'is_all_day': is_all_day, 'start_time': start_time * 60, 'end_time': end_time * 60, 'repeat': repeat } else: return response.json(444, {'error param': 'invalid isAllDay'}) msg['time'] = time_dict msg['smart_scene_id'] = smart_scene_qs.id task_list = [] for task in tasks_list: task_temp = { 'sensor_type': int(task['device_type']), 'sensor_action': int(task['event_type']) } sub_device_id = task.get('subDeviceId', None) if sub_device_id: sub_device_qs = GatewaySubDevice.objects.filter(id=sub_device_id).values('src_addr').first() task_temp['sensor_src'] = int(sub_device_qs['src_addr'], 16) task_list.append(task_temp) msg['task'] = task_list smart_scene_qs.device_data = json.dumps(msg) smart_scene_qs.save() # 发布MQTT消息通知网关设备 thing_name = serial_number topic_name = 'loocam/gateway_sensor/smart_scene/{}'.format(serial_number) success = CommonService.req_publish_mqtt_msg(thing_name, topic_name, msg) try: assert success except AssertionError: return response.json(10044) return response.json(0) except Exception as e: return response.json(500, repr(e)) @staticmethod def scene_list(request_dict, user_id, response): """ 查询智能场景列表 @param request_dict: 请求参数 @param user_id: 用户id @request_dict deviceId: 网关设备id @request_dict subDeviceId: 子设备id @param response: 响应对象 @return: response """ device_id = request_dict.get('deviceId', None) sub_device_id = request_dict.get('subDeviceId', None) if not any([device_id, sub_device_id]): return response.json(444, {'error param': 'deviceId or subDeviceId'}) try: if device_id: sub_device_id = GatewaySubDevice.objects.filter(device_id=device_id).values('id') smart_scene_qs = SmartScene.objects.filter( Q(user_id=user_id) & Q(device_id=device_id) | Q(sub_device_id__in=sub_device_id)) else: smart_scene_qs = SmartScene.objects.filter(user_id=user_id, sub_device_id=sub_device_id) if not smart_scene_qs.exists(): return response.json(173) smart_scene_qs = smart_scene_qs.values('id', 'scene_name', 'is_enable') return response.json(0, list(smart_scene_qs)) except Exception as e: return response.json(500, repr(e)) @staticmethod def smart_button_scene_list(request_dict, user_id, response): """ 查询智能按钮场景列表 @param request_dict: 请求参数 @param user_id: 用户id @request_dict subDeviceId: 子设备id @param response: 响应对象 @return: response """ sub_device_id = request_dict.get('subDeviceId', None) if not sub_device_id: return response.json(444, {'error param': 'subDeviceId'}) try: click_scene_qs = SmartScene.objects.filter(user_id=user_id, sub_device_id=sub_device_id, conditions__contains='2161').values('id', 'scene_name', 'is_enable') double_click_scene_qs = SmartScene.objects.filter(user_id=user_id, sub_device_id=sub_device_id, conditions__contains='2162').values('id', 'scene_name', 'is_enable') press_scene_qs = SmartScene.objects.filter(user_id=user_id, sub_device_id=sub_device_id, conditions__contains='2163').values('id', 'scene_name', 'is_enable') scene_list = [] if click_scene_qs.exists(): scene_list.append({ 'trigger_type': 1, 'id': click_scene_qs[0]['id'], 'scene_name': click_scene_qs[0]['scene_name'], 'is_enable': click_scene_qs[0]['is_enable'] }) if double_click_scene_qs.exists(): scene_list.append({ 'trigger_type': 2, 'id': double_click_scene_qs[0]['id'], 'scene_name': double_click_scene_qs[0]['scene_name'], 'is_enable': double_click_scene_qs[0]['is_enable'] }) if press_scene_qs.exists(): scene_list.append({ 'trigger_type': 3, 'id': press_scene_qs[0]['id'], 'scene_name': press_scene_qs[0]['scene_name'], 'is_enable': press_scene_qs[0]['is_enable'] }) return response.json(0, scene_list) except Exception as e: return response.json(500, repr(e)) @staticmethod def update_status(request_dict, response): """ 更新智能场景状态 @param request_dict: 请求参数 @request_dict smartSceneId: 智能场景id @request_dict isEnable: 状态,True or False @param response: 响应对象 @return: response """ smart_scene_id = request_dict.get('smartSceneId', None) is_enable = request_dict.get('isEnable', None) if not all([smart_scene_id, is_enable]): return response.json(444, {'error param': 'smartSceneId and status'}) try: SmartScene.objects.filter(id=smart_scene_id).update(is_enable=is_enable) return response.json(0) except Exception as e: return response.json(500, repr(e)) @staticmethod def scene_detail(request_dict, response): """ 查询智能场景详情 @param request_dict: 请求参数 @request_dict smartSceneId: 智能场景id @param response: 响应对象 @return: response """ smart_scene_id = request_dict.get('smartSceneId', None) if not smart_scene_id: return response.json(444, {'error param': 'smartSceneId'}) try: smart_scene_qs = SmartScene.objects.filter(id=smart_scene_id).values('id', 'scene_name', 'conditions', 'tasks', 'effective_time_id', 'is_all_day') if not smart_scene_qs.exists(): return response.json(173) res = { 'scene_name': smart_scene_qs[0]['scene_name'], 'condition': eval(smart_scene_qs[0]['conditions']), 'task': eval(smart_scene_qs[0]['tasks']), } # 如果存在关联的时间数据,组织时间数据 is_all_day = smart_scene_qs[0]['is_all_day'] effectiveTime = {} if is_all_day != 0: effectiveTime['isAllDay'] = is_all_day if is_all_day == 2: try: effective_time_qs = EffectiveTime.objects.get(id=smart_scene_qs[0]['effective_time_id']) effectiveTime['startTime'] = effective_time_qs.start_time effectiveTime['endTime'] = effective_time_qs.end_time effectiveTime['repeat'] = effective_time_qs.repeat except ObjectDoesNotExist: return response.json(0, res) res['effectiveTime'] = effectiveTime return response.json(0, res) except Exception as e: return response.json(500, repr(e)) @staticmethod def edit_smart_scene(request_dict, user_id, response): """ 编辑智能场景 @param request_dict: 请求参数 @param user_id: 用户id @request_dict smartSceneId: 智能场景id @param response: 响应对象 @return: response """ smart_scene_id = request_dict.get('smartSceneId', None) device_id = request_dict.get('deviceId', None) sub_device_id = request_dict.get('subDeviceId', None) scene_name = request_dict.get('sceneName', None) conditions = request_dict.get('conditions', None) tasks = request_dict.get('tasks', None) is_all_day = request_dict.get('isAllDay', None) conditions_dict = eval(conditions) tasks_list = eval(tasks) now_time = int(time.time()) smart_scene_qs = SmartScene.objects.filter(user_id=user_id, scene_name=scene_name).filter(~Q(id=smart_scene_id)) if smart_scene_qs.exists(): return response.json(179) res = { 'scene_name': scene_name, 'conditions': conditions_dict, 'tasks': tasks_list } effective_time = {} if is_all_day: is_all_day = int(is_all_day) effective_time['is_all_day'] = is_all_day if not all([smart_scene_id, scene_name, conditions, tasks]): return response.json(444, {'error param': 'smartSceneId,sceneName,conditions or tasks'}) try: smart_scene_qs = SmartScene.objects.filter(id=smart_scene_id) if not smart_scene_qs.exists(): return response.json(173) msg = {} if conditions_dict['type'] == 2: # 条件为选择子设备 if not sub_device_id: return response.json(444, {'error param': 'subDeviceId'}) # 智能按钮不能创建触发条件相同的场景 device_type = conditions_dict['sensor']['device_type'] if device_type == '216': event_type = conditions_dict['sensor']['eventValues'][0]['event_type'] smart_scene_qs = SmartScene.objects.filter(sub_device_id=sub_device_id, conditions__contains=event_type) if smart_scene_qs.exists(): return response.json(180) device_id = '' sub_device_qs = GatewaySubDevice.objects.filter(id=sub_device_id).values('src_addr', 'device__serial_number') if not sub_device_qs.exists(): return response.json(173) serial_number = sub_device_qs[0]['device__serial_number'] msg['smart_scene_id'] = smart_scene_id msg['scene_status'] = 1 msg['sensor_type'] = conditions_dict['sensor']['device_type'] msg['sensor_src'] = int(sub_device_qs[0]['src_addr'], 16) msg['sensor_status'] = int(conditions_dict['sensor']['eventValues'][0]['event_type']) else: if not device_id: return response.json(444, {'error param': 'deviceId'}) sub_device_id = 0 device_qs = Device_Info.objects.filter(id=device_id).value('serial_number') if not device_qs.exists(): return response.json(173) serial_number = device_qs[0]['serial_number'] task_list = [] for task in tasks_list: task_temp = { 'sensor_type': int(task['device_type']), 'sensor_action': int(task['event_type']) } task_sub_device_id = task.get('subDeviceId', None) if task_sub_device_id: sub_device_qs = GatewaySubDevice.objects.filter(id=task_sub_device_id).values('src_addr').first() task_temp['sensor_src'] = int(sub_device_qs['src_addr'], 16) task_list.append(task_temp) msg['task'] = task_list with transaction.atomic(): smart_scene_qs.update(scene_name=scene_name, conditions=conditions, tasks=tasks, device_data=json.dumps(msg), updated_time=now_time, device_id=device_id, sub_device_id=sub_device_id) if is_all_day is None: # 不设置时间或全天 smart_scene_qs.update(effective_time_id=0, is_all_day=0) time_dict = { 'start_time': conditions_dict['time']['minutes'] * 60, 'repeat': conditions_dict['time']['repeat'] } elif is_all_day == 1: smart_scene_qs.update(effective_time_id=0, is_all_day=is_all_day) time_dict = { 'is_all_day': is_all_day } else: start_time = int(request_dict.get('startTime', None)) end_time = int(request_dict.get('endTime', None)) repeat = int(request_dict.get('repeat', None)) effective_time_qs = EffectiveTime.objects.filter(start_time=start_time, end_time=end_time, repeat=repeat).values('id') if effective_time_qs.exists(): effective_time_id = effective_time_qs[0]['id'] else: effective_time_id = EffectiveTime.objects.create(start_time=start_time, end_time=end_time, repeat=repeat).id smart_scene_qs.update(effective_time_id=effective_time_id, is_all_day=is_all_day) time_dict = { 'is_all_day': is_all_day, 'start_time': start_time * 60, 'end_time': end_time * 60, 'repeat': repeat } effective_time = { 'isAllDay': is_all_day, 'startTime': start_time, 'endTime': end_time, 'repeat': repeat } msg['time'] = time_dict # 通过mqtt发送设备数据 thing_name = serial_number topic_name = 'loocam/gateway_sensor/smart_scene/{}'.format(serial_number) success = CommonService.req_publish_mqtt_msg(thing_name, topic_name, msg) res['effectiveTime'] = effective_time return response.json(0, res) except Exception as e: return response.json(500, repr(e)) @staticmethod def delete_smart_scene(request_dict, response): """ 删除智能场景 @param request_dict: 请求参数 @request_dict smartSceneIds: 智能场景id @param response: 响应对象 @return: response """ smart_scene_ids = request_dict.get('smartSceneIds', None) if not smart_scene_ids: return response.json(444, {'error param': 'smartSceneIds'}) try: SmartScene.objects.filter(id__in=smart_scene_ids.split(',')).delete() except Exception as e: return response.json(500, repr(e)) else: return response.json(0) @staticmethod def scene_log(request_dict, response): """ 查询场景日志 @param request_dict: 请求参数 @request_dict deviceId: 网关id @request_dict subDeviceId: 子设备id @request_dict page: 页数 @request_dict size: 条数 @request_dict startTime: 开始时间 @request_dict endTime: 结束时间 @param response: 响应对象 @return: response """ device_id = request_dict.get('deviceId', None) sub_device_id = request_dict.get('subDeviceId', None) page = request_dict.get('page', None) size = request_dict.get('size', None) start_time = request_dict.get('startTime', None) end_time = request_dict.get('endTime', None) if not any([device_id, sub_device_id]): return response.json(444, {'error param': 'deviceId and subDeviceId'}) if not all([page, size]): return response.json(444, {'error param': 'page or size'}) device_dict = {} if device_id: device_dict['device_id'] = device_id else: device_dict['sub_device_id'] = sub_device_id try: page, size = int(page), int(size) if start_time and end_time: scene_log_qs = SceneLog.objects.filter(**device_dict, created_time__range=(start_time, end_time)). \ values('scene_id', 'scene_log', 'status', 'created_time').order_by( '-created_time')[(page - 1) * size:page * size] else: scene_log_qs = SceneLog.objects.filter(**device_dict).values('scene_id', 'scene_log', 'status', 'created_time').order_by( '-created_time')[(page - 1) * size:page * size] if not scene_log_qs.exists(): return response.json(0, []) for item in scene_log_qs: scene_id = item['scene_id'] scene_name = SmartScene.objects.filter(id=scene_id)[0].scene_name item['scene_name'] = scene_name return response.json(0, list(scene_log_qs)) except Exception as e: print(repr(e)) return response.json(500, repr(e)) @staticmethod def scene_log_date(request_dict, response): """ 查询场景日志日期 @param request_dict: 请求参数 @request_dict deviceId: 网关id @request_dict subDeviceId: 子设备id @param response: 响应对象 @return: response """ device_id = request_dict.get('deviceId', None) sub_device_id = request_dict.get('subDeviceId', None) if device_id: device_dict = { 'device_id': device_id } else: device_dict = { 'sub_device_id': sub_device_id } if not any([device_id, sub_device_id]): return response.json(444, {'error param': 'device_id and gatewaySubId'}) try: scene_log_qs = SceneLog.objects.extra( select={'date': "FROM_UNIXTIME(created_time,'%%Y-%%m-%%d')"}).values('date'). \ filter(**device_dict). \ annotate(count=Count('created_time')). \ order_by('-date')[:31] log_date_list = [] for scene_log in scene_log_qs: log_date_list.append({ 'timestamp': CommonService.str_to_timestamp(scene_log['date'], '%Y-%m-%d'), 'count': scene_log['count'], 'format': scene_log['date'], }) return response.json(0, log_date_list) except Exception as e: return response.json(500, repr(e))