225 lines
6.9 KiB
Python
225 lines
6.9 KiB
Python
import sys
|
|
import json
|
|
import threading
|
|
|
|
from time import time, sleep
|
|
from datetime import datetime
|
|
from collections import deque
|
|
from copy import copy
|
|
from uuid import uuid4
|
|
|
|
from .task import Task
|
|
from .task_manager import TaskManager
|
|
from .instruction import Instruction
|
|
from biopro.device.manager import DeviceManager
|
|
from biopro.text import *
|
|
|
|
key_list = {
|
|
'deviceList': 'device',
|
|
}
|
|
|
|
class Project(threading.Thread):
|
|
def __init__(self, project, device_manager: DeviceManager, mqttThread = None, name="project"):
|
|
super(Project, self).__init__(name = name)
|
|
self._project = project
|
|
self._device_manager = device_manager
|
|
self._mqtt_thread = mqttThread
|
|
self._time_interval = 1
|
|
self._start_time = None
|
|
self._end_time = None
|
|
|
|
self._id = None
|
|
self._uuid = str(uuid4())
|
|
self._name = None
|
|
self._desc = None
|
|
self._device = None
|
|
self._complete_device = []
|
|
self._status = 0
|
|
|
|
self._instruction_set = Instruction()
|
|
self._stop_flag = False
|
|
|
|
self._task_manager = None
|
|
|
|
self.setup_project(project)
|
|
self.setup_device(self._device)
|
|
|
|
def setup_project(self, project):
|
|
for (key, value) in project.items():
|
|
if key in key_list.keys():
|
|
key = key_list[key]
|
|
|
|
if key == 'task':
|
|
self._task_manager = TaskManager(project['task'])
|
|
elif key == 'uuid':
|
|
pass
|
|
else:
|
|
setattr(self, key, value)
|
|
|
|
def setup_device(self, device_list):
|
|
for device in device_list:
|
|
complete_device = self._device_manager.get_device(device['connectDevice']['device_address'])
|
|
self._complete_device.append(complete_device)
|
|
|
|
@property
|
|
def id(self) -> int:
|
|
return self._id
|
|
|
|
@id.setter
|
|
def id(self, new_id):
|
|
self._id = new_id
|
|
|
|
@property
|
|
def uuid(self) -> str:
|
|
return self._uuid
|
|
|
|
@uuid.setter
|
|
def uuid(self, new_uuid):
|
|
self._uuid = new_uuid
|
|
|
|
@property
|
|
def name(self) -> str:
|
|
return self._name
|
|
|
|
@name.setter
|
|
def name(self, new_name):
|
|
self._name = new_name
|
|
|
|
@property
|
|
def desc(self) -> str:
|
|
return self._desc
|
|
|
|
@desc.setter
|
|
def desc(self, new_desc):
|
|
self._desc = new_desc
|
|
|
|
@property
|
|
def status(self) -> str:
|
|
return self._status
|
|
|
|
@status.setter
|
|
def status(self, new_status):
|
|
self._status = new_status
|
|
|
|
@property
|
|
def device(self) -> list:
|
|
return self._device
|
|
|
|
@device.setter
|
|
def device(self, new_device):
|
|
self._device = new_device
|
|
|
|
@property
|
|
def task_list(self):
|
|
return self._task_manager.export_task_list
|
|
|
|
@property
|
|
def mqtt_thread(self):
|
|
return self._mqtt_thread
|
|
|
|
def run(self):
|
|
self._status = 1
|
|
self._start_time = time()
|
|
self.mqtt_thread.broadcast_command('project:' + self._name + ' start at ' + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
|
|
|
|
while not self._stop_flag :
|
|
# check running task first
|
|
delay_time = 0
|
|
check_list = copy(self._task_manager.check_list)
|
|
|
|
for task in check_list:
|
|
if task != None:
|
|
now = time()
|
|
# print('round task', task.name)
|
|
# print('running task', self._task_manager.running_task.name, self._task_manager.running_task.status)
|
|
# if self._task_manager.prev_task != None:
|
|
# print('previous_task', self._task_manager.prev_task.name, self._task_manager.prev_task.status)
|
|
|
|
match_condition_list = task.check_condition(
|
|
project_start_time = self._start_time,
|
|
delay_time = delay_time,
|
|
running_task= self._task_manager.running_task,
|
|
previous_task = self._task_manager.prev_task
|
|
)
|
|
# print('match_condition_list', match_condition_list)
|
|
for condition in match_condition_list:
|
|
match_action_list = task.get_match_action(condition.id)
|
|
for action in match_action_list:
|
|
# print('match_action', action.type, action.target)
|
|
if action.type == 'start' and task.status != 1:
|
|
self._task_manager.set_running_task(task)
|
|
self.mqtt_thread.broadcast_command('project:task ' + task.name + ' start at ' + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
|
|
|
|
device = self._complete_device[action.target]
|
|
task_info = task.get_task_info(action)
|
|
instruction_set = getattr(self._instruction_set, action.type, None)
|
|
# print('instruction_set',instruction_set)
|
|
|
|
if instruction_set != None:
|
|
for instruction in instruction_set:
|
|
args = list(map(lambda arg: task_info[arg], instruction['arguments']))
|
|
threading.Thread(target=getattr(device, instruction['method'])(*args))
|
|
|
|
delay_time += (time() - now)
|
|
|
|
# check task not running then stop
|
|
if self.check_running_task_not_run() == True:
|
|
self.mqtt_thread.broadcast_command('project:task ' + str(self._task_manager.running_task.name) + ' stop at ' + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
|
|
self._task_manager.running_task.stop()
|
|
|
|
# check project done then close project
|
|
if self.check_project_done() == True:
|
|
print('project stop at', datetime.now())
|
|
self.close()
|
|
|
|
if self._time_interval - delay_time > 0:
|
|
sleep(self._time_interval - delay_time)
|
|
|
|
def pause(self):
|
|
# TODO
|
|
pass
|
|
|
|
def stop(self):
|
|
self._task_manager.running_task.stop()
|
|
self.mqtt_thread.broadcast_command('project:task ' + str(self._task_manager.running_task.name) + ' stop at ' + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
|
|
self._status = 2
|
|
self._end_time = time()
|
|
self._stop_flag = True
|
|
self.mqtt_thread.broadcast_command('project:project ' + str(self._name) + ' stop at ' + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
|
|
|
|
def close(self):
|
|
self._status = 2
|
|
self._end_time = time()
|
|
self._stop_flag = True
|
|
self.mqtt_thread.broadcast_command('project:project ' + str(self._name) + ' stop at ' + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
|
|
|
|
def check_project_done(self):
|
|
for task in self._task_manager.task_list:
|
|
# if task never start or still task is running then reject
|
|
if task.status == 1 or task.status == -1:
|
|
return False
|
|
return True
|
|
|
|
def check_running_task_not_run(self):
|
|
# if no running task
|
|
if self._task_manager.running_task == None:
|
|
return False
|
|
|
|
for device in self._task_manager.running_task.device:
|
|
if self._complete_device[device].status == 1:
|
|
return False
|
|
return True
|
|
|
|
def as_json(self):
|
|
data = {
|
|
'id': self._id,
|
|
'name': self._name,
|
|
'uuid': self._uuid,
|
|
'desc': self._desc,
|
|
'status': self._status,
|
|
'device': self._device,
|
|
'task': self.task_list,
|
|
'running_task': self._task_manager.running_task.as_json()
|
|
}
|
|
return data
|