|
@@ -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
|
|
|
|
|
|
|
|
|
#
|