Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2edf28c7ba | |||
| 5531dcc0f0 | |||
| b20d46daa8 | |||
| c0bb567bf7 |
@@ -87,7 +87,8 @@ class DataAPI(metaclass=abc.ABCMeta):
|
|||||||
def update_device_configuration(self,
|
def update_device_configuration(self,
|
||||||
device: Union[int, Device],
|
device: Union[int, Device],
|
||||||
meta_file: Union[str, Path, RecordingMetaFile],
|
meta_file: Union[str, Path, RecordingMetaFile],
|
||||||
data_format: Union[AnyStr, DataDecodeFormat]):
|
data_format: Union[AnyStr, DataDecodeFormat],
|
||||||
|
project_info: str):
|
||||||
"""set device configuration.
|
"""set device configuration.
|
||||||
|
|
||||||
:param device: device ID
|
:param device: device ID
|
||||||
@@ -154,7 +155,8 @@ class DataClient(SocketClient, DataAPI, metaclass=SocketClientMacro(DataAPI)):
|
|||||||
def update_device_configuration(self,
|
def update_device_configuration(self,
|
||||||
device: Union[int, Device],
|
device: Union[int, Device],
|
||||||
meta_file: Union[str, Path, RecordingMetaFile],
|
meta_file: Union[str, Path, RecordingMetaFile],
|
||||||
data_format: Union[AnyStr, DataDecodeFormat]):
|
data_format: Union[AnyStr, DataDecodeFormat],
|
||||||
|
project_info: str):
|
||||||
|
|
||||||
# meta file
|
# meta file
|
||||||
if isinstance(meta_file, str):
|
if isinstance(meta_file, str):
|
||||||
@@ -186,7 +188,7 @@ class DataClient(SocketClient, DataAPI, metaclass=SocketClientMacro(DataAPI)):
|
|||||||
raise TypeError('not a data decode format : ' + data_format.__class__.__name__)
|
raise TypeError('not a data decode format : ' + data_format.__class__.__name__)
|
||||||
|
|
||||||
# send
|
# send
|
||||||
self.send_command('update_device_configuration', device, meta_file, data_format)
|
self.send_command('update_device_configuration', device, meta_file, data_format, project_info)
|
||||||
|
|
||||||
def is_sync(self, device: Union[None, int, Device] = None) -> bool:
|
def is_sync(self, device: Union[None, int, Device] = None) -> bool:
|
||||||
if isinstance(device, Device):
|
if isinstance(device, Device):
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
from sqlalchemy import create_engine
|
||||||
|
# from sqlalchemy.ext.declarative import declarative_base
|
||||||
|
from sqlalchemy.orm import sessionmaker, declarative_base
|
||||||
|
|
||||||
|
SQLALCHEMY_DATABASE_URL = "postgresql://biopro:BioProControlBox@127.0.0.1:5432/postgres"
|
||||||
|
|
||||||
|
engine = create_engine(SQLALCHEMY_DATABASE_URL)
|
||||||
|
Session = sessionmaker(bind=engine)
|
||||||
|
|
||||||
|
Base = declarative_base()
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
from sqlalchemy import Table, Column, String, MetaData, ForeignKey, JSON
|
||||||
|
from sqlalchemy.sql import select, func
|
||||||
|
from sqlalchemy.types import Integer, BigInteger, String, Boolean, TIMESTAMP, Numeric
|
||||||
|
from sqlalchemy.dialects.postgresql import JSONB
|
||||||
|
|
||||||
|
from .base import Base
|
||||||
|
|
||||||
|
class MetaProjectInfo(Base):
|
||||||
|
__tablename__ = "meta_project_info"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
project = Column(String(36))
|
||||||
|
cycle = Column(String)
|
||||||
|
task = Column(JSONB)
|
||||||
|
serial_number = Column(Integer)
|
||||||
|
deleted = Column(Boolean, default = False)
|
||||||
|
created_at = Column(TIMESTAMP(timezone=True), server_default=func.now())
|
||||||
|
updated_at = Column(TIMESTAMP(timezone=True), onupdate=func.now())
|
||||||
|
|
||||||
|
# def __repr__(self):
|
||||||
|
# return f"User(id={self.id!r}, name={self.name!r}, fullname={self.task!r})"
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
from sqlalchemy import Table, Column, String, MetaData, ForeignKey, JSON
|
||||||
|
from sqlalchemy.sql import select, func
|
||||||
|
from sqlalchemy.types import Integer, BigInteger, String, Boolean, TIMESTAMP, Numeric
|
||||||
|
from sqlalchemy.dialects.postgresql import JSONB
|
||||||
|
|
||||||
|
from .base import Base
|
||||||
|
|
||||||
|
class ProjectReport(Base):
|
||||||
|
__tablename__ = "project_report"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
name = Column(String)
|
||||||
|
desc = Column(String)
|
||||||
|
task = Column(JSONB)
|
||||||
|
cycle = Column(JSONB)
|
||||||
|
device = Column(JSONB)
|
||||||
|
uuid = Column(String(36))
|
||||||
|
user_auth = Column(JSONB)
|
||||||
|
deleted = Column(Boolean, default = False)
|
||||||
|
created_at = Column(TIMESTAMP(timezone=True), server_default=func.now())
|
||||||
|
updated_at = Column(TIMESTAMP(timezone=True), onupdate=func.now())
|
||||||
|
|
||||||
|
# def __repr__(self):
|
||||||
|
# return f"User(id={self.id!r}, name={self.name!r}, fullname={self.task!r})"
|
||||||
@@ -574,20 +574,23 @@ class DeviceManager(MasterDevice, Synchronized):
|
|||||||
:param device: device ID or response info
|
:param device: device ID or response info
|
||||||
:return: CompletedDevice, None if not found.
|
:return: CompletedDevice, None if not found.
|
||||||
"""
|
"""
|
||||||
if isinstance(device, int):
|
try:
|
||||||
for slave in self._device:
|
if isinstance(device, int):
|
||||||
if slave.device_id == device:
|
for slave in self._device:
|
||||||
return slave
|
if slave.device_id == device:
|
||||||
|
return slave
|
||||||
|
|
||||||
elif isinstance(device, str):
|
elif isinstance(device, str):
|
||||||
for slave in self._device:
|
for slave in self._device:
|
||||||
if ':'.join('{:02x}'.format(b) for b in slave.mac_address) == device.lower():
|
if ':'.join('{:02x}'.format(b) for b in slave.mac_address) == device.lower():
|
||||||
return slave
|
return slave
|
||||||
|
|
||||||
elif isinstance(device, DeviceInfo):
|
elif isinstance(device, DeviceInfo):
|
||||||
for slave in self._device:
|
for slave in self._device:
|
||||||
if device.match(slave):
|
if device.match(slave):
|
||||||
return slave
|
return slave
|
||||||
|
except BaseException as e:
|
||||||
|
self.log_error('device not found', str(device))
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
@@ -738,7 +738,7 @@ class DeviceCommonInstruction:
|
|||||||
elif instruction == cls.START:
|
elif instruction == cls.START:
|
||||||
return '_data_format("TDC4VAF2")', '_notify(True)', 'VIS_STI', '_sync(True)'
|
return '_data_format("TDC4VAF2")', '_notify(True)', 'VIS_STI', '_sync(True)'
|
||||||
elif instruction == cls.INTERRUPT:
|
elif instruction == cls.INTERRUPT:
|
||||||
return '_sync(False)', '_notify(False)', 'VIS_INT'
|
return '_notify(False)', 'VIS_INT', '_sync(False)'
|
||||||
elif instruction == cls.CLOSE:
|
elif instruction == cls.CLOSE:
|
||||||
return '_sync(False)', '_notify(False)', 'VIS_INT'
|
return '_sync(False)', '_notify(False)', 'VIS_INT'
|
||||||
elif instruction == cls.CALL:
|
elif instruction == cls.CALL:
|
||||||
|
|||||||
@@ -968,7 +968,7 @@ class CompletedDevice(Device):
|
|||||||
"""
|
"""
|
||||||
__slots__ = ('_master', '_device_id', '_device', '_library', '_context',
|
__slots__ = ('_master', '_device_id', '_device', '_library', '_context',
|
||||||
'_parameter', '_configuration', '_lock', '_feature_mask',
|
'_parameter', '_configuration', '_lock', '_feature_mask',
|
||||||
'_cache_battery', '_cache_battery_timestamp', '_coeff', '_status')
|
'_cache_battery', '_cache_battery_timestamp', '_coeff', '_status', '_occupied_by_project')
|
||||||
|
|
||||||
def __init__(self, master: MasterDevice, library: DeviceLibrary, device_id: int, device: Device):
|
def __init__(self, master: MasterDevice, library: DeviceLibrary, device_id: int, device: Device):
|
||||||
"""
|
"""
|
||||||
@@ -986,6 +986,8 @@ class CompletedDevice(Device):
|
|||||||
|
|
||||||
# device status ( 0: idle, 1: working, 2: error, 3: power off)
|
# device status ( 0: idle, 1: working, 2: error, 3: power off)
|
||||||
self._status = 0
|
self._status = 0
|
||||||
|
# device be occupied by project
|
||||||
|
self._occupied_by_project = None
|
||||||
|
|
||||||
# context
|
# context
|
||||||
s1 = library.constant
|
s1 = library.constant
|
||||||
@@ -1082,6 +1084,14 @@ class CompletedDevice(Device):
|
|||||||
def status(self, new_status):
|
def status(self, new_status):
|
||||||
self._status = new_status
|
self._status = new_status
|
||||||
|
|
||||||
|
@property
|
||||||
|
def occupied_by_project(self) -> str:
|
||||||
|
return self._occupied_by_project
|
||||||
|
|
||||||
|
@occupied_by_project.setter
|
||||||
|
def occupied_by_project(self, new_occupied_by_project):
|
||||||
|
self._occupied_by_project = new_occupied_by_project
|
||||||
|
|
||||||
# device parameter getter/setter
|
# device parameter getter/setter
|
||||||
|
|
||||||
def parameters(self) -> List[str]:
|
def parameters(self) -> List[str]:
|
||||||
@@ -1303,6 +1313,7 @@ class CompletedDevice(Device):
|
|||||||
'recording_file_name': self.recording_file_name,
|
'recording_file_name': self.recording_file_name,
|
||||||
'library_name': self._library.name,
|
'library_name': self._library.name,
|
||||||
'library_version': str(self._library.version),
|
'library_version': str(self._library.version),
|
||||||
|
'occupied_by_project': self._occupied_by_project,
|
||||||
'configuration': self.configuration.as_json(list_hide=True),
|
'configuration': self.configuration.as_json(list_hide=True),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ class Project(threading.Thread):
|
|||||||
for device in device_list:
|
for device in device_list:
|
||||||
mac_address = device_list[device]['pair']
|
mac_address = device_list[device]['pair']
|
||||||
complete_device = self._device_manager.get_device(mac_address)
|
complete_device = self._device_manager.get_device(mac_address)
|
||||||
|
complete_device.occupied_by_project = self._uuid
|
||||||
self._complete_device[device] = complete_device
|
self._complete_device[device] = complete_device
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -136,6 +137,10 @@ class Project(threading.Thread):
|
|||||||
def running_task(self):
|
def running_task(self):
|
||||||
return self._task_manager.running_task
|
return self._task_manager.running_task
|
||||||
|
|
||||||
|
def get_device_parameter_set(self, device_address):
|
||||||
|
parameter_set = self._task_manager.running_task.parameter_set
|
||||||
|
return next((x for x in parameter_set if parameter_set[x]['target'] == device_address), None)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self._status = 1
|
self._status = 1
|
||||||
self._start_time = time()
|
self._start_time = time()
|
||||||
@@ -161,6 +166,7 @@ class Project(threading.Thread):
|
|||||||
|
|
||||||
for condition in match_condition_list:
|
for condition in match_condition_list:
|
||||||
match_action_list = task.get_match_action(condition.id)
|
match_action_list = task.get_match_action(condition.id)
|
||||||
|
print('match_action_list', match_action_list, match_action_list)
|
||||||
for action in match_action_list:
|
for action in match_action_list:
|
||||||
if action.type == 'cycle' and condition.type == 'previous_task_done':
|
if action.type == 'cycle' and condition.type == 'previous_task_done':
|
||||||
self.mqtt_thread.broadcast_command('project:task ' + task.name + ' start at ' + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
|
self.mqtt_thread.broadcast_command('project:task ' + task.name + ' start at ' + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
|
||||||
@@ -184,6 +190,8 @@ class Project(threading.Thread):
|
|||||||
|
|
||||||
elif action.type == 'idle':
|
elif action.type == 'idle':
|
||||||
self._task_manager.running_task.stop()
|
self._task_manager.running_task.stop()
|
||||||
|
# elif action.type == 'stop':
|
||||||
|
# self._task_manager.running_task.stop()
|
||||||
|
|
||||||
instruction_set = None
|
instruction_set = None
|
||||||
|
|
||||||
@@ -223,7 +231,7 @@ class Project(threading.Thread):
|
|||||||
task_info['file_name'] += '#' + str(cycle_info['name']) + '-' + str(cycle_info['count'])
|
task_info['file_name'] += '#' + str(cycle_info['name']) + '-' + str(cycle_info['count'])
|
||||||
self.log_verbose('file name ' + task_info['file_name'])
|
self.log_verbose('file name ' + task_info['file_name'])
|
||||||
|
|
||||||
if instruction_set != None and len(task.parameter_set) > 0:
|
if instruction_set != None and self.get_device_parameter_set(action.target) != None:
|
||||||
if action.type == 'start':
|
if action.type == 'start':
|
||||||
self._count += 1
|
self._count += 1
|
||||||
for instruction in instruction_set:
|
for instruction in instruction_set:
|
||||||
@@ -253,6 +261,8 @@ class Project(threading.Thread):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
|
for device in self._complete_device:
|
||||||
|
self._complete_device[device].occupied_by_project = None
|
||||||
self._task_manager.running_task.stop()
|
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.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._status = 2
|
||||||
@@ -261,6 +271,8 @@ class Project(threading.Thread):
|
|||||||
self.mqtt_thread.broadcast_command('project:project ' + str(self._name) + ' stop at ' + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
|
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):
|
def close(self):
|
||||||
|
for device in self._complete_device:
|
||||||
|
self._complete_device[device].occupied_by_project = None
|
||||||
self._status = 2
|
self._status = 2
|
||||||
self._end_time = time()
|
self._end_time = time()
|
||||||
self._stop_flag = True
|
self._stop_flag = True
|
||||||
@@ -319,6 +331,18 @@ class Project(threading.Thread):
|
|||||||
'device': self._device,
|
'device': self._device,
|
||||||
'task': self.task_list,
|
'task': self.task_list,
|
||||||
'running_task': running_task,
|
'running_task': running_task,
|
||||||
'cycle': self._cycle
|
'cycle': self._cycle,
|
||||||
|
'count': self._count,
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
|
||||||
|
def info_pass_data_server(self):
|
||||||
|
if self._task_manager.running_task is not None:
|
||||||
|
running_task = self._task_manager.running_task.as_json()
|
||||||
|
data = {
|
||||||
|
'project': self._uuid,
|
||||||
|
'task': running_task,
|
||||||
|
'cycle': self._cycle,
|
||||||
|
'serial_number': self._count,
|
||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ class RecordingMetaFile(JsonSerialize):
|
|||||||
'_dirty', '_last_modify_time', '_file_size_cache',
|
'_dirty', '_last_modify_time', '_file_size_cache',
|
||||||
'_recording_file_ch', '_recording_sub_file', '_size',
|
'_recording_file_ch', '_recording_sub_file', '_size',
|
||||||
'_parameter', '_parent', '_recording_file_name', '_recording_sub_mini', '_recording_mini_ch',
|
'_parameter', '_parent', '_recording_file_name', '_recording_sub_mini', '_recording_mini_ch',
|
||||||
'_raw_serial_number', '_mini_serial_number', '_device_id')
|
'_raw_serial_number', '_mini_serial_number', '_device_id', '_project_id')
|
||||||
|
|
||||||
def __init__(self, filepath: Union[str, Path], data_format: bytes = None, id_db = 0, database = None):
|
def __init__(self, filepath: Union[str, Path], data_format: bytes = None, id_db = 0, database = None):
|
||||||
if isinstance(filepath, str):
|
if isinstance(filepath, str):
|
||||||
@@ -153,6 +153,7 @@ class RecordingMetaFile(JsonSerialize):
|
|||||||
self._parent = ''
|
self._parent = ''
|
||||||
self._recording_file_name = ''
|
self._recording_file_name = ''
|
||||||
self._device_id = -1
|
self._device_id = -1
|
||||||
|
self._project_id = None
|
||||||
|
|
||||||
# recording parameter
|
# recording parameter
|
||||||
self._configuration = None
|
self._configuration = None
|
||||||
@@ -297,6 +298,7 @@ class RecordingMetaFile(JsonSerialize):
|
|||||||
'uuid': str(self._file_uuid),
|
'uuid': str(self._file_uuid),
|
||||||
'data_format': 'rec',
|
'data_format': 'rec',
|
||||||
'device': self._device,
|
'device': self._device,
|
||||||
|
'project': self._project_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(self._parent) > 0:
|
if len(self._parent) > 0:
|
||||||
@@ -462,7 +464,7 @@ class RecordingMetaFile(JsonSerialize):
|
|||||||
def parameter(self) -> str:
|
def parameter(self) -> str:
|
||||||
return self._parameter
|
return self._parameter
|
||||||
|
|
||||||
@device.setter
|
@parameter.setter
|
||||||
def parameter(self, parameter):
|
def parameter(self, parameter):
|
||||||
self._parameter = parameter
|
self._parameter = parameter
|
||||||
return None
|
return None
|
||||||
@@ -471,7 +473,7 @@ class RecordingMetaFile(JsonSerialize):
|
|||||||
def parent(self) -> str:
|
def parent(self) -> str:
|
||||||
return self._parent
|
return self._parent
|
||||||
|
|
||||||
@device.setter
|
@parent.setter
|
||||||
def parent(self, parent):
|
def parent(self, parent):
|
||||||
self._parent = parent
|
self._parent = parent
|
||||||
|
|
||||||
@@ -479,7 +481,7 @@ class RecordingMetaFile(JsonSerialize):
|
|||||||
def recording_file_name(self) -> str:
|
def recording_file_name(self) -> str:
|
||||||
return self._recording_file_name
|
return self._recording_file_name
|
||||||
|
|
||||||
@device.setter
|
@recording_file_name.setter
|
||||||
def recording_file_name(self, recording_file_name):
|
def recording_file_name(self, recording_file_name):
|
||||||
self._recording_file_name = recording_file_name
|
self._recording_file_name = recording_file_name
|
||||||
|
|
||||||
@@ -492,6 +494,15 @@ class RecordingMetaFile(JsonSerialize):
|
|||||||
self._configuration = conf
|
self._configuration = conf
|
||||||
self._dirty = True
|
self._dirty = True
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def project_id(self) -> int:
|
||||||
|
return self._project_id
|
||||||
|
|
||||||
|
@project_id.setter
|
||||||
|
def project_id(self, project: int):
|
||||||
|
self._project_id = project
|
||||||
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def channels(self) -> List[int]:
|
def channels(self) -> List[int]:
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ from time import time, sleep
|
|||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import gc
|
import gc
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
|
|
||||||
from biopro.data import *
|
from biopro.data import *
|
||||||
@@ -27,7 +26,6 @@ from .mqtt import MqttDataMessageHandler, MqttThread
|
|||||||
from .database import DataBaseProcess
|
from .database import DataBaseProcess
|
||||||
from .recording import RecordingProcess
|
from .recording import RecordingProcess
|
||||||
from multiprocessing import Queue
|
from multiprocessing import Queue
|
||||||
import queue
|
|
||||||
|
|
||||||
from json import loads as json_parse, dumps as _json_stringify
|
from json import loads as json_parse, dumps as _json_stringify
|
||||||
import json
|
import json
|
||||||
@@ -317,7 +315,8 @@ class DataServer(SocketServer, DataAPI):
|
|||||||
def update_device_configuration(self,
|
def update_device_configuration(self,
|
||||||
device: str,
|
device: str,
|
||||||
meta_file: Union[str, Path, RecordingMetaFile],
|
meta_file: Union[str, Path, RecordingMetaFile],
|
||||||
data_format: Union[AnyStr, DataDecodeFormat]):
|
data_format: Union[AnyStr, DataDecodeFormat],
|
||||||
|
project_info: str):
|
||||||
# meta file
|
# meta file
|
||||||
|
|
||||||
device_id = -1
|
device_id = -1
|
||||||
@@ -345,6 +344,8 @@ class DataServer(SocketServer, DataAPI):
|
|||||||
_parent = json_stringify(_device['parent'])
|
_parent = json_stringify(_device['parent'])
|
||||||
_recording_file_name = _device['recording_file_name']
|
_recording_file_name = _device['recording_file_name']
|
||||||
mac_address = json.loads(device)['device_address']
|
mac_address = json.loads(device)['device_address']
|
||||||
|
device_id = _device['device_id']
|
||||||
|
|
||||||
del _device['configuration']
|
del _device['configuration']
|
||||||
del _device['parent']
|
del _device['parent']
|
||||||
del _device['recording_file_name']
|
del _device['recording_file_name']
|
||||||
@@ -354,13 +355,22 @@ class DataServer(SocketServer, DataAPI):
|
|||||||
# meta_file.parameter = _parameter
|
# meta_file.parameter = _parameter
|
||||||
# meta_file.parent = _parent
|
# meta_file.parent = _parent
|
||||||
# meta_file.recording_file_name = _recording_file_name
|
# meta_file.recording_file_name = _recording_file_name
|
||||||
device_id = int(json.loads(device)['device_id'])
|
|
||||||
|
|
||||||
if device_id < 0:
|
if device_id < 0:
|
||||||
raise ValueError('illegal device ID : ' + str(device_id))
|
raise ValueError('illegal device ID : ' + str(device_id))
|
||||||
|
|
||||||
self.log_verbose('device ID', device_id)
|
self.log_verbose('device ID', device_id)
|
||||||
|
|
||||||
|
# project binding meta file
|
||||||
|
project_id = None
|
||||||
|
_project = None
|
||||||
|
if project_info != None:
|
||||||
|
_project = json.loads(project_info)
|
||||||
|
self.database_process.put_queue(['project_insert', device_id, _project])
|
||||||
|
result = self._queue_ds_dict[int(device_id)].get()
|
||||||
|
if result[0] == 'project_id':
|
||||||
|
project_id = result[1]
|
||||||
|
|
||||||
# while len(self._configurations) <= device_id:
|
# while len(self._configurations) <= device_id:
|
||||||
# self._configurationsappend(None)
|
# self._configurationsappend(None)
|
||||||
|
|
||||||
@@ -380,8 +390,6 @@ class DataServer(SocketServer, DataAPI):
|
|||||||
else:
|
else:
|
||||||
data_format = data_format.name
|
data_format = data_format.name
|
||||||
|
|
||||||
# self.log_verbose('device data format', data_format)
|
|
||||||
|
|
||||||
self.log_verbose('device meta file', meta_file)
|
self.log_verbose('device meta file', meta_file)
|
||||||
|
|
||||||
# data runtime
|
# data runtime
|
||||||
@@ -406,15 +414,15 @@ class DataServer(SocketServer, DataAPI):
|
|||||||
c.shutdown()
|
c.shutdown()
|
||||||
c.join()
|
c.join()
|
||||||
self._spi.set_wait_flag(c._device, True)
|
self._spi.set_wait_flag(c._device, True)
|
||||||
|
|
||||||
data_runtime_process = RecordingProcess('data_server', self.log_verbose, device_id,
|
data_runtime_process = RecordingProcess('data_server', self.log_verbose, device_id,
|
||||||
Queue(), self._queue_ds_dict[int(device_id)], self._queue_msg, meta_file,
|
Queue(), self._queue_ds_dict[int(device_id)], self._queue_msg, meta_file,
|
||||||
json_stringify(_device), _parameter, _parent, _recording_file_name,
|
json_stringify(_device), _parameter, _parent, _recording_file_name,
|
||||||
data_format, self.socket_mqtt_ip, self.socket_mqtt_port,
|
data_format, self.socket_mqtt_ip, self.socket_mqtt_port,
|
||||||
database = self.database_process )
|
project_id = project_id,
|
||||||
# data_runtime_process.start()
|
database = self.database_process)
|
||||||
|
|
||||||
# check channel
|
# check channel
|
||||||
|
|
||||||
if isinstance(data_runtime_process, RecordingProcess) and device_id not in self._available_channel:
|
if isinstance(data_runtime_process, RecordingProcess) and device_id not in self._available_channel:
|
||||||
raise RuntimeError('set device configuration on un-available channel', device_id)
|
raise RuntimeError('set device configuration on un-available channel', device_id)
|
||||||
|
|
||||||
|
|||||||
@@ -550,4 +550,33 @@ class DataBaseProcess(Process):
|
|||||||
except psycopg2.Error as e:
|
except psycopg2.Error as e:
|
||||||
print('e', e)
|
print('e', e)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def project_insert(self, device_id, _data):
|
||||||
|
sql_str = 'INSERT INTO "public"."meta_project_info" ('
|
||||||
|
sql_set = []
|
||||||
|
for item in _data.keys():
|
||||||
|
sql_str = sql_str + str(item) + ', '
|
||||||
|
if isinstance(_data[item], dict) or isinstance(_data[item], list):
|
||||||
|
sql_set.append(json_stringify(_data[item]))
|
||||||
|
else:
|
||||||
|
sql_set.append(_data[item])
|
||||||
|
|
||||||
|
sql_str = sql_str[0:-2] + ') VALUES ('
|
||||||
|
for item in _data.keys():
|
||||||
|
sql_str = sql_str + '%s, '
|
||||||
|
|
||||||
|
sql_str = sql_str[0:-2] + ') RETURNING id'
|
||||||
|
sql_cursor = self._psql_conn.cursor()
|
||||||
|
|
||||||
|
try:
|
||||||
|
sql_cursor.execute(sql_str, sql_set)
|
||||||
|
except BaseException as e:
|
||||||
|
print('insert error', e)
|
||||||
|
self._psql_conn.commit()
|
||||||
|
sql_cursor.close()
|
||||||
|
self._queue_error.put()
|
||||||
|
finally:
|
||||||
|
self._queue_ds[int(device_id)].put(['project_id', int(sql_cursor.fetchone()[0])])
|
||||||
|
self._psql_conn.commit()
|
||||||
|
sql_cursor.close()
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from time import sleep
|
from time import sleep
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
import json
|
||||||
|
|
||||||
import biopro.impl.vcgencmd as vcg
|
import biopro.impl.vcgencmd as vcg
|
||||||
from biopro.data import DataServerOptions, DataAPI
|
from biopro.data import DataServerOptions, DataAPI
|
||||||
@@ -31,8 +32,10 @@ from biopro.api.auth import AuthAPI
|
|||||||
from biopro.api.controller import ControllerAPI
|
from biopro.api.controller import ControllerAPI
|
||||||
from biopro.api.device import DeviceAPI
|
from biopro.api.device import DeviceAPI
|
||||||
from biopro.project.project_manager import ProjectManager
|
from biopro.project.project_manager import ProjectManager
|
||||||
### do not import Websocket mode
|
from biopro.db.base import Base, Session, engine
|
||||||
###from .websocket import WebsocketThread
|
from biopro.db.project_report import ProjectReport
|
||||||
|
from biopro.db.meta_project_info import MetaProjectInfo
|
||||||
|
|
||||||
|
|
||||||
_RUNTIME_COMPILE = False
|
_RUNTIME_COMPILE = False
|
||||||
|
|
||||||
@@ -117,8 +120,8 @@ class ControlServer(SocketServer, ControlServerAPI):
|
|||||||
self.ups_thread = UPSDetectThread(self, c.flag_ups_wait_time)
|
self.ups_thread = UPSDetectThread(self, c.flag_ups_wait_time)
|
||||||
|
|
||||||
# user session
|
# user session
|
||||||
self._session = {}
|
# self._session = {}
|
||||||
self._user_session_expire = c.user_session_expire_days * 24 * 60 * 60 # sec
|
# self._user_session_expire = c.user_session_expire_days * 24 * 60 * 60 # sec
|
||||||
|
|
||||||
# indicate those device together
|
# indicate those device together
|
||||||
self._device_instruction_group = None
|
self._device_instruction_group = None
|
||||||
@@ -129,6 +132,10 @@ class ControlServer(SocketServer, ControlServerAPI):
|
|||||||
# _api request build
|
# _api request build
|
||||||
self._api = ApiRequests()
|
self._api = ApiRequests()
|
||||||
|
|
||||||
|
# sqlalchemy
|
||||||
|
Base.metadata.create_all(engine)
|
||||||
|
self._session = Session()
|
||||||
|
|
||||||
# init method
|
# init method
|
||||||
|
|
||||||
def _init_file_manager(self, option: ControlServerOptions) -> FileManager:
|
def _init_file_manager(self, option: ControlServerOptions) -> FileManager:
|
||||||
@@ -820,16 +827,19 @@ class ControlServer(SocketServer, ControlServerAPI):
|
|||||||
|
|
||||||
@logging_info
|
@logging_info
|
||||||
def device_battery(self, device:int) -> List[int]:
|
def device_battery(self, device:int) -> List[int]:
|
||||||
battery = {}
|
try:
|
||||||
if device == 'all':
|
battery = {}
|
||||||
device_list = self.device_manager.list_device()
|
if device == 'all':
|
||||||
if len(device_list) > 0:
|
device_list = self.device_manager.list_device()
|
||||||
battery = list(map(lambda x: {"device": x.memory_board, "battery":self.device_manager.get_device(x).battery}, device_list))
|
if len(device_list) > 0:
|
||||||
else:
|
battery = list(map(lambda x: {"device": x.memory_board, "battery":self.device_manager.get_device(x).battery}, device_list))
|
||||||
battery = {
|
else:
|
||||||
"device": device,
|
battery = {
|
||||||
"battery": self.device_manager.get_device(device).battery
|
"device": device,
|
||||||
}
|
"battery": self.device_manager.get_device(device).battery
|
||||||
|
}
|
||||||
|
except AttributeError as e:
|
||||||
|
print('device_battery', device, 'not found', e)
|
||||||
return battery
|
return battery
|
||||||
|
|
||||||
@logging_info
|
@logging_info
|
||||||
@@ -1021,8 +1031,17 @@ class ControlServer(SocketServer, ControlServerAPI):
|
|||||||
@logging_info
|
@logging_info
|
||||||
def run_project(self, project) -> bool:
|
def run_project(self, project) -> bool:
|
||||||
if project is not None:
|
if project is not None:
|
||||||
# print(project)
|
|
||||||
project = self._project_manager.create(project)
|
project = self._project_manager.create(project)
|
||||||
|
with self._session as session:
|
||||||
|
project_report = ProjectReport(
|
||||||
|
name = project.name,
|
||||||
|
uuid = project.uuid,
|
||||||
|
cycle = project.cycle,
|
||||||
|
task = project.task_list,
|
||||||
|
device = project.device
|
||||||
|
)
|
||||||
|
session.add(project_report)
|
||||||
|
session.commit()
|
||||||
self._project_manager.run_project(project)
|
self._project_manager.run_project(project)
|
||||||
return project.as_json()
|
return project.as_json()
|
||||||
|
|
||||||
@@ -1078,6 +1097,7 @@ class ControlServer(SocketServer, ControlServerAPI):
|
|||||||
self.log_verbose('update data format', value)
|
self.log_verbose('update data format', value)
|
||||||
|
|
||||||
client = self.data_server.client()
|
client = self.data_server.client()
|
||||||
|
project = None
|
||||||
if client is not None:
|
if client is not None:
|
||||||
info = self.file_manager.use(device)
|
info = self.file_manager.use(device)
|
||||||
|
|
||||||
@@ -1088,9 +1108,12 @@ class ControlServer(SocketServer, ControlServerAPI):
|
|||||||
filename = self._file_save_cache.get(device.device_id, self.TEMP_FILENAME_EXPR)
|
filename = self._file_save_cache.get(device.device_id, self.TEMP_FILENAME_EXPR)
|
||||||
filename = format_filename(filename, device)
|
filename = format_filename(filename, device)
|
||||||
info = self.file_manager.save(device, filename)
|
info = self.file_manager.save(device, filename)
|
||||||
|
|
||||||
|
if device.occupied_by_project != None:
|
||||||
|
project = json.dumps(self.project_manager.get(device.occupied_by_project).info_pass_data_server())
|
||||||
|
|
||||||
with client:
|
with client:
|
||||||
client.update_device_configuration(device, info.meta_file, value)
|
client.update_device_configuration(device, info.meta_file, value, project)
|
||||||
|
|
||||||
def _device_set_disable_cache(self, device: CompletedDevice, disable):
|
def _device_set_disable_cache(self, device: CompletedDevice, disable):
|
||||||
if disable:
|
if disable:
|
||||||
@@ -1124,7 +1147,6 @@ class ControlServer(SocketServer, ControlServerAPI):
|
|||||||
filename = format_filename(self.TEMP_FILENAME_EXPR, device)
|
filename = format_filename(self.TEMP_FILENAME_EXPR, device)
|
||||||
info = self.file_manager.save(device, filename)
|
info = self.file_manager.save(device, filename)
|
||||||
client.update_device_configuration(device, info.meta_file, RawDataDecoder())
|
client.update_device_configuration(device, info.meta_file, RawDataDecoder())
|
||||||
|
|
||||||
if self._device_instruction_group is None:
|
if self._device_instruction_group is None:
|
||||||
client.start_sync(device)
|
client.start_sync(device)
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,9 @@ class RecordingProcess(Process):
|
|||||||
def __init__(self, client_id: str, log_verbose, device_id, queue_rec, queue_ds, queue_msg, meta_path,
|
def __init__(self, client_id: str, log_verbose, device_id, queue_rec, queue_ds, queue_msg, meta_path,
|
||||||
device_info, parameter, parent, recording_file_name, data_format,
|
device_info, parameter, parent, recording_file_name, data_format,
|
||||||
mqtt_ip, mqtt_port,
|
mqtt_ip, mqtt_port,
|
||||||
name = 'Recording-Process', database = None):
|
name = 'Recording-Process',
|
||||||
|
project_id = None,
|
||||||
|
database = None):
|
||||||
super(RecordingProcess, self).__init__(name = name)
|
super(RecordingProcess, self).__init__(name = name)
|
||||||
|
|
||||||
self._database = database
|
self._database = database
|
||||||
@@ -57,6 +59,7 @@ class RecordingProcess(Process):
|
|||||||
self._meta_file._parent = parent
|
self._meta_file._parent = parent
|
||||||
self._meta_file._recording_file_name = recording_file_name
|
self._meta_file._recording_file_name = recording_file_name
|
||||||
self._meta_file._device_id = device_id
|
self._meta_file._device_id = device_id
|
||||||
|
self._meta_file._project_id = project_id
|
||||||
print(self._meta_file._device, self._meta_file._parameter, self._meta_file._parent, self._meta_file._filepath)
|
print(self._meta_file._device, self._meta_file._parameter, self._meta_file._parent, self._meta_file._filepath)
|
||||||
self._meta_file.write(self._database)
|
self._meta_file.write(self._database)
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
0,
|
0,
|
||||||
1,
|
1,
|
||||||
1,
|
1,
|
||||||
|
1,
|
||||||
1
|
1
|
||||||
],
|
],
|
||||||
"domain": {
|
"domain": {
|
||||||
@@ -617,7 +618,8 @@
|
|||||||
"Open Circuit Potential",
|
"Open Circuit Potential",
|
||||||
"Pulse Sensing",
|
"Pulse Sensing",
|
||||||
"Differential Pulse Voltammetry (DPV)",
|
"Differential Pulse Voltammetry (DPV)",
|
||||||
"Chronopotentiometry"
|
"Chronopotentiometry",
|
||||||
|
"Idle"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"VOLT_ORIGIN": {
|
"VOLT_ORIGIN": {
|
||||||
@@ -949,6 +951,7 @@
|
|||||||
"10": "cali_dac_test",
|
"10": "cali_dac_test",
|
||||||
"11": "cali_adc_test",
|
"11": "cali_adc_test",
|
||||||
"12": "",
|
"12": "",
|
||||||
|
"17": "start_data_with_empty_ins",
|
||||||
"*": "start_data"
|
"*": "start_data"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -976,6 +979,11 @@
|
|||||||
"VIS_STI",
|
"VIS_STI",
|
||||||
"_cdr('1X;4X>ADC_VALUE_I')"
|
"_cdr('1X;4X>ADC_VALUE_I')"
|
||||||
],
|
],
|
||||||
|
"start_data_with_empty_ins": [
|
||||||
|
"data_format",
|
||||||
|
"_sync(True)",
|
||||||
|
"VIS_STI"
|
||||||
|
],
|
||||||
"start_data": [
|
"start_data": [
|
||||||
"data_format",
|
"data_format",
|
||||||
"_notify(True)",
|
"_notify(True)",
|
||||||
|
|||||||
@@ -290,7 +290,7 @@
|
|||||||
"auto"
|
"auto"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"RT_VOLT_SET": {
|
"DAC_VOLT": {
|
||||||
"description": "DAC output Voltage",
|
"description": "DAC output Voltage",
|
||||||
"record_meta": true,
|
"record_meta": true,
|
||||||
"initial": 37500,
|
"initial": 37500,
|
||||||
@@ -299,8 +299,7 @@
|
|||||||
],
|
],
|
||||||
"value": {
|
"value": {
|
||||||
"expression": "VALUE"
|
"expression": "VALUE"
|
||||||
},
|
}
|
||||||
"on_change": "set_para_RT_VOLT_SET"
|
|
||||||
},
|
},
|
||||||
"BLE_WRITE": {
|
"BLE_WRITE": {
|
||||||
"description": "send msg to elite",
|
"description": "send msg to elite",
|
||||||
@@ -354,7 +353,7 @@
|
|||||||
"1": "curve_cv3",
|
"1": "curve_cv3",
|
||||||
"2": "curve_const_vscan",
|
"2": "curve_const_vscan",
|
||||||
"3": "curve_vt",
|
"3": "curve_vt",
|
||||||
"4": "curve_rt"
|
"4": "curve_zt"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -487,10 +486,10 @@
|
|||||||
"2B>pe"
|
"2B>pe"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"curve_rt": {
|
"curve_zt": {
|
||||||
"type": "RIS",
|
"type": "RIS",
|
||||||
"parameter": {
|
"parameter": {
|
||||||
"va": "RT_VOLT_SET",
|
"va": "DAC_VOLT",
|
||||||
"pa": "ADC_LEVEL_I_15",
|
"pa": "ADC_LEVEL_I_15",
|
||||||
"pb": "ADC_LEVEL_V_IN_15",
|
"pb": "ADC_LEVEL_V_IN_15",
|
||||||
"pd": "CTRL_HIGH_Z_15",
|
"pd": "CTRL_HIGH_Z_15",
|
||||||
@@ -521,12 +520,6 @@
|
|||||||
"1B>va"
|
"1B>va"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"set_para_RT_VOLT_SET": {
|
|
||||||
"type": "RIS",
|
|
||||||
"data": [
|
|
||||||
"XE2;X01;2B>RT_VOLT_SET"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"ble_instru_send": [
|
"ble_instru_send": [
|
||||||
"ble_write",
|
"ble_write",
|
||||||
"_cdr('20X>ADC_VALUE_I')"
|
"_cdr('20X>ADC_VALUE_I')"
|
||||||
|
|||||||
Reference in New Issue
Block a user