Compare commits

...

5 Commits

Author SHA1 Message Date
peterlu14 aa9d270039 -fix DetachedInstanceError 2023-06-08 10:17:06 +08:00
peterlu14 32bc481a91 -update add subject write in same folder 2023-06-08 10:17:04 +08:00
peterlu14 0e30bd1263 -update db_update_script 2023-06-08 10:16:50 +08:00
peterlu14 dda51889dc -fix import error 2023-06-08 10:15:46 +08:00
peterlu14 0c811f529b -update subject 2023-06-05 11:55:36 +08:00
10 changed files with 320 additions and 26 deletions
+30 -15
View File
@@ -20,29 +20,44 @@ class Collection(Base):
updated_at = Column(TIMESTAMP(timezone=True), onupdate=func.now()) updated_at = Column(TIMESTAMP(timezone=True), onupdate=func.now())
@classmethod @classmethod
def create_collection(cls, collection_name, parent): def create_collection(cls, collection_name, parent, duplicate=False):
with Session() as session: with Session() as session:
name = cls.check_name_duplicate(collection_name, parent, 0) name = cls.check_name_duplicate(collection_name, parent, 0, duplicate=duplicate)
collection = Collection( if name == None:
name = name, return session.query(Collection).filter(Collection.name == collection_name, Collection.parent == parent).first()
parent = parent, else:
type= "folder", collection = Collection(
) name = name,
session.add(collection) parent = parent,
session.commit() type= "folder",
print('a', collection.id) )
return collection session.add(collection)
session.commit()
session.refresh(collection)
return collection
@classmethod @classmethod
def check_name_duplicate(cls, collection_name, parent, n): def check_name_duplicate(cls, collection_name, parent, n, _session = None, duplicate=False):
with Session() as session: if _session == None:
result = session.query(Collection).filter(Collection.name == cls.generate_name(collection_name, n), Collection.parent == parent).first() with Session() as session:
result = session.query(Collection).filter(Collection.name == cls.generate_name(collection_name, n), Collection.parent == parent).first()
if result is None:
return cls.generate_name(collection_name, n)
else:
if duplicate == True:
return None
else:
new_num = n + 1
# new_name = f"{collection_name}({new_num})"
return cls.check_name_duplicate(collection_name, parent, new_num, session)
else:
result = _session.query(Collection).filter(Collection.name == cls.generate_name(collection_name, n), Collection.parent == parent).first()
if result is None: if result is None:
return cls.generate_name(collection_name, n) return cls.generate_name(collection_name, n)
else: else:
new_num = n + 1 new_num = n + 1
# new_name = f"{collection_name}({new_num})" # new_name = f"{collection_name}({new_num})"
return cls.check_name_duplicate(collection_name, parent, new_num) return cls.check_name_duplicate(collection_name, parent, new_num, _session)
@classmethod @classmethod
def generate_name(cls, collection_name, n): def generate_name(cls, collection_name, n):
+24
View File
@@ -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, Session
class RecordingDataMeta(Base):
__tablename__ = "recording_data_metas"
id = Column(Integer, primary_key=True)
path = Column(String(255))
name = Column(String(255))
parent = Column(JSONB)
size = Column(String(255))
time_duration = (String(255))
raw_data = Column(JSONB)
project = 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})"
+88
View File
@@ -0,0 +1,88 @@
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, Text
from sqlalchemy.dialects.postgresql import JSONB
from biopro.db.base import Session
from .base import Base
# build a model class with a specific table name
def get_raw_model(channel):
tablename = str(channel) + '_recording_data_raws' # dynamic table name
class_name = 'RECORDING_DATA_RAWS' # dynamic class name
print('get_raw_model', tablename)
for mapper in Base.registry.mappers:
cls = mapper.class_
classname = cls.__name__
tblname = cls.__tablename__
print(cls, classname, tblname)
if (classname == class_name):
if tblname == tablename:
return cls
Model = type(class_name, (RECORDING_DATA_RAWS,), {
'__tablename__': tablename
})
return Model
class RECORDING_DATA_RAWS(Base):
__abstract__ = True
id = Column(Integer, primary_key=True)
name = Column(String(255))
parent = Column(Integer)
size = Column(String(255))
path = Column(JSONB)
uuid = Column(String(255))
serial_number = Column(String(255))
data_format = Column(String(255))
channel = Column(Integer)
start_time = Column(String(255))
end_time = Column(String(255))
data = Column(Text)
compressed = Column(Boolean)
deleted = Column(Boolean)
created_at = Column(TIMESTAMP(timezone=True), server_default=func.now())
updated_at = Column(TIMESTAMP(timezone=True), onupdate=func.now())
# @classmethod
# def create_subject_data(cls, subject_id, project, meta, data):
# with Session() as session:
# subject = Subject(
# subject_id = subject_id,
# project = project,
# meta= meta,
# data = data
# )
# session.add(subject)
# session.commit()
# return subject
# @classmethod
# def check_name_duplicate(cls, collection_name, parent, n):
# with Session() as session:
# result = session.query(Collection).filter(Collection.name == cls.generate_name(collection_name, n), Collection.parent == parent).first()
# if result is None:
# return cls.generate_name(collection_name, n)
# else:
# new_num = n + 1
# # new_name = f"{collection_name}({new_num})"
# return cls.check_name_duplicate(collection_name, parent, new_num)
# @classmethod
# def generate_name(cls, collection_name, n):
# if n==0:
# return collection_name
# else:
# return f"{collection_name}({n})"
# @classmethod
# def find_data(cls, id):
# with Session() as session:
# result = session.query(RECORDING_DATA_RAWS).first()
# return result
+60
View File
@@ -0,0 +1,60 @@
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 biopro.db.base import Session
from .base import Base
class SubjectData(Base):
__tablename__ = "subject_datas"
id = Column(Integer, primary_key=True)
subject_id = Column(Integer)
mode = Column(JSONB)
data = Column(JSONB)
user_auth = Column(JSONB)
meta = Column(String(255))
project = Column(String(255))
deleted = Column(Boolean)
created_at = Column(TIMESTAMP(timezone=True), server_default=func.now())
updated_at = Column(TIMESTAMP(timezone=True), onupdate=func.now())
@classmethod
def create_subject_data(cls, subject_id, project, meta, data):
with Session() as session:
subject = SubjectData(
subject_id = subject_id,
project = project,
meta= meta,
data = data
)
session.add(subject)
session.commit()
return subject
# @classmethod
# def check_name_duplicate(cls, collection_name, parent, n):
# with Session() as session:
# result = session.query(Collection).filter(Collection.name == cls.generate_name(collection_name, n), Collection.parent == parent).first()
# if result is None:
# return cls.generate_name(collection_name, n)
# else:
# new_num = n + 1
# # new_name = f"{collection_name}({new_num})"
# return cls.check_name_duplicate(collection_name, parent, new_num)
# @classmethod
# def generate_name(cls, collection_name, n):
# if n==0:
# return collection_name
# else:
# return f"{collection_name}({n})"
# @classmethod
# def find_collection(cls, collection_name, parent):
# with Session() as session:
# result = session.query(Collection).filter(Collection.name == collection_name, Collection.parent == parent).first()
# return result
+3
View File
@@ -1292,6 +1292,9 @@ class CompletedDevice(Device):
def central_version_get(self) -> Optional[list]: def central_version_get(self) -> Optional[list]:
return self._device.central_version_get() return self._device.central_version_get()
def save_data_to_subject(self, project, meta, device, subject_id):
self._master._handler.save_data_to_subject(project, meta, device, subject_id)
# utility method # utility method
+26 -1
View File
@@ -49,6 +49,9 @@ class Project(threading.Thread):
self._count = 1 #流水號 self._count = 1 #流水號
self._project_meta_id = -1
self._subject = []
self.log_verbose = log_verbose self.log_verbose = log_verbose
self._logger = logging.getLogger('project') self._logger = logging.getLogger('project')
self._logger.setLevel('DEBUG') self._logger.setLevel('DEBUG')
@@ -69,7 +72,10 @@ class Project(threading.Thread):
collection = Collection.find_collection(default_name, default_parent) collection = Collection.find_collection(default_name, default_parent)
parent = {"folder": [collection.id]} parent = {"folder": [collection.id]}
# create project folder # create project folder
collection = Collection.create_collection(self.name, parent) folder_name_duplicate = False
if len(self._subject) > 0:
folder_name_duplicate = True
collection = Collection.create_collection(self.name, parent, folder_name_duplicate)
self.setup_collection(collection) self.setup_collection(collection)
def setup_project(self, project): def setup_project(self, project):
@@ -101,6 +107,22 @@ class Project(threading.Thread):
@id.setter @id.setter
def id(self, new_id): def id(self, new_id):
self._id = new_id self._id = new_id
@property
def project_meta_id(self) -> int:
return self._project_meta_id
@project_meta_id.setter
def project_meta_id(self, new_project_meta_id):
self._project_meta_id = new_project_meta_id
@property
def subject(self) -> object:
return self._subject
@subject.setter
def subject(self, new_subject):
self._subject = new_subject
@property @property
def uuid(self) -> str: def uuid(self) -> str:
@@ -278,6 +300,9 @@ class Project(threading.Thread):
args = list(map(lambda arg: task_info[arg], instruction['arguments'])) args = list(map(lambda arg: task_info[arg], instruction['arguments']))
target=getattr(device, instruction['method'])(*args) target=getattr(device, instruction['method'])(*args)
print('instruction 2', device, instruction, datetime.now()) print('instruction 2', device, instruction, datetime.now())
if (action.type == 'stop'):
if (len(self._subject) > 0):
target=getattr(device, "save_data_to_subject")(self.id, self.project_meta_id, device, self._subject[0])
if action.type == 'start': if action.type == 'start':
self._count += 1 self._count += 1
+1 -1
View File
@@ -175,7 +175,7 @@ class TaskManager():
for index, task in enumerate(self._task_list): for index, task in enumerate(self._task_list):
if self.check_task_in_cycle(index) == True: if self.check_task_in_cycle(index) == True:
if task.type == '': if task.type == '':
collection = Collection.create_collection(task.name, {"folder": [parent.id]}) collection = Collection.create_collection(task.name, {"folder": [parent.id]}, False)
task.parent = {"folder": [collection.id]} task.parent = {"folder": [collection.id]}
else: else:
task.parent = {"folder": [parent.id]} task.parent = {"folder": [parent.id]}
+81 -7
View File
@@ -35,8 +35,11 @@ from biopro.project.project_manager import ProjectManager
from biopro.db.base import Base, Session, engine from biopro.db.base import Base, Session, engine
from biopro.db.project_report import ProjectReport from biopro.db.project_report import ProjectReport
from biopro.db.project_meta import MetaProjectInfo from biopro.db.project_meta import MetaProjectInfo
from biopro.db.device import Device # from biopro.db.device import Device
from biopro.db.recording_data import get_raw_model
from biopro.db.subject_data import SubjectData
from biopro.db.meta import RecordingDataMeta
import random
_RUNTIME_COMPILE = False _RUNTIME_COMPILE = False
@@ -329,6 +332,18 @@ class ControlServer(SocketServer, ControlServerAPI):
finally: finally:
self.led_thread.set_state(LED.AVAILABLE) self.led_thread.set_state(LED.AVAILABLE)
# version_info = [0, 2, 1, 7, 23, 2]
# serial_number = DeviceSerialNumber(version_info[0],
# version_info[1],
# version_info[2],
# version_info[3],
# version_info[4],
# version_info[5])
# response = DeviceResponseInfo('Elite-EDC', serial_number, (164, 218, 50, 212, 231, 12), addr_type=0)
# print('setup done', response)
# ret = self.device_manager.connect(response)
# print('ret', ret)
def _setup_get_available_channel(self) -> Optional[List[int]]: def _setup_get_available_channel(self) -> Optional[List[int]]:
client = self.data_server.client() client = self.data_server.client()
@@ -558,8 +573,15 @@ class ControlServer(SocketServer, ControlServerAPI):
response = content response = content
else: else:
response = to_device_info(content) response = to_device_info(content)
try: try:
# version_info = [0, 2, 1, 7, 23, 2]
# serial_number = DeviceSerialNumber(version_info[0],
# version_info[1],
# version_info[2],
# version_info[3],
# version_info[4],
# version_info[5])
# response = DeviceResponseInfo('Elite-EDC', serial_number, (164, 218, 50, 212, 231, 12))
ret = self.device_manager.connect(response) ret = self.device_manager.connect(response)
except DeviceInstructionError as e: except DeviceInstructionError as e:
'''when device reset fail error''' '''when device reset fail error'''
@@ -1107,7 +1129,7 @@ class ControlServer(SocketServer, ControlServerAPI):
client = self.data_server.client() client = self.data_server.client()
project = None project = None
project_meta_id = None _project_meta_id = None
if client is not None: if client is not None:
info = self.file_manager.use(device) info = self.file_manager.use(device)
@@ -1121,10 +1143,12 @@ class ControlServer(SocketServer, ControlServerAPI):
if device.occupied_by_project != None: if device.occupied_by_project != None:
project = self.project_manager.get(device.occupied_by_project).info_pass_data_server() project = self.project_manager.get(device.occupied_by_project).info_pass_data_server()
project_meta_id = MetaProjectInfo.create_project_meta(project) _project_meta_id = MetaProjectInfo.create_project_meta(project)
new_project = self.project_manager.get(device.occupied_by_project)
new_project.project_meta_id = _project_meta_id
with client: with client:
client.update_device_configuration(device, info.meta_file, value, project_meta_id) client.update_device_configuration(device, info.meta_file, value, _project_meta_id)
def _device_set_disable_cache(self, device: CompletedDevice, disable): def _device_set_disable_cache(self, device: CompletedDevice, disable):
if disable: if disable:
@@ -1354,6 +1378,57 @@ class ControlServer(SocketServer, ControlServerAPI):
} for pkg in PipPackage.list()] } for pkg in PipPackage.list()]
return ret return ret
def save_data_to_subject(self, project, meta, device, subject):
mode = device.get_parameter('MODE')
library = device.library_name
device = {
"library": library,
"mode": mode
}
# "pattern": {
# "id": number,
# "name": string,
# "parameter": object,
# },
# "data": {
# "id": list[int],
# "channel: list[int]
# }
with Session() as session:
meta_result = session.query(RecordingDataMeta).filter(RecordingDataMeta.project == meta).first()
self.mqtt_thread.publish('', json.dumps({
"pattern": {
"id": 4,
},
"data": {
"id": [meta_result.id],
"channel": ['Time', 6]
},
"others": {
"subject": subject,
"device": device,
"project": project,
"project_meta": meta,
}
}), analysis= True)
# result = session.query(recording_raws).order_by(recording_raws.id.desc()).first()
# value = result.data.split(' ')[1:-1:2]
# _value = list(map(int, value))
# sum_value = sum(_value)
# average_value = sum_value / len(_value)
# subject_data = SubjectData(
# subject_id= subject['id'],
# project = project,
# meta = meta,
# mode= device,
# data= average_value
# )
# # Execute the update query
# session.add(subject_data)
# session.commit()
def _hardware_send_test_hardware(self, section: Optional[str] = None) -> Dict[str, Any]: def _hardware_send_test_hardware(self, section: Optional[str] = None) -> Dict[str, Any]:
if section is not None: if section is not None:
@@ -1398,7 +1473,6 @@ class ControlServer(SocketServer, ControlServerAPI):
if client is not None: if client is not None:
with client: with client:
client.show_data(device) client.show_data(device)
class _RandomCrashThread(ServerThread): class _RandomCrashThread(ServerThread):
def __init__(self): def __init__(self):
super().__init__('Crash') super().__init__('Crash')
+3 -1
View File
@@ -170,9 +170,11 @@ class MqttThread(threading.Thread):
self.sleep(3) self.sleep(3)
self._mqtt_client_local.reconnect() self._mqtt_client_local.reconnect()
def publish(self, topic: str, payload: str, inter = False, qos = 2): def publish(self, topic: str, payload: str, inter = False, analysis=False, qos = 2):
if inter: if inter:
_topic = self.__controller_ID + '_user' _topic = self.__controller_ID + '_user'
elif analysis:
_topic = self.__controller_ID + '_data_analysis/get_analysis_data'
else: else:
_topic = self.__controller_ID + '/' + topic _topic = self.__controller_ID + '/' + topic
if self._mqtt_client_local is not None: if self._mqtt_client_local is not None:
+4 -1
View File
@@ -35,4 +35,7 @@ sudo su -c "psql -d postgres -c \"ALTER TABLE devices ALTER COLUMN calibration D
sudo su -c "psql -d postgres -c \"ALTER TABLE devices ALTER COLUMN calibration TYPE bytea USING calibration::bytea;\"" postgres sudo su -c "psql -d postgres -c \"ALTER TABLE devices ALTER COLUMN calibration TYPE bytea USING calibration::bytea;\"" postgres
# add column project in recording_data_metas # add column project in recording_data_metas
sudo su -c "psql -d postgres -c \"ALTER TABLE devices ADD COLUMN IF NOT EXISTS calibration_version Int4 DEFAULT -1;\"" postgres sudo su -c "psql -d postgres -c \"ALTER TABLE devices ADD COLUMN IF NOT EXISTS calibration_version Int4 DEFAULT -1;\"" postgres
# add column subject in project
sudo su -c "psql -d postgres -c \"ALTER TABLE projects ADD COLUMN IF NOT EXISTS subject JSONB;\"" postgres