浏览代码

修改场景数据结构

locky 1 年之前
父节点
当前提交
5baae1dc4b
共有 2 个文件被更改,包括 174 次插入50 次删除
  1. 173 49
      Controller/SensorGateway/SmartSceneController.py
  2. 1 1
      Model/models.py

+ 173 - 49
Controller/SensorGateway/SmartSceneController.py

@@ -374,11 +374,11 @@ class SmartSceneView(View):
                 msg['scene_id'] = smart_scene_qs.id
 
                 # 获取设备任务数据
-                msg['task'], mqtt_tasks = cls.get_msg_task_list(tasks_list, conditions_dict, tz, now_time)
+                msg['task'], scene_data = cls.get_task_list_and_scene_data(tasks_list, conditions_dict, tz, now_time)
 
                 smart_scene_qs.device_data = json.dumps(msg)
-                if mqtt_tasks:
-                    smart_scene_qs.mqtt_tasks = json.dumps(mqtt_tasks)
+                if scene_data:
+                    smart_scene_qs.scene_data = json.dumps(scene_data)
                 smart_scene_qs.save()
                 # 发布MQTT消息通知网关设备
                 thing_name = serial_number
@@ -520,7 +520,7 @@ class SmartSceneView(View):
             }
             # 查询序列号
             smart_scene_qs = SmartScene.objects.filter(id=smart_scene_id).\
-                values('device_id', 'sub_device_id', 'mqtt_tasks')
+                values('device_id', 'sub_device_id', 'scene_data')
             device_id = smart_scene_qs[0]['device_id']
             if device_id:
                 serial_number = Device_Info.objects.filter(id=device_id).values('serial_number')[0]['serial_number']
@@ -529,14 +529,22 @@ class SmartSceneView(View):
                 serial_number = GatewaySubDevice.objects.filter(id=sub_device_id).values('device__serial_number')[0][
                     'device__serial_number']
 
+            smart_scene_data = {
+                'is_enable': is_enable
+            }
             # 如果存在定时任务,暂停或恢复任务
-            mqtt_tasks = smart_scene_qs[0]['mqtt_tasks']
-            cls.pause_or_resume_job(scene_status, mqtt_tasks)
+            scene_data = smart_scene_qs[0]['scene_data']
+            if scene_data:
+                scene_data_dict = eval(scene_data)
+                new_scene_data_dict = cls.pause_or_resume_job(scene_data_dict, scene_status)
+                if new_scene_data_dict:
+                    new_scene_data = json.dumps(new_scene_data_dict)
+                    smart_scene_data['scene_data'] = new_scene_data
 
             topic_name = SMART_SCENE_TOPIC.format(serial_number)
 
             with transaction.atomic():
-                SmartScene.objects.filter(id=smart_scene_id).update(is_enable=is_enable)
+                SmartScene.objects.filter(id=smart_scene_id).update(**smart_scene_data)
                 # 通过mqtt发送设备数据
                 success = CommonService.req_publish_mqtt_msg(serial_number, topic_name, msg)
                 try:
@@ -636,8 +644,8 @@ class SmartSceneView(View):
                 return response.json(173)
 
             tz = smart_scene_qs[0].tz
-            mqtt_tasks = smart_scene_qs[0].mqtt_tasks
-            mqtt_tasks_list = eval(mqtt_tasks) if mqtt_tasks else None
+            scene_data = smart_scene_qs[0].scene_data
+            scene_data_dict = eval(scene_data) if scene_data else None
             scene_status = 1 if smart_scene_qs[0].is_enable else 0
             msg = {
                 'scene_id': smart_scene_id,
@@ -696,12 +704,13 @@ class SmartSceneView(View):
                 msg['sensor_ieee_addr'] = 'FFFFFFFFFFFFFFFF'
 
             # 获取设备任务数据
-            msg['task'], mqtt_tasks = cls.get_msg_task_list(tasks_list, conditions_dict, tz, now_time, mqtt_tasks_list)
-            if mqtt_tasks:
-                mqtt_tasks = json.dumps(mqtt_tasks)
+            msg['task'], scene_data = cls.get_task_list_and_scene_data(tasks_list, conditions_dict, tz, now_time,
+                                                                       scene_data_dict)
+            if scene_data:
+                scene_data = json.dumps(scene_data)
 
             with transaction.atomic():
-                smart_scene_qs.update(scene_name=scene_name, conditions=conditions, tasks=tasks, mqtt_tasks=mqtt_tasks,
+                smart_scene_qs.update(scene_name=scene_name, conditions=conditions, tasks=tasks, scene_data=scene_data,
                                       device_data=json.dumps(msg), updated_time=now_time, device_id=device_id,
                                       sub_device_id=sub_device_id)
 
@@ -1034,19 +1043,18 @@ class SmartSceneView(View):
             return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
 
     @classmethod
-    def get_msg_task_list(cls, tasks_list, conditions_dict, tz, now_time, mqtt_tasks_list=None):
+    def get_task_list_and_scene_data(cls, tasks_list, conditions_dict, tz, now_time, scene_data_dict=None):
         """
-        获取设备任务数据
+        获取设备任务数据和场景数据
         @param tasks_list: app任务列表
         @param conditions_dict: 条件
         @param tz: 时区
         @param now_time: 当前时间
-        @param mqtt_tasks_list: mqtt定时任务时列表
-        @return: task_list, mqtt_task_list
+        @param scene_data_dict: 场景数据
+        @return: task_list, scene_data
         """
-        # 传入任务列表,删除旧任务
-        if mqtt_tasks_list is not None:
-            cls.del_aps_job(mqtt_tasks_list)
+        # 删除旧的定时任务
+        cls.del_aps_job(scene_data_dict)
         task_list = []
         mqtt_task_list = []
         for task in tasks_list:
@@ -1099,10 +1107,61 @@ class SmartSceneView(View):
                         task_temp['duration'] = task.get('duration')
                         task_temp['value_type'] = task.get('value_type')
                 task_list.append(task_temp)
-        # 列表为空保存为空字符串
-        if not mqtt_task_list:
-            mqtt_task_list = ''
-        return task_list, mqtt_task_list
+
+        # mqtt_task_list不为空,组织完整场景数据
+        scene_data = ''
+        if mqtt_task_list:
+            scene_data = {
+                'condition': cls.get_condition(conditions_dict, now_time, tz),
+                'task_list': mqtt_task_list
+            }
+
+        return task_list, scene_data
+
+    @classmethod
+    def get_condition(cls, conditions_dict, now_time, tz):
+        """
+        获取场景条件
+        @param conditions_dict: 条件数据
+        @param now_time: 当前时间
+        @param tz: 时区
+        @return: condition
+        """
+        condition = {}
+        # 条件为设置时间
+        if conditions_dict['type'] == 1:
+            minutes = conditions_dict['time']['minutes']
+            hour, minute = divmod(minutes, 60)
+            repeat = conditions_dict['time']['repeat']
+
+            # 一次性任务
+            if repeat == 0:
+                condition['time'] = 'date'
+                # 根据时间戳和时区获取年月日,拼接由分钟转换出来的时间
+                time_string = CommonService.get_date_from_timestamp(now_time, tz)
+                time_string += ' {:02d}:{:02d}:00'.format(hour, minute)
+                time_stamp = CommonService.convert_to_timestamp(tz, time_string)
+                time_dict = {
+                    'time_stamp': time_stamp
+                }
+                condition['time_dict'] = time_dict
+            else:
+                condition['time'] = 'cron'
+                weeks = cls.int_to_weeks(repeat)
+                time_dict = {
+                    'weeks': weeks,
+                    'hour': hour,
+                    'minute': minute
+                }
+                condition['time_dict'] = time_dict
+        else:
+            device_type = conditions_dict['sensor']['device_type']
+            event_type = conditions_dict['sensor']['eventValues']['event_type']
+            condition['event_type'] = event_type
+            # 温湿度传感器,取值
+            if device_type == SENSOR_TYPE['tem_hum_sensor']:
+                condition['value'] = event_type = conditions_dict['sensor']['eventValues']['value']
+        return condition
 
     @staticmethod
     def time_conflict(sub_device_id, conditions, is_all_day, request_dict, smart_scene_id=None):
@@ -1233,7 +1292,7 @@ class SmartSceneView(View):
         return hour, minute, second, is_next_day
 
     @staticmethod
-    def int_to_weeks(repeat, is_next_day):
+    def int_to_weeks(repeat, is_next_day=False):
         """
         十进制转星期周期
         @param repeat: 星期周期的十进制数,如127 -> 0,1,2,3,4,5,6
@@ -1270,39 +1329,104 @@ class SmartSceneView(View):
             CommonService.req_publish_mqtt_msg(serial_number, topic_name, msg)
 
     @staticmethod
-    def del_aps_job(mqtt_tasks_list):
+    def del_aps_job(scene_data_dict):
         """
         删除定时任务
-        @param mqtt_tasks_list: mqtt任务列表
+        @param scene_data_dict: 场景数据
         @return:
         """
-        apscheduler_obj = ApschedulerObject()
-        for mqtt_task in mqtt_tasks_list:
-            task_id = mqtt_task.get('task_id')
-            if not task_id:
-                # 如果task_id不存在,则跳过该任务
-                continue
-            apscheduler_obj.del_job(task_id)
+        if scene_data_dict is not None:
+            if scene_data_dict['condition'].get('time'):
+                apscheduler_obj = ApschedulerObject()
+                time_task_list = scene_data_dict['task_list']
+                for time_task in time_task_list:
+                    # 存在任务则删除
+                    task_id = time_task.get('task_id')
+                    if task_id:
+                        apscheduler_obj.del_job(task_id)
 
-    @staticmethod
-    def pause_or_resume_job(scene_status, mqtt_tasks):
+    @classmethod
+    def pause_or_resume_job(cls, scene_data_dict, scene_status):
         """
         暂停或恢复定时任务
-        @param scene_status: 场景状态
-        @param mqtt_tasks: mqtt任务列表
+        @param scene_data_dict: 场景数据
+        @param scene_status: 场景状态: SCENE_STATUS_ON, SCENE_STATUS_OFF
+        @return: None or scene_data_dict
+        """
+        # 判断条件是否为设置时间
+        time_type = scene_data_dict['condition'].get('time')
+        if time_type:
+            time_task_list = scene_data_dict['task_list']
+            apscheduler_obj = ApschedulerObject()
+            # 关闭: 暂停任务, 打开: 恢复任务
+            if scene_status == SCENE_STATUS_OFF:
+                cls.pause_job(apscheduler_obj, time_task_list)
+            else:
+                time_stamp, task_list = cls.resume_job(apscheduler_obj, time_type, time_task_list)
+                if time_stamp and time_task_list:
+                    scene_data_dict['condition']['time_dict']['time_stamp'] = time_stamp
+                    scene_data_dict['condition']['task_list'] = task_list
+                    return scene_data_dict
+
+    @staticmethod
+    def pause_job(apscheduler_obj, time_task_list):
+        """
+        暂停定时任务
+        @param apscheduler_obj: apscheduler对象
+        @param time_task_list: 定时任务列表
         @return:
         """
-        if not mqtt_tasks:
-            return
-        apscheduler_obj = ApschedulerObject()
-        job_func = apscheduler_obj.resume_job if scene_status else apscheduler_obj.pause_job
-        mqtt_tasks_list = eval(mqtt_tasks)
-        for mqtt_task in mqtt_tasks_list:
-            task_id = mqtt_task.get('task_id')
-            if not task_id:
-                # 如果task_id不存在,则跳过该任务
-                continue
-            job_func(task_id)
+        for time_task in time_task_list:
+            task_id = time_task.get('task_id')
+            if task_id:
+                try:
+                    apscheduler_obj.pause_job(task_id)
+                except Exception:
+                    continue
+
+    @classmethod
+    def resume_job(cls, apscheduler_obj, time_type, time_task_list):
+        """
+        恢复定时任务
+        @param apscheduler_obj: apscheduler对象
+        @param time_type: 时间类型: date, cron
+        @param time_task_list: 定时任务列表
+        @return: None, None or time_stamp, time_task_list
+        """
+        if time_type == 'cron':
+            for time_task in time_task_list:
+                task_id = time_task.get('task_id')
+                if task_id:
+                    try:
+                        apscheduler_obj.resume_job(task_id)
+                    except Exception:
+                        continue
+            return None, None
+        else:
+            now_time = int(time.time())
+            time_stamp = time_task_list[0]['time_dict']['time_stamp']
+            if time_stamp > now_time:
+                for time_task in time_task_list:
+                    task_id = time_task.get('task_id')
+                    if task_id:
+                        try:
+                            apscheduler_obj.resume_job(task_id)
+                        except Exception:
+                            continue
+                return None, None
+            else:
+                # 创建新的定时任务,时间+24小时
+                time_stamp += 24 * 60 * 60
+                for time_task in time_task_list:
+                    device_type = time_task['device_type']
+                    event_type = time_task['event_type']
+                    serial_number = time_task['serial_number']
+                    task_id = serial_number + str(time_stamp)
+                    apscheduler_obj.create_date_job(func=cls.pub_mqtt, task_id=task_id, time_stamp=time_stamp,
+                                                    args=(device_type, event_type, serial_number))
+                    # 更新task_id
+                    time_task[task_id] = task_id
+                return time_stamp, time_task_list
 
 
 #

+ 1 - 1
Model/models.py

@@ -3196,7 +3196,7 @@ class SmartScene(models.Model):
     is_enable = models.BooleanField(default=True, verbose_name=u'是否开启')
     device_data = models.TextField(default='', verbose_name=u'设备场景数据')
     tz = models.FloatField(default=0, verbose_name='时区')
-    mqtt_tasks = models.TextField(default='', verbose_name='mqtt任务')
+    scene_data = models.TextField(default='', verbose_name='场景数据')
     created_time = models.IntegerField(default=0, verbose_name='创建时间')
     updated_time = models.IntegerField(default=0, verbose_name='更新时间')