Compare commits
53 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ecb9e92092 | |||
| 2e1ae9892b | |||
| e98e05a515 | |||
| 52095f0284 | |||
| 3f790b43de | |||
| 01e5370e1c | |||
| df4c178131 | |||
| 81e6c48350 | |||
| cd720e80e7 | |||
| b253aca73f | |||
| 2fd05d18ed | |||
| 03011ebd5f | |||
| 4b9bc30e28 | |||
| 4966113393 | |||
| 3371c21bbd | |||
| afc87829d9 | |||
| 952403cbf4 | |||
| 1cdd04901c | |||
| cd60e14cbe | |||
| ae55e6c789 | |||
| b8addb7686 | |||
| da581ae225 | |||
| a941f7c060 | |||
| 4b0472ecf4 | |||
| de51f53657 | |||
| 6974950d31 | |||
| 0887c48ddc | |||
| 184c7536a6 | |||
| 1a3a833680 | |||
| df3c7db8bc | |||
| 7287f4c19b | |||
| 7d3f7a47ff | |||
| 81c699e830 | |||
| 71e469ec2f | |||
| e4bef30be2 | |||
| 96ec0a983f | |||
| 2dd19a575f | |||
| affacfddeb | |||
| de8a6e58e4 | |||
| 390da7b004 | |||
| f8e41e9247 | |||
| 1d96f49f63 | |||
| 23a04d06c9 | |||
| 7c3bc2d20b | |||
| 01d1bd989c | |||
| 1dffa29658 | |||
| a0e8f9c6c4 | |||
| 416503f7fb | |||
| be36bb785c | |||
| 9560b9e0ef | |||
| 07a1e0f5bc | |||
| a96837a462 | |||
| 6b29f1f08e |
@@ -18,9 +18,10 @@ class ControllerAPI():
|
||||
@staticmethod
|
||||
def getByMac(mac_address):
|
||||
try:
|
||||
ret = requests.get(API_URL + 'api/controller/get_by_mac/' + mac_address, headers= AuthAPI.get_key())
|
||||
if ret.status_code == 200:
|
||||
return ret.json()
|
||||
if mac_address != None:
|
||||
ret = requests.get(API_URL + 'api/controller/get_by_mac/' + mac_address, headers= AuthAPI.get_key())
|
||||
if ret.status_code == 200:
|
||||
return ret.json()
|
||||
except (requests.exceptions.ConnectionError, json.decoder.JSONDecodeError) as e:
|
||||
print('get controller fail', e)
|
||||
return []
|
||||
|
||||
@@ -1576,6 +1576,11 @@ class ControlAPI(metaclass=Router):
|
||||
should handle this exit code and re-run server process.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def run_project(self, project) -> bool:
|
||||
print('create_project', project)
|
||||
self._project_manager.create(project)
|
||||
return False
|
||||
|
||||
|
||||
# noinspection PyAbstractClass
|
||||
|
||||
@@ -536,7 +536,7 @@ class CC2650Device(Device):
|
||||
self._master.log_warn('device', self.device_id, 'update_battery_info no response')
|
||||
|
||||
else:
|
||||
if data is not None and len(data) == 4 :
|
||||
if data is not None and len(data) > 2 :
|
||||
battery = struct.unpack('<H', data[1:3])[0]
|
||||
if battery is not None:
|
||||
self._battery = battery
|
||||
@@ -2035,6 +2035,7 @@ class CC2650SingleMasterCentralDevice(CC2650MasterDevice, Synchronized):
|
||||
# print("local_name = ", local_name)
|
||||
|
||||
# addr type is don't care in BMD380
|
||||
print('scan_response:', list(scan_response))
|
||||
local_addr_type = int(scan_response[index:index + 1][0])
|
||||
# local_addr_type = 0xFF
|
||||
index = index + 1
|
||||
|
||||
@@ -562,6 +562,7 @@ class DeviceManager(MasterDevice, Synchronized):
|
||||
|
||||
@logging_verbose
|
||||
def get_device(self, device: Union[int, DeviceInfo]) -> Optional[CompletedDevice]:
|
||||
print('get_device', device)
|
||||
"""get connected device
|
||||
|
||||
:param device: device ID or response info
|
||||
@@ -574,7 +575,7 @@ class DeviceManager(MasterDevice, Synchronized):
|
||||
|
||||
elif isinstance(device, str):
|
||||
for slave in self._device:
|
||||
if ':'.join('{:02x}'.format(b) for b in slave.mac_address) == device:
|
||||
if ':'.join('{:02x}'.format(b) for b in slave.mac_address) == device.lower():
|
||||
return slave
|
||||
|
||||
elif isinstance(device, DeviceInfo):
|
||||
|
||||
@@ -882,21 +882,18 @@ class I4V4Z4T4DataDecoder(RecDataDecoder):
|
||||
if len(data) < 18:
|
||||
return None
|
||||
|
||||
current = struct.unpack('>i', data[1:5])[0] # unit: 1/1000 nA
|
||||
voltage = struct.unpack('>i', data[5:9])[0] # unit: mV
|
||||
impedance = struct.unpack('>i', data[9:13])[0] # unit: kOm
|
||||
time_stamp: float = struct.unpack('<I', data[13:17])[0] # unit: ms
|
||||
cycle_number = struct.unpack('>H', data[17:19])[0]
|
||||
finish_mode_falg = data[19]
|
||||
mem_cnt = data[1]
|
||||
time_stamp: float = struct.unpack('<I', data[4:8])[0] # unit: ms 0x18030000
|
||||
current = struct.unpack('<i', data[8:12])[0] # unit: nA
|
||||
voltage = struct.unpack('<i', data[12:16])[0] # unit: uV
|
||||
impedance = struct.unpack('<i', data[16:20])[0] # unit: mOm
|
||||
cycle_number = struct.unpack('<H', data[20:22])[0]
|
||||
finish_mode_falg = data[22]
|
||||
battery = struct.unpack('<i', data[23:27])[0]
|
||||
elite_notify_times = data[27]
|
||||
|
||||
mem_wrong_information = struct.unpack('>i', data[40:40+4])[0]
|
||||
|
||||
# print('decode', list(data[20:]))
|
||||
mem_wrong = data[40]
|
||||
mem_retry_cnt = data[41]
|
||||
mem_green_wrong = data[42]
|
||||
mem_green_retry_cnt = data[43]
|
||||
ram_num = data[44]
|
||||
mem_wrong_information = struct.unpack('<i', data[43:47])[0] # mem_wrong_information = green retry, green wrong, red retry, red wrong
|
||||
ram_num = data[47]
|
||||
broken_flag = data[-1]
|
||||
|
||||
if (finish_mode_falg & 0b11110000 == 0b10100000):
|
||||
@@ -917,10 +914,13 @@ class I4V4Z4T4DataDecoder(RecDataDecoder):
|
||||
print("error timeStamp full data:", list(data), datetime.now(), '\n')
|
||||
return None
|
||||
else:
|
||||
# print('|', time_stamp, '|', delta, '|', current, '|', voltage, '|', impedance,
|
||||
# print('|', time_stamp, '|', delta, '|', int(time_stamp * 1000 / 2),
|
||||
# '|', current, '|', voltage, '|', impedance,
|
||||
# '|', cycle_number, '|', finishMode, '@', str(self.device))
|
||||
|
||||
# print('|', '{:10}'.format(time_stamp),
|
||||
# '|', '{:10}'.format(delta),
|
||||
# '|', '{:4}'.format(delta),
|
||||
# '|', '{:10}'.format(int(time_stamp * 1000 / 2)),
|
||||
# '|', '{:10}'.format(current),
|
||||
# '|', '{:10}'.format(voltage),
|
||||
# '|', '{:10}'.format(impedance),
|
||||
@@ -928,13 +928,9 @@ class I4V4Z4T4DataDecoder(RecDataDecoder):
|
||||
# '|', '{:1}'.format(finishMode),
|
||||
# '@', str(self.device), '|')
|
||||
|
||||
# print('|', '{:5}'.format(mem_wrong),
|
||||
# '|', '{:5}'.format(mem_retry_cnt),
|
||||
# '|', '{:5}'.format(mem_green_wrong),
|
||||
# '|', '{:5}'.format(mem_green_retry_cnt),
|
||||
# '|', '{:5}'.format(mem_wrong_information),
|
||||
# '|', '{:5}'.format(ram_num),
|
||||
# '|', '{:5}'.format(broken_flag),
|
||||
# print('|', '{:5}'.format(mem_wrong_information),
|
||||
# '|', '{:2}'.format(ram_num),
|
||||
# '|', '{:2}'.format(broken_flag),
|
||||
# '@', str(self.device), '|')
|
||||
pass
|
||||
|
||||
@@ -949,16 +945,20 @@ class I4V4Z4T4DataDecoder(RecDataDecoder):
|
||||
ret.append_data(1, voltage)
|
||||
ret.append_data(2, impedance)
|
||||
ret.append_data(3, cycle_number)
|
||||
ret.append_data(4, battery)
|
||||
ret.append_data(5, elite_notify_times)
|
||||
ret.append_data(6, mem_cnt)
|
||||
|
||||
# memoryboard information
|
||||
# ret.append_data(4, mem_wrong)
|
||||
# ret.append_data(5, mem_retry_cnt)
|
||||
# ret.append_data(6, mem_green_wrong)
|
||||
# ret.append_data(7, mem_green_retry_cnt)
|
||||
ret.append_data(4, ram_num)
|
||||
ret.append_data(5, broken_flag)
|
||||
ret.append_data(6, mem_wrong_information)
|
||||
# ret.append_data(4, ram_num)
|
||||
ret.append_data(7, ram_num)
|
||||
ret.append_data(8, broken_flag)
|
||||
try:
|
||||
ret.append_data(9, mem_wrong_information)
|
||||
# print('append_data success, mem_wrong_information:', mem_wrong_information, hex(mem_wrong_information))
|
||||
except:
|
||||
print('append_data fail, mem_wrong_information:', mem_wrong_information, hex(mem_wrong_information))
|
||||
|
||||
|
||||
|
||||
if cycle_number != self._cycle_number:
|
||||
# notify cycle_number change
|
||||
@@ -1456,12 +1456,12 @@ class EISZeroOneDataDecoder(RecDataDecoder):
|
||||
if len(data) < 18:
|
||||
return None
|
||||
|
||||
ch1 = struct.unpack('>i', data[1:5])[0] # unit: 1/1000 nA
|
||||
ch2 = struct.unpack('>i', data[5:9])[0] # unit: mV
|
||||
ch3 = struct.unpack('>i', data[9:13])[0] # unit: kOm
|
||||
time_stamp: float = struct.unpack('<I', data[13:17])[0] # unit: ms
|
||||
cycle_number = struct.unpack('>H', data[17:19])[0]
|
||||
d19 = data[19]
|
||||
ch1 = struct.unpack('>i', data[1+3:5+3])[0] # unit: 1/1000 nA
|
||||
ch2 = struct.unpack('>i', data[5+3:9+3])[0] # unit: mV
|
||||
ch3 = struct.unpack('>i', data[9+3:13+3])[0] # unit: kOm
|
||||
time_stamp: float = struct.unpack('<I', data[13+3:17+3])[0] # unit: ms
|
||||
cycle_number = struct.unpack('>H', data[17+3:19+3])[0]
|
||||
d19 = data[19+3]
|
||||
gain = (d19 & 0x0F)
|
||||
finishMode = (d19 & 0x80) >> 7
|
||||
|
||||
|
||||
@@ -1082,6 +1082,11 @@ class CompletedDevice(Device):
|
||||
:return: parameter V value
|
||||
"""
|
||||
return self._configuration.get_parameter(name, False)
|
||||
|
||||
def set_multi_parameters(self, parameter):
|
||||
for (name, value) in parameter[0].items():
|
||||
if name != 'target':
|
||||
self.set_parameter(name, value)
|
||||
|
||||
def set_parameter(self, name: str, value: Union[int, str]):
|
||||
"""replace parameter value with *value*
|
||||
|
||||
+117
-43
@@ -24,8 +24,10 @@ def zero_buffer(size: int) -> List[int]:
|
||||
return [0] * size
|
||||
|
||||
class MultiExtMemSpiInterface(LowLevelHardwareInterface):
|
||||
MEM_INS_MARKED = [MEM_INS_WRITE, 0, 2, 1, 1]
|
||||
MEM_INS_RESET = [MEM_INS_WRITE, 0, 2, 1, 1, 0, 0xFF]
|
||||
MEM_INS_MARKED1 = [MEM_INS_WRITE, 0, 2, 0x5A, 0xA5]
|
||||
MEM_INS_MARKED2 = [MEM_INS_WRITE, 0, 6, 0x5A, 0xA5]
|
||||
MEM_INS_MARKED3 = [MEM_INS_WRITE, 0, 10, 0x5A, 0xA5]
|
||||
# MEM_INS_RESET = [MEM_INS_WRITE, 0, 2, 1, 1, 0, 0xFF]
|
||||
|
||||
__slots__ = ('_selector', '_wait_for_first_data', '_spi', '_tx_buffer_header', '_tx_buffer_data',
|
||||
'pin_busy', 'pin_mem_req', 'pin_mem_sel', 'pin_ram_sel',
|
||||
@@ -44,11 +46,11 @@ class MultiExtMemSpiInterface(LowLevelHardwareInterface):
|
||||
|
||||
self._elite_data_len = 40
|
||||
self._mem_header_len = 3
|
||||
self._mem_tailer_len = 8
|
||||
self._mem_tailer_len = 6
|
||||
self._single_data_len = self._elite_data_len + self._mem_header_len + self._mem_tailer_len
|
||||
|
||||
# buffer
|
||||
self._tx_buffer_header = [0] * 11
|
||||
self._tx_buffer_header = [0] * 19
|
||||
self._tx_buffer_data = [0] * (self._single_data_len * 10 + 3)
|
||||
|
||||
# memory control pin
|
||||
@@ -165,6 +167,52 @@ class MultiExtMemSpiInterface(LowLevelHardwareInterface):
|
||||
print("read red data times", self._read_red_times)
|
||||
return data
|
||||
|
||||
def _compare_green_data_addr_and_flag(self, data: Union[bytes, List[int]], device: int):
|
||||
|
||||
green_data_section1 = data[3:7]
|
||||
green_data_section2 = data[7:11]
|
||||
green_data_section3 = data[11:15]
|
||||
green_data_section = []
|
||||
|
||||
if green_data_section1 == green_data_section2:
|
||||
green_data_section = green_data_section1
|
||||
|
||||
elif(green_data_section2 == green_data_section3 or green_data_section1 == green_data_section3):
|
||||
print("green data not equal: = ", data[3:15])
|
||||
print("green data print:", data, device, datetime.now())
|
||||
green_data_section = green_data_section3
|
||||
|
||||
else:
|
||||
print("green data not equal: = ", data[3:15])
|
||||
print("green data print:", data, device, datetime.now())
|
||||
green_data_section = green_data_section3 # use last data
|
||||
|
||||
|
||||
return green_data_section
|
||||
|
||||
def _print_ram_all_data(self):
|
||||
addr = 0
|
||||
red_length = int(7000 / 2)
|
||||
tx_temp = [0] * (red_length + 3)
|
||||
|
||||
while True:
|
||||
tx_temp[0] = MEM_INS_READ
|
||||
tx_temp[1] = ((addr >> 8) & 0xFF)
|
||||
tx_temp[2] = (addr & 0xFF)
|
||||
|
||||
ram_data = []
|
||||
ram_data = self._spi.send_byte(tx_temp)
|
||||
ram_data[0:3] = [255, 255, 255]
|
||||
print(list(ram_data), len(ram_data), addr)
|
||||
addr += len(ram_data) - 3
|
||||
|
||||
if (7000 < addr + len(ram_data)):
|
||||
del ram_data
|
||||
break
|
||||
print()
|
||||
|
||||
return
|
||||
|
||||
def recv_memory(self, device: int) -> Optional[bytes]:
|
||||
self.pin_busy.output(False)
|
||||
|
||||
@@ -191,7 +239,7 @@ class MultiExtMemSpiInterface(LowLevelHardwareInterface):
|
||||
self._head_wrong_cnt[device] = self._head_wrong_cnt[device] + 1
|
||||
if (self._head_wrong_cnt[device] <= 5): # print 5 times
|
||||
print('data_first[0:3] != [255, 255, 255], device:', device, ',', self._head_wrong_cnt[device], 'times')
|
||||
print(list(data[0:7]))
|
||||
print(list(data))
|
||||
|
||||
data[0:3] = [255, 255, 255]
|
||||
# ----------------------------------------------------------------------------------------------
|
||||
@@ -210,13 +258,13 @@ class MultiExtMemSpiInterface(LowLevelHardwareInterface):
|
||||
# self._head_wrong_cnt[device] = self._head_wrong_cnt[device] + 1
|
||||
# if (self._head_wrong_cnt[device] < 10):
|
||||
# print('data_first[0:3] != [255, 255, 255], device:', device, ',', self._head_wrong_cnt[device], 'times')
|
||||
# print(list(data_first[0:7]))
|
||||
# print(list(data_first))
|
||||
|
||||
# if (data_second[0] != 255 or data_second[1] != 255 or data_second[2] != 255):
|
||||
# self._head_wrong_cnt[device] = self._head_wrong_cnt[device] + 1
|
||||
# if (self._head_wrong_cnt[device] < 10):
|
||||
# print('data_second[0:3] != [255, 255, 255], device:', device, ',', self._head_wrong_cnt[device], 'times')
|
||||
# print(list(data_second[0:7]))
|
||||
# print(list(data_second))
|
||||
|
||||
# if (data_first[3:] == data_second[3:]):
|
||||
# data = data_first
|
||||
@@ -228,59 +276,47 @@ class MultiExtMemSpiInterface(LowLevelHardwareInterface):
|
||||
# data = self.compare_green_data(data_first, data_second, data_third, len(tx_h))
|
||||
# ----------------------------------------------------------------------------------------------
|
||||
|
||||
# debug use
|
||||
# green_data = []
|
||||
# green_data = data
|
||||
# print("_[Debug] @ spi green data = ", green_data)
|
||||
green_data_section = self._compare_green_data_addr_and_flag(data, device)
|
||||
|
||||
length = (data[3] << 8) | data[4]
|
||||
header = data[7]
|
||||
elite_data_len = data[9]
|
||||
length = (green_data_section[0] << 8) | green_data_section[1]
|
||||
header = data[15]
|
||||
elite_data_len = data[17]
|
||||
|
||||
if length <= 12:
|
||||
if length < 12:
|
||||
print("length < 12")
|
||||
print("green data print:", data, device, datetime.now())
|
||||
|
||||
# if length == 0:
|
||||
# self._print_ram_all_data()
|
||||
|
||||
if length <= 4:
|
||||
# print("length <= 4")
|
||||
# print("green data print:", data, device, datetime.now())
|
||||
return None
|
||||
|
||||
if data[5] != 0 or data[6] != 0:
|
||||
if green_data_section[2] != 0xA5 or green_data_section[3] != 0x5A:
|
||||
# give a default length if the data header did not update
|
||||
length = 7000
|
||||
print("green data: is not [0,0], = ", data[5:7])
|
||||
print("green data: is not [0xA5, 0x5A], = ", data[5:7])
|
||||
print("green data print:", data, device, datetime.now())
|
||||
return None
|
||||
|
||||
if (length >= 7000):
|
||||
if (length >= 4000):
|
||||
flag_print = True
|
||||
print("green data: big length:", length)
|
||||
|
||||
if (header != 255):
|
||||
flag_print = True
|
||||
print("green data: header is not 255: ", header)
|
||||
# self._print_ram_all_data()
|
||||
|
||||
if (elite_data_len != self._elite_data_len):
|
||||
flag_print = True
|
||||
print("green data: length is not", self._elite_data_len, ": ", elite_data_len)
|
||||
|
||||
if (flag_print):
|
||||
print("green data print:", data, device, datetime.now())
|
||||
print("green data print:", data, device, datetime.now(), '\n')
|
||||
|
||||
# neulive
|
||||
# address += len(data) - 11
|
||||
# tx_d = self._tx_buffer_data
|
||||
# red_length = len(tx_d)
|
||||
|
||||
# elite read all data of ram
|
||||
# address = 4
|
||||
# red_length = length - 1
|
||||
# tx_d = [0] * red_length
|
||||
|
||||
address = 4
|
||||
address = 12
|
||||
red_length = int(length / 2)
|
||||
tx_d = [0] * red_length
|
||||
|
||||
# elite read len(_tx_buffer_data) byte
|
||||
# address = 4
|
||||
# tx_d = self._tx_buffer_data
|
||||
tx_d = [0] * (red_length + 3)
|
||||
|
||||
while True:
|
||||
tx_d[0] = MEM_INS_READ
|
||||
@@ -319,22 +355,60 @@ class MultiExtMemSpiInterface(LowLevelHardwareInterface):
|
||||
address += len(data) - 3
|
||||
del data
|
||||
|
||||
# print("_[Debug] @ spi recv data rx = ")
|
||||
# last_index = 0
|
||||
# print("_[Debug] @ spi recv data rx, ram_select:", self._pin_ram_sel_value[device], ",", datetime.now())
|
||||
# for i in range(0, len(rx), self._single_data_len):
|
||||
# print(rx[i:i+self._single_data_len])
|
||||
# last_index = i
|
||||
# # print(rx[i:i+self._single_data_len])
|
||||
# if i == 0:
|
||||
# print(rx[0:8], 'ram:', rx[47])
|
||||
|
||||
# if last_index != 0:
|
||||
# print(rx[last_index:last_index+8], 'ram:', rx[last_index+47])
|
||||
# print()
|
||||
|
||||
# /*
|
||||
# * red data formate:
|
||||
# * ramHdr, ramHdr, ramHdr, (3B)
|
||||
# * 255, #, data_length, (3B)
|
||||
# * data, (20B)
|
||||
# * data, (40B)
|
||||
# * red_wrong, red_retry_cnt, green_wrong, green_retry_cnt, (4B)
|
||||
# * 255, #, data_length, (3B)
|
||||
# * check_num, (1B)
|
||||
# * */
|
||||
|
||||
# read again if check num is wrong
|
||||
index = 0
|
||||
check_number_print = False
|
||||
for i in range(0, len(rx), self._single_data_len):
|
||||
check_sum = sum(rx[i : i + self._single_data_len - 1]) & 0b11111111
|
||||
# print(check_sum, rx[i + self._single_data_len - 1])
|
||||
|
||||
if (check_sum != rx[i + self._single_data_len - 1]):
|
||||
# print('check_sum wrong, origin value:', 'check_sum =', check_sum, rx[i : i + self._single_data_len])
|
||||
tx_d = [0] * (self._single_data_len + 3)
|
||||
address = 12 + self._single_data_len * index
|
||||
tx_d[0] = MEM_INS_READ
|
||||
tx_d[1] = ((address >> 8) & 0xFF)
|
||||
tx_d[2] = (address & 0xFF)
|
||||
|
||||
data = []
|
||||
data = self._spi.send_byte(tx_d)
|
||||
data[0:3] = [255, 255, 255]
|
||||
rx[i : i + self._single_data_len] = data[3:]
|
||||
print('check_sum wrong, read again:', 'check_sum =', check_sum, rx[i : i + self._single_data_len])
|
||||
check_number_print = True
|
||||
index = index + 1
|
||||
|
||||
if check_number_print:
|
||||
print('check_sum wrong:', device, datetime.now())
|
||||
for i in range(0, len(rx), self._single_data_len):
|
||||
print(rx[i:i+self._single_data_len])
|
||||
print()
|
||||
|
||||
# mark read
|
||||
self._spi.send_byte(self.MEM_INS_MARKED)
|
||||
self._spi.send_byte(self.MEM_INS_MARKED1)
|
||||
self._spi.send_byte(self.MEM_INS_MARKED2)
|
||||
self._spi.send_byte(self.MEM_INS_MARKED3)
|
||||
|
||||
except BaseException as e:
|
||||
print(e)
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
|
||||
class Action():
|
||||
def __init__(self, task, action_id, action):
|
||||
self._task = task
|
||||
self._id:str = action_id
|
||||
self._type:str = action['type']
|
||||
self._target:str = action['target']
|
||||
self._condition_list:list[str] = action['condition']
|
||||
self._duration = action.get('duration', None)
|
||||
self._goto = action.get('goto', None)
|
||||
self._cycle = action.get('cycle', None)
|
||||
|
||||
self._instruction = None
|
||||
|
||||
self.update_instruction()
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return self._type
|
||||
|
||||
def update_instruction(self):
|
||||
self._instruction = {
|
||||
"device_instruction": {
|
||||
"header": "call_instruction",
|
||||
"device": self._target,
|
||||
"arguments": {
|
||||
"instruction": self._type,
|
||||
}
|
||||
},
|
||||
"device_parameter": {
|
||||
"header": "set_multi_parameters",
|
||||
"device": self._target,
|
||||
"arguments": {
|
||||
"parameter": self._task.get_parameter_set_by_device(self._target),
|
||||
}
|
||||
},
|
||||
"device_recording_file_name": {
|
||||
"header": "update_recording_file_name_info",
|
||||
"device": self._target,
|
||||
"arguments": {
|
||||
"content": self._task.file_name,
|
||||
}
|
||||
},
|
||||
"device_parent": {
|
||||
"header": "update_parent_info",
|
||||
"device": self._target,
|
||||
"arguments": {
|
||||
"content": self._task.parent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def get_condition_list(self):
|
||||
return self._condition_list
|
||||
|
||||
def get_instruction(self, value):
|
||||
return self._instruction[value]
|
||||
|
||||
def get_instruction_list(self):
|
||||
instruction_set = {
|
||||
'start': ['device_parent', 'device_recording_file_name', 'device_parameter', 'device_instruction'],
|
||||
'stop': ['device_instruction'],
|
||||
}
|
||||
|
||||
return map(self.get_instruction, instruction_set[self._type])
|
||||
@@ -0,0 +1,75 @@
|
||||
from datetime import datetime
|
||||
from time import time
|
||||
|
||||
class Condition():
|
||||
def __init__(self, id, condition):
|
||||
print('condition', id, condition)
|
||||
self._id = id
|
||||
self._type = condition['type']
|
||||
self._comparsion = condition['comparsion']
|
||||
self._value = condition['value']
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
return self._id
|
||||
@property
|
||||
def type(self):
|
||||
return self._type
|
||||
@property
|
||||
def comparsion(self):
|
||||
return self._comparsion
|
||||
@property
|
||||
def value(self):
|
||||
return self._value
|
||||
|
||||
def set_comparsion(self, comparsion):
|
||||
self._comparsion = comparsion
|
||||
|
||||
def set_type(self, type):
|
||||
self._type = type
|
||||
|
||||
def set_value(self, value):
|
||||
self._value = value
|
||||
|
||||
def compareWith(self, operator:str, x, y) -> bool:
|
||||
cases = {
|
||||
"equal": lambda a, b: a == b,
|
||||
"bigger": lambda a, b: a > b,
|
||||
"smaller": lambda a, b: a < b,
|
||||
}
|
||||
|
||||
# print('x','y',x, y,type(x),type(y))
|
||||
return cases[operator](x, y)
|
||||
|
||||
def match_or_not(self, **kwargs):
|
||||
return self.method_mapping(self.type)()
|
||||
|
||||
def absolute_time(self, **kwargs):
|
||||
now = time()
|
||||
time_condition = self.datetime_to_timestamp(self.str_to_datetime(self._value))
|
||||
|
||||
return self.compareWith(self.comparsion, int(now), int(time_condition))
|
||||
|
||||
def relative_time(self, **kwargs):
|
||||
now = time()
|
||||
|
||||
def device(self, **kwargs):
|
||||
print('device')
|
||||
|
||||
def task_status(self, **kwargs):
|
||||
print('task_status')
|
||||
|
||||
def method_mapping(self, method_name):
|
||||
methods = {
|
||||
"relative_time": self.relative_time,
|
||||
"absolute_time": self.absolute_time,
|
||||
"device": self.device,
|
||||
"task_status": self.task_status,
|
||||
}
|
||||
return methods[method_name]
|
||||
|
||||
def str_to_datetime(self, time_str):
|
||||
return datetime.strptime(time_str,'%Y-%m-%dT%H:%M')
|
||||
|
||||
def datetime_to_timestamp(self, date):
|
||||
return datetime.timestamp(date)
|
||||
@@ -0,0 +1,78 @@
|
||||
from .task import Task
|
||||
from .task_manager import TaskManager
|
||||
import sys
|
||||
import json
|
||||
import threading
|
||||
import time
|
||||
from datetime import datetime
|
||||
from collections import deque
|
||||
from biopro.device.manager import DeviceManager
|
||||
from biopro.text import *
|
||||
|
||||
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._task_manager = TaskManager(self._project['taskList'])
|
||||
|
||||
self._start_time = None
|
||||
|
||||
@property
|
||||
def desc(self) -> str:
|
||||
return self._project['desc']
|
||||
|
||||
@property
|
||||
def status(self) -> str:
|
||||
return self._project['status']
|
||||
|
||||
@property
|
||||
def device(self) -> list:
|
||||
return self._project['deviceList']
|
||||
|
||||
@property
|
||||
def task(self) -> list:
|
||||
return self._task_manager.get()
|
||||
|
||||
@property
|
||||
def get_current_task(self) -> str:
|
||||
return self._task_manager.get_current_task()
|
||||
|
||||
def run(self):
|
||||
self._start_time = time.time()
|
||||
|
||||
while True:
|
||||
# current task
|
||||
for task in self._task_manager.get_check_task_list():
|
||||
# [<match_condition>, ...]
|
||||
match_condition_list = task.check_condition('time')
|
||||
# [[<match_action>, ...], ...]
|
||||
match_action_list = task.get_match_action_list(match_condition_list)
|
||||
|
||||
for action_list in match_action_list:
|
||||
for action in action_list:
|
||||
if action.type == 'start':
|
||||
self._task_manager.set_current_task(task)
|
||||
task.do_action(action)
|
||||
|
||||
while len(task.instruction_list) > 0:
|
||||
instruction = task.instruction_list.pop(0)
|
||||
if instruction.get('device', None) != None:
|
||||
device = self._device_manager.get_device(self.device[instruction['device']]['connectDevice']['device_address'])
|
||||
|
||||
if device is None:
|
||||
raise RuntimeError(DEVICE_NOT_FOUND, device)
|
||||
|
||||
# print(instruction['header'], *instruction['arguments'].values())
|
||||
getattr(device, instruction['header'])(*instruction['arguments'].values())
|
||||
|
||||
time.sleep(self._time_interval)
|
||||
def stop(self):
|
||||
return
|
||||
|
||||
def close(self):
|
||||
return
|
||||
@@ -0,0 +1,33 @@
|
||||
from io import StringIO
|
||||
from json import loads as json_parse, dumps as _json_stringify
|
||||
from typing import Dict, Optional, Any
|
||||
import paho.mqtt.client as mqtt
|
||||
from .project import Project
|
||||
from biopro.device.manager import DeviceManager
|
||||
|
||||
def json_stringify(o: Any) -> str:
|
||||
return _json_stringify(o, separators=(',', ':'))
|
||||
|
||||
class ProjectManager():
|
||||
def __init__(self, device_manager: DeviceManager, mqtt_thread=None) :
|
||||
self._project_list = []
|
||||
self._mqtt_thread = mqtt_thread
|
||||
self._device_manager = device_manager
|
||||
|
||||
def create(self, project):
|
||||
new_project = Project(project, self._device_manager, self._mqtt_thread)
|
||||
self._project_list.append(new_project)
|
||||
return new_project
|
||||
|
||||
def remove(self, index):
|
||||
self._project_list[index].stop()
|
||||
del self._project_list[index]
|
||||
|
||||
def get(self):
|
||||
return self._project_list
|
||||
|
||||
def run(self, project):
|
||||
project.start()
|
||||
|
||||
def stop(self, project):
|
||||
project.stop()
|
||||
@@ -0,0 +1,168 @@
|
||||
from .condition import Condition
|
||||
from .action import Action
|
||||
from time import time
|
||||
|
||||
class Task:
|
||||
def __init__(self, task):
|
||||
self._task = task
|
||||
|
||||
self._condition_list = []
|
||||
self._action_list = []
|
||||
|
||||
self._start_time = time()
|
||||
self._idle_time = []
|
||||
self._period = None
|
||||
self._next_time = None
|
||||
self._last_time = None
|
||||
|
||||
self._instruction_list = []
|
||||
|
||||
self.setup()
|
||||
|
||||
def setup(self) -> None:
|
||||
# add condition
|
||||
for key, condition in self._task['condition'].items():
|
||||
new_condition = Condition(key, condition)
|
||||
self._condition_list.append(new_condition)
|
||||
|
||||
# add action
|
||||
for key, action in self._task['action'].items():
|
||||
new_action = Action(self, key, action)
|
||||
self._action_list.append(new_action)
|
||||
|
||||
@property
|
||||
def id(self) -> str:
|
||||
return self._task['id']
|
||||
|
||||
@property
|
||||
def file_name(self):
|
||||
return self._task['name']
|
||||
|
||||
@property
|
||||
def parent(self):
|
||||
return self._task.get('parent', {"folder": [2]})
|
||||
|
||||
@property
|
||||
def instruction_list(self):
|
||||
return self._instruction_list
|
||||
|
||||
@property
|
||||
def cycle(self) -> int:
|
||||
return self._task['cycle']
|
||||
|
||||
@property
|
||||
def order(self) -> int:
|
||||
return self._task['order']
|
||||
|
||||
@property
|
||||
def max_cycle(self) -> int:
|
||||
return self._task['max_cycle']
|
||||
|
||||
@property
|
||||
def devices(self) -> dict:
|
||||
return self._task['devices']
|
||||
|
||||
@property
|
||||
def devices_id(self) -> list:
|
||||
return [device_id for device_id in self.devices]
|
||||
|
||||
@property
|
||||
def events(self) -> list:
|
||||
return self._task['events']
|
||||
|
||||
@property
|
||||
def triggers(self) -> list:
|
||||
return self._task['triggers']
|
||||
|
||||
@property
|
||||
def parameter_set(self) -> list:
|
||||
return self._task['parameterSet']
|
||||
|
||||
@property
|
||||
def instructions(self) -> list:
|
||||
return self._task['instructions']
|
||||
|
||||
@property
|
||||
def conditions(self) -> list:
|
||||
return self._task['conditions']
|
||||
|
||||
@property
|
||||
def actions(self) -> list:
|
||||
return self._task['actions']
|
||||
|
||||
@property
|
||||
def condition_list(self) -> list:
|
||||
return self._condition_list
|
||||
|
||||
@property
|
||||
def status(self) -> str:
|
||||
return self._task['status']
|
||||
|
||||
@property
|
||||
def uuid(self) -> str:
|
||||
return self._task['uuid']
|
||||
|
||||
@property
|
||||
def next(self) -> str:
|
||||
return self._task['next']
|
||||
|
||||
def get_parameter_set_by_device(self, device):
|
||||
return [parameter_set for parameter_set in self.parameter_set.values() if device == parameter_set['target']]
|
||||
|
||||
def get_parameter(self, name_or_value, device):
|
||||
name_list = []
|
||||
value_list = []
|
||||
for parameter in self.get_parameter_set_by_device(device):
|
||||
for key, value in parameter.items():
|
||||
if key != 'target':
|
||||
name_list.append(key)
|
||||
value_list.append(str(value))
|
||||
|
||||
return '|'.join(name_list) if name_or_value == 'name' else '|'.join(value_list)
|
||||
|
||||
def run(self):
|
||||
self._status = 'running'
|
||||
self._start_time = time()
|
||||
|
||||
def pause(self):
|
||||
self._status = 'pause'
|
||||
|
||||
def set_cycle(self, cycle):
|
||||
self._cycle = cycle
|
||||
|
||||
def set_status(self, status):
|
||||
self._status = status
|
||||
|
||||
def start(self):
|
||||
self.set_status('running')
|
||||
|
||||
def stop(self):
|
||||
if self.status == 'running':
|
||||
self.do_action('stop')
|
||||
self.set_status('idle')
|
||||
|
||||
def done(self):
|
||||
self.set_status('done')
|
||||
|
||||
def end(self):
|
||||
self.set_status('end')
|
||||
|
||||
def get_match_action_list(self, match_condition_list):
|
||||
return map(lambda condition: [x for x in self._action_list if condition.id in x.get_condition_list()], match_condition_list)
|
||||
|
||||
def do_action(self, action):
|
||||
# # match_action = [x for x in self._action_list if condition_id in x.get_condition_list()]
|
||||
|
||||
# for action in match_action:
|
||||
for instruction in action.get_instruction_list():
|
||||
self._instruction_list.append(instruction)
|
||||
|
||||
def status_mapping(self, status):
|
||||
statuses = {
|
||||
"start": self.task_start,
|
||||
"done": self.task_done,
|
||||
}
|
||||
return statuses[status]
|
||||
|
||||
def check_condition(self, type):
|
||||
return [condition for condition in self._condition_list if condition.match_or_not()]
|
||||
@@ -0,0 +1,56 @@
|
||||
from json import loads as json_parse, dumps as _json_stringify
|
||||
from typing import Dict, Optional, Any
|
||||
from xml.dom.expatbuilder import parseString
|
||||
import paho.mqtt.client as mqtt
|
||||
from biopro.text import *
|
||||
from .task import Task
|
||||
|
||||
_RUNTIME_COMPILE = False
|
||||
|
||||
def json_stringify(o: Any) -> str:
|
||||
return _json_stringify(o, separators=(',', ':'))
|
||||
|
||||
class TaskManager():
|
||||
def __init__(self, task_list):
|
||||
self._current_task = None
|
||||
self._task_list = []
|
||||
self._need_to_check_task_list = []
|
||||
|
||||
for task in task_list:
|
||||
task = Task(task)
|
||||
self._task_list.append(task)
|
||||
|
||||
self.set_current_task(self._task_list[0])
|
||||
self._current_task.run()
|
||||
|
||||
def remove(self, index):
|
||||
pass
|
||||
|
||||
def get_task(self, task_id):
|
||||
return self._task_list[task_id]
|
||||
|
||||
def get_check_task_list(self):
|
||||
return self._need_to_check_task_list
|
||||
|
||||
def get_current_task(self) -> Task:
|
||||
return self._current_task
|
||||
|
||||
def get_next_task(self):
|
||||
return self._current_task.next
|
||||
|
||||
def set_current_task(self, task):
|
||||
try:
|
||||
if self._current_task != None and self._current_task.id != task.id:
|
||||
self._current_task.stop()
|
||||
|
||||
self._current_task = task
|
||||
self._need_to_check_task_list = []
|
||||
# append current task
|
||||
self._need_to_check_task_list.append(self._current_task)
|
||||
|
||||
# append next task
|
||||
for task_uuid in self._current_task.next:
|
||||
task = next((task for task in self._task_list if task.uuid == task_uuid), None)
|
||||
self._need_to_check_task_list.append(task)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
@@ -8,6 +8,7 @@ import gc
|
||||
|
||||
from biopro.util.json import JSON
|
||||
from biopro.util.stack import print_exception
|
||||
from biopro.util.logger import calculate_time
|
||||
from .data import RecordingData
|
||||
from .loader import *
|
||||
|
||||
@@ -19,6 +20,8 @@ from statistics import mean
|
||||
import random
|
||||
# from numba import jit
|
||||
|
||||
from copy import copy
|
||||
|
||||
def json_stringify(o) -> str:
|
||||
return _json_stringify(o, separators=(',', ':'))
|
||||
|
||||
@@ -113,8 +116,8 @@ class RecordingMetaFile(JsonSerialize):
|
||||
__slots__ = ('_filename', '_filepath', '_id_db', '_create_time', '_file_version', '_file_uuid', '_data_format', '_last_time',
|
||||
'_device', '_configuration', '_channel_mask', '_database',
|
||||
'_dirty', '_last_modify_time', '_file_size_cache',
|
||||
'_recording_file_ch', '_recording_sub_file', '_size',
|
||||
'_parameter', '_parent', '_recording_file_name', '_recording_sub_mini', '_recording_mini_ch',
|
||||
'_recording_file_ch', '_size',
|
||||
'_parameter', '_parent', '_recording_file_name', '_recording_mini_ch',
|
||||
'_raw_serial_number', '_mini_serial_number', '_device_id')
|
||||
|
||||
def __init__(self, filepath: Union[str, Path], data_format: bytes = None, id_db = 0, database = None):
|
||||
@@ -165,10 +168,6 @@ class RecordingMetaFile(JsonSerialize):
|
||||
self._raw_serial_number = {}
|
||||
self._mini_serial_number = {}
|
||||
|
||||
self._recording_sub_file = {}
|
||||
self._recording_sub_mini = {}
|
||||
|
||||
|
||||
self._size = 0
|
||||
|
||||
self._dirty = True
|
||||
@@ -306,7 +305,6 @@ class RecordingMetaFile(JsonSerialize):
|
||||
if database is not None :
|
||||
self._database = database
|
||||
self._database.put_queue(['data_meta_write', meta_data, self._device_id, str(self._file_uuid), self._id_db])
|
||||
# database.put_queue(['data_meta_write', self, meta_data, _path, self._id_db])
|
||||
|
||||
with self._filepath.open('wb') as _f:
|
||||
f = FileEncoder(_f)
|
||||
@@ -356,19 +354,15 @@ class RecordingMetaFile(JsonSerialize):
|
||||
|
||||
def update_subfile(self, database = None):
|
||||
meta_data = {
|
||||
'raw_data': self._recording_sub_file,
|
||||
'mini_data': self._recording_sub_mini,
|
||||
'channels': str(self._channel_mask.channels()),
|
||||
'size': str(self._size),
|
||||
'time_duration': str(self._last_time),
|
||||
'uuid': str(self._file_uuid),
|
||||
}
|
||||
_path = str(self._filepath).replace('/', '^')
|
||||
|
||||
if database is not None :
|
||||
self._database = database
|
||||
self._database.put_queue(['data_meta_write', meta_data, self._device_id, str(self._file_uuid), self._id_db])
|
||||
# database.put_queue(['data_meta_write', self, meta_data, _path, self._id_db])
|
||||
return None
|
||||
|
||||
@property
|
||||
@@ -517,11 +511,6 @@ class RecordingMetaFile(JsonSerialize):
|
||||
'start_time': str(_start_time),
|
||||
}
|
||||
|
||||
# if database is not None:
|
||||
# database.data_raw_create(self, f, raw_data, _channel)
|
||||
|
||||
# self._recording_file_ch[_channel]
|
||||
|
||||
return f, raw_data
|
||||
|
||||
def new_recording_mini(self, _channel: int, _start_time, scale, database = None) -> 'RecordingMini':
|
||||
@@ -567,9 +556,6 @@ class RecordingMetaFile(JsonSerialize):
|
||||
'start_time': str(_start_time),
|
||||
}
|
||||
|
||||
# if database is not None:
|
||||
# database.data_mini_create(self, f, mini_data, _channel, scale)
|
||||
|
||||
return f, mini_data
|
||||
|
||||
def clear_recording_file(self):
|
||||
@@ -628,15 +614,6 @@ class RecordingMetaFile(JsonSerialize):
|
||||
'device': self._device,
|
||||
}
|
||||
|
||||
# d = self._device
|
||||
|
||||
# if d is not None:
|
||||
# ret['device'] = {
|
||||
# 'device_name': d.device_name,
|
||||
# 'device_address': list(d.mac_address),
|
||||
# 'serial_number': d.serial_number.as_json(),
|
||||
# }
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
@@ -792,14 +769,10 @@ class RecordingFile:
|
||||
'end_time': str(_end_time),
|
||||
'size': str(self._size)
|
||||
}
|
||||
# if self._meta_file._id_db == 0:
|
||||
# _path = str(self._meta_file.filepath).replace('/', '^')
|
||||
# self._database.put_queue(['data_meta_id_get_by_path', _path])
|
||||
# # self._meta_file._id_db = self._database.put_queue(['data_meta_id_get_by_path', _path])
|
||||
|
||||
if self._meta_file._id_db != 0:
|
||||
_data['parent'] = self._meta_file._id_db
|
||||
self._database.put_queue(['data_raw_update', self._id_db, self._channel, _data])
|
||||
# self._database.put_queue(['data_raw_update', self._id_db, self._channel, _data])
|
||||
self._status = False
|
||||
return None
|
||||
|
||||
@@ -965,10 +938,7 @@ class RecordingMini:
|
||||
'end_time': str(_end_time),
|
||||
'size': str(self._size)
|
||||
}
|
||||
# if self._meta_file._id_db == 0:
|
||||
# _path = str(self._meta_file.filepath).replace('/', '^')
|
||||
# self._database.put_queue(['data_meta_id_get_by_path', _path])
|
||||
# # self._meta_file._id_db = self._database.put_queue(['data_meta_id_get_by_path', _path])
|
||||
|
||||
if self._meta_file._id_db != 0:
|
||||
_data['parent'] = self._meta_file._id_db
|
||||
self._database.put_queue(['data_mini_update', self._id_db, self._channel, _data])
|
||||
@@ -996,7 +966,8 @@ class RecordingFileWriter:
|
||||
'_data_value_ch', '_close', '_data_mini_ch',
|
||||
'_mini_scale_list', '_time_real_time', '_data_rl', '_data_db',
|
||||
'_raw_save', '_mini_save', '_data_time_ch', '_data_value_ch_for_rl',
|
||||
'_data_time_ch_for_rl', '_device_id', '_send_data', '_data_mqtt_ch')
|
||||
'_data_time_ch_for_rl', '_device_id', '_send_data', '_data_mqtt_ch', '_id_db_save', '_raw_create_not_done',
|
||||
'_mini_create_not_done')
|
||||
|
||||
def __init__(self, meta: RecordingMetaFile, device_id, database = None):
|
||||
self._meta = meta
|
||||
@@ -1017,7 +988,9 @@ class RecordingFileWriter:
|
||||
|
||||
self._raw_save = {
|
||||
'id': {},
|
||||
'data': {}
|
||||
'data': {},
|
||||
'end_time': {},
|
||||
'size': {}
|
||||
}
|
||||
self._mini_save = {
|
||||
'10': {
|
||||
@@ -1052,6 +1025,7 @@ class RecordingFileWriter:
|
||||
self._data_value_ch_for_rl = {}
|
||||
self._data_time_ch_for_rl = {}
|
||||
self._data_time_ch = {}
|
||||
self._id_db_save = {}
|
||||
|
||||
# mini data
|
||||
self._data_mini_ch = {}
|
||||
@@ -1068,12 +1042,15 @@ class RecordingFileWriter:
|
||||
|
||||
# splitting
|
||||
self.splitting_threshold_time = 30 * 60 * 1000 # one minute
|
||||
self.splitting_threshold_size = 16 * 16 * 1024 # 16 * 16KB
|
||||
self.splitting_threshold_size = 16 * 1024 # 16 * 16KB
|
||||
|
||||
self._writer_batch_size = 8192
|
||||
|
||||
self._splitting_size = None
|
||||
|
||||
self._raw_create_not_done = True
|
||||
self._mini_create_not_done = True
|
||||
|
||||
|
||||
@property
|
||||
def meta_file(self) -> RecordingMetaFile:
|
||||
@@ -1094,6 +1071,7 @@ class RecordingFileWriter:
|
||||
|
||||
def channels_update(self, channels):
|
||||
channels.sort()
|
||||
self._database.put_queue(['data_meta_update_raw_empty_channel', self._meta._id_db, channels])
|
||||
self._channel_list.extend(channels)
|
||||
return self._channel_list
|
||||
|
||||
@@ -1107,9 +1085,6 @@ class RecordingFileWriter:
|
||||
return None
|
||||
|
||||
def close(self):
|
||||
# if self._recording_file is not None:
|
||||
# self._recording_file.close()
|
||||
# self._recording_file = None
|
||||
print('close1')
|
||||
self._close = True
|
||||
if len(self._recording_file_dict) > 0:
|
||||
@@ -1123,7 +1098,7 @@ class RecordingFileWriter:
|
||||
self._meta._size += self._recording_file_dict[ch]._size
|
||||
# self._data_db.clear()
|
||||
if self._database is not None:
|
||||
self._database.put_queue(['data_raw_recording', self._raw_save['id'], self._channel_list, self._raw_save['data']])
|
||||
self._database.put_queue(['data_raw_recording', self._raw_save['id'], self._channel_list, self._raw_save['data'], self._id_db_save])
|
||||
# self._database.put_queue(['data_raw_recording', self._raw_save['id'], self._channel_list, self._raw_save['data']])
|
||||
self._recording_file_dict.clear()
|
||||
for scale in self._mini_scale_list:
|
||||
@@ -1289,7 +1264,8 @@ class RecordingFileWriter:
|
||||
self._data_db[c].append(str(v))
|
||||
self._time_now = int(t)
|
||||
return
|
||||
|
||||
|
||||
@calculate_time(1)
|
||||
def write(self, data: Union[bytes, RecordingData, List[bytes], List[RecordingData]], mqtt_thread) -> int:
|
||||
# check size
|
||||
ths = self.splitting_threshold_size
|
||||
@@ -1348,42 +1324,62 @@ class RecordingFileWriter:
|
||||
|
||||
self.get_data_iter(d, mqtt_thread)
|
||||
|
||||
data_save = False
|
||||
mini_save = False
|
||||
if len(self._recording_file_dict) > 0:
|
||||
for ch in self._data_db.keys():
|
||||
if self._time_now - self._time_real_time[ch] > 1000000:
|
||||
self._send_data[ch] = True
|
||||
self._time_real_time[ch] = self._time_now
|
||||
# # if self._time_now - self._time_real_time[ch] > 500000:
|
||||
# self._data_rl[ch].append(str(self._time_now))
|
||||
# mes = ' '.join(self._data_rl[ch])
|
||||
# # print(mes)
|
||||
# # if mqtt_thread is not None:
|
||||
# # mqtt_thread.publish('data_server/device_data_stream/' + str(self._device_id) + '/' + str(ch), mes)
|
||||
# # mqtt_queue.put([self._device_id, ch, mes])
|
||||
# mqtt_thread[ch].on_message(mes)
|
||||
# self._data_rl[ch].clear()
|
||||
# # self._time_real_time[ch] = self._time_now
|
||||
|
||||
for ch in self._recording_file_dict:
|
||||
if self._recording_file_dict[ch]._id_db == 0:
|
||||
return None
|
||||
|
||||
for ch in self._data_db.keys():
|
||||
for scale in self._mini_scale_list:
|
||||
if self._recording_mini_dict[str(scale)][ch]._id_db == 0:
|
||||
return None
|
||||
|
||||
if self._raw_create_not_done :
|
||||
self._raw_create_not_done = False
|
||||
raw_id_dict = {}
|
||||
for ch in self._data_db.keys():
|
||||
raw_id_dict[ch] = self._recording_file_dict[ch]._id_db
|
||||
self._database.put_queue(['data_meta_update_all_channel_raw_id', self._meta._id_db, raw_id_dict])
|
||||
|
||||
if self._mini_create_not_done :
|
||||
self._mini_create_not_done = False
|
||||
mini_id_dict = {}
|
||||
for ch in self._data_db.keys():
|
||||
mini_id_dict[ch] = {}
|
||||
for scale in self._mini_scale_list:
|
||||
mini_id_dict[ch][scale] = self._recording_mini_dict[str(scale)][ch]._id_db
|
||||
self._database.put_queue(['data_meta_update_all_channel_mini_id', self._meta._id_db, mini_id_dict])
|
||||
|
||||
data_save = False
|
||||
mini_save = False
|
||||
if len(self._recording_file_dict) > 0:
|
||||
for ch in self._data_db.keys():
|
||||
if self._time_now - self._time[ch] > 5000000:
|
||||
if self._recording_file_dict[ch]._status:
|
||||
_data = ' '.join(self._data_db[ch])
|
||||
write_sz = self._recording_file_dict[ch].write(_data, self._channel_list)
|
||||
sz = sz + write_sz
|
||||
self._raw_save['data'][ch] = _data
|
||||
self._raw_save['id'][ch] = self._recording_file_dict[ch]._id_db
|
||||
data_save = True
|
||||
self._raw_save['end_time'][ch] = self._time_now
|
||||
self._raw_save['size'][ch] = self._recording_file_dict[ch]._size
|
||||
self._data_db[ch].clear()
|
||||
self._time[ch] = self._time_now
|
||||
self._splitting_size += sz
|
||||
self._meta._last_time = self._time_now
|
||||
self._recording_file_dict[ch].update_endtime(self._time_now)
|
||||
if len(self._data_mini_ch[ch]['1000']['mean']) >= 10:
|
||||
self._splitting_size += write_sz
|
||||
data_save = True
|
||||
if len(self._data_mini_ch[ch]['1000']['mean']) >= 1:
|
||||
mini_save = True
|
||||
for scale in self._mini_scale_list:
|
||||
str_mean = [str(int) for int in self._data_mini_ch[ch][str(scale)]['mean']]
|
||||
data_mean = str(self._data_mini_ch[ch][str(scale)]['start_time']) + ' ' + ' '.join(str_mean) + '"***"'
|
||||
self._mini_save[str(scale)]['id'][ch] = self._recording_mini_dict[str(scale)][ch]._id_db
|
||||
self._mini_save[str(scale)]['start_time'][ch] = str(self._data_mini_ch[ch][str(scale)]['start_time'])
|
||||
self._mini_save[str(scale)]['data_mean'][ch] = self._data_mini_ch[ch][str(scale)]['mean'].copy()
|
||||
self._mini_save[str(scale)]['data_mean'][ch] = data_mean
|
||||
# self._mini_save[str(scale)]['data_random'][ch] = self._data_mini_ch[ch][str(scale)]['random'].copy()
|
||||
# self._mini_save[str(scale)]['data_bar'][ch] = self._data_mini_ch[ch][str(scale)]['bar'].copy()
|
||||
self._recording_mini_dict[str(scale)][ch].write(self._mini_save[str(scale)]['data_mean'][ch])
|
||||
@@ -1394,26 +1390,25 @@ class RecordingFileWriter:
|
||||
|
||||
if data_save is True:
|
||||
if self._database is not None:
|
||||
self._database.put_queue(['data_raw_recording', self._raw_save['id'], self._channel_list, self._raw_save['data']])
|
||||
recording_input = ['data_raw_recording_new', copy(self._raw_save['id']), copy(self._channel_list), copy(self._raw_save['data']), copy(self._raw_save['end_time']), copy(self._raw_save['size'])]
|
||||
self._database.put_queue(recording_input)
|
||||
self._meta.update_subfile(database = self._database)
|
||||
if mini_save is True:
|
||||
if self._database is not None:
|
||||
for scale in self._mini_scale_list:
|
||||
self._database.put_queue(['data_mini_recording', self._mini_save[str(scale)]['id'], self._channel_list, self._mini_save[str(scale)]['start_time'], self._mini_save[str(scale)]['data_mean']])
|
||||
self._database.put_queue(['data_mini_recording_new', copy(self._mini_save[str(scale)]['id']), self._channel_list, copy(self._mini_save[str(scale)]['data_mean'])])
|
||||
self._meta.update_subfile(database = self._database)
|
||||
|
||||
|
||||
del data
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def _switch_recording_file(self):
|
||||
# if self._recording_file is not None:
|
||||
# self._recording_file.close()
|
||||
|
||||
self._raw_create_not_done = True
|
||||
|
||||
if len(self._recording_file_dict) > 0:
|
||||
for ch in self._recording_file_dict.keys():
|
||||
self._id_db_save[ch] = self._recording_file_dict[ch]._id_db
|
||||
self._recording_file_dict[ch].close(self._time_now)
|
||||
self._meta._size += self._recording_file_dict[ch]._size
|
||||
|
||||
@@ -1429,7 +1424,6 @@ class RecordingFileWriter:
|
||||
|
||||
if self._database is not None:
|
||||
self._database.put_queue(['data_raw_create', raw_data_dict, self._channel_list, self._device_id])
|
||||
# self._database.put_queue(['data_raw_create', self._meta, self._recording_file_dict, raw_data_dict, self._channel_list])
|
||||
|
||||
self._meta._last_time = self._time_now
|
||||
self._meta.update_subfile(database = self._database)
|
||||
@@ -1439,6 +1433,7 @@ class RecordingFileWriter:
|
||||
return None
|
||||
|
||||
def _switch_recording_mini(self, scale):
|
||||
self._mini_create_not_done = True
|
||||
|
||||
if len(self._recording_mini_dict[str(scale)]) > 0:
|
||||
for ch in self._recording_mini_dict[str(scale)].keys():
|
||||
@@ -1456,29 +1451,21 @@ class RecordingFileWriter:
|
||||
|
||||
if self._database is not None:
|
||||
self._database.put_queue(['data_mini_create', mini_data_dict, self._channel_list, scale, self._device_id])
|
||||
# self._database.put_queue(['data_mini_create', self._meta, self._recording_mini_dict[str(scale)], mini_data_dict, self._channel_list, scale])
|
||||
|
||||
self._meta._last_time = self._time_now
|
||||
self._meta.update_subfile(database = self._database)
|
||||
return None
|
||||
|
||||
def update_meta_id(self, _id):
|
||||
# print('update meta')
|
||||
self._meta._id_db = _id
|
||||
return None
|
||||
|
||||
def update_raw_dict_id(self, _channel, _id):
|
||||
self._recording_file_dict[int(_channel)]._id_db = _id
|
||||
if int(_channel) not in self._meta._recording_sub_file:
|
||||
self._meta._recording_sub_file[int(_channel)] = []
|
||||
self._meta._recording_sub_file[int(_channel)].append(_id)
|
||||
# self._database.put_queue(['data_meta_update_channel_raw_id', self._meta._id_db, _channel, _id])
|
||||
return None
|
||||
|
||||
def update_mini_dict_id(self, _scale, _channel, _id):
|
||||
self._recording_mini_dict[str(_scale)][int(_channel)]._id_db = _id
|
||||
if int(_channel) not in self._meta._recording_sub_mini:
|
||||
self._meta._recording_sub_mini[int(_channel)] = {}
|
||||
if int(_scale) not in self._meta._recording_sub_mini[int(_channel)]:
|
||||
self._meta._recording_sub_mini[int(_channel)][int(_scale)] = []
|
||||
self._meta._recording_sub_mini[int(_channel)][int(_scale)].append(_id)
|
||||
# self._database.put_queue(['data_meta_update_channel_mini_id', self._meta._id_db, _channel, _scale, _id])
|
||||
return None
|
||||
@@ -1335,3 +1335,6 @@ def to_device_info(content: Union[str, ADDRESS, JSON_OBJECT]) -> DeviceResponseI
|
||||
return DeviceResponseInfo(None,
|
||||
serial_number=serial,
|
||||
mac_address=address)
|
||||
|
||||
def run_project(self, project) -> bool:
|
||||
return False
|
||||
|
||||
@@ -126,6 +126,9 @@ class DataServer(SocketServer, DataAPI):
|
||||
self.database_process = DataBaseProcess('data_server', self.log_verbose, self._queue_db, self._queue_ds_dict, self._queue_db_error)
|
||||
self.database_process.start()
|
||||
|
||||
self._no_data_total_duration = 0
|
||||
self._recv_memory_cost_time = 0
|
||||
|
||||
@logging_info
|
||||
def setup(self):
|
||||
self._available_channel.clear()
|
||||
@@ -669,7 +672,13 @@ class DataServer(SocketServer, DataAPI):
|
||||
print("q size= ", self._configurations[device]._queue_rec.qsize())
|
||||
|
||||
self._configurations[device].put_rec_queue(data)
|
||||
self._no_data_total_duration = 0
|
||||
ret = True
|
||||
else:
|
||||
time_diff = time() - self._recv_memory_cost_time
|
||||
self._no_data_total_duration += time_diff
|
||||
print('data is None', device, datetime.now(), self._no_data_total_duration)
|
||||
self._recv_memory_cost_time = time()
|
||||
|
||||
return ret
|
||||
|
||||
@@ -1179,20 +1188,20 @@ class SpiRuntimeThread(ServerThread):
|
||||
|
||||
run_time = time() - self._timer
|
||||
|
||||
real_run_time = run_time
|
||||
|
||||
if run_time > 0.045:
|
||||
print('time, recv_data_form_spi_routine_time', time(), run_time)
|
||||
# print('time, recv_data_form_spi_routine_time', time(), run_time)
|
||||
run_time = 0.045
|
||||
|
||||
if server.sync_started:
|
||||
event.wait(self._interval - run_time)
|
||||
sync.set_pin_mem_sel(True)
|
||||
sleep(0.005)
|
||||
return
|
||||
else:
|
||||
event.wait(self._interval - run_time)
|
||||
sync.set_pin_mem_sel(True)
|
||||
self.close()
|
||||
return
|
||||
if run_time >= 0.030:
|
||||
print('time, recv_data_form_spi_routine_time >= 0.030', 'device:', c, datetime.now(), time(), real_run_time)
|
||||
|
||||
event.wait(self._interval - run_time)
|
||||
sync.set_pin_mem_sel(True)
|
||||
sleep(0.005)
|
||||
|
||||
return
|
||||
|
||||
class RecRuntimeThread(ServerThread):
|
||||
def __init__(self, server: DataServer):
|
||||
|
||||
@@ -15,13 +15,15 @@ from biopro.util.json import JSON_OBJECT
|
||||
from .socket import ServerThread
|
||||
|
||||
import psycopg2
|
||||
# from psycopg2.pool import ThreadedConnectionPool
|
||||
from psycopg2.extras import execute_batch
|
||||
from multiprocessing import Process, Queue
|
||||
|
||||
import biopro.server._identify
|
||||
|
||||
from time import time
|
||||
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
from biopro.util.logger import calculate_time
|
||||
|
||||
_RUNTIME_COMPILE = False
|
||||
|
||||
@@ -50,7 +52,7 @@ class DataBaseProcess(Process):
|
||||
self._api_token = None
|
||||
self._api_header = None
|
||||
self.log_verbose = log_verbose
|
||||
self._executor = ThreadPoolExecutor(max_workers=4)
|
||||
self._executor = ThreadPoolExecutor(max_workers=8)
|
||||
|
||||
self._psql_multi_thread = None
|
||||
self._psql_conn_pool = None
|
||||
@@ -62,6 +64,14 @@ class DataBaseProcess(Process):
|
||||
|
||||
self._is_close = False
|
||||
|
||||
|
||||
self._meta_write_sql_str = None
|
||||
|
||||
self._data_raw_create_sql_str = None
|
||||
self._data_raw_update_sql_str = None
|
||||
self._data_raw_recording_sql_str = 'UPDATE "public"."%s_recording_data_raws" SET data = concat(data, %s), end_time=%s, size=%s where id = %s'
|
||||
self._data_mini_recording_sql_str = 'UPDATE "public"."%s_recording_data_minis" SET data_mean = concat(data_mean, %s) where id = %s'
|
||||
|
||||
@property
|
||||
def db_host(self) -> str:
|
||||
return self._db_host
|
||||
@@ -149,7 +159,8 @@ class DataBaseProcess(Process):
|
||||
if callable(getattr(self, do)):
|
||||
getattr(self, do)(*args)
|
||||
return None
|
||||
|
||||
|
||||
@calculate_time(1)
|
||||
def data_meta_write(self, _data: JSON_OBJECT, device_id, _uuid = None, _id = None):
|
||||
if _id > 0:
|
||||
sql_str = 'UPDATE "public"."recording_data_metas" SET '
|
||||
@@ -252,6 +263,7 @@ class DataBaseProcess(Process):
|
||||
# _conn.close()
|
||||
return None
|
||||
|
||||
# @calculate_time
|
||||
def data_meta_get(self, _path = None, _id = None):
|
||||
if _id is not None:
|
||||
sql_str = 'SELECT * FROM "public"."recording_data_metas" WHERE id = %s'
|
||||
@@ -286,6 +298,7 @@ class DataBaseProcess(Process):
|
||||
# _conn.close()
|
||||
return None
|
||||
|
||||
# @calculate_time
|
||||
def data_meta_id_get_by_path(self, _path = None):
|
||||
ret = None
|
||||
if _path is not None:
|
||||
@@ -307,39 +320,29 @@ class DataBaseProcess(Process):
|
||||
# _conn.close()
|
||||
return None
|
||||
|
||||
# @calculate_time
|
||||
def data_raw_create(self, _data_dict, _channel_list, device_id):
|
||||
|
||||
for _channel in _channel_list:
|
||||
sql_str = 'INSERT INTO "public"."' + str(_channel) + '_recording_data_raws" ('
|
||||
sql_set = []
|
||||
for item in _data_dict[_channel].keys():
|
||||
sql_str = sql_str + str(item) + ', '
|
||||
if isinstance(_data_dict[_channel][item], dict):
|
||||
sql_set.append(json_stringify(_data_dict[_channel][item]))
|
||||
else:
|
||||
sql_set.append(str(_data_dict[_channel][item]))
|
||||
|
||||
sql_str = sql_str[0:-2] + ') VALUES ('
|
||||
for item in _data_dict[_channel].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 RuntimeError as e:
|
||||
print('data_raw_create error', e)
|
||||
self._psql_conn.commit()
|
||||
sql_cursor.close()
|
||||
self._queue_error.put(device_id)
|
||||
finally:
|
||||
self._queue_ds[int(device_id)].put(['update_raw_dict_id', _data_dict[_channel]['uuid'], _channel, int(sql_cursor.fetchone()[0])])
|
||||
self._psql_conn.commit()
|
||||
sql_cursor.close()
|
||||
if self._data_raw_create_sql_str == None:
|
||||
sql_str_list = []
|
||||
key_list = _data_dict[_channel_list[0]].keys()
|
||||
key_str = ','.join(key_list)
|
||||
values = ','.join(['%s'] * len(key_list))
|
||||
sql_str_list = ['INSERT INTO "public"."{channel}_recording_data_raws" (', key_str, ') VALUES (', values, ') RETURNING id']
|
||||
self._data_raw_create_sql_str = ''.join(sql_str_list)
|
||||
try:
|
||||
with self._psql_conn as conn:
|
||||
with conn.cursor() as sql_cursor:
|
||||
for _channel in _channel_list:
|
||||
sql_set = list(map(lambda x: str(x), _data_dict[_channel].values()))
|
||||
sql_cursor.execute(self._data_raw_create_sql_str.format(channel = _channel), sql_set)
|
||||
self._queue_ds[int(device_id)].put(['update_raw_dict_id', _data_dict[_channel]['uuid'], _channel, int(sql_cursor.fetchone()[0])])
|
||||
except (psycopg2.Error, RuntimeError) as e:
|
||||
print('data_raw_create error', e)
|
||||
self._queue_error.put(device_id)
|
||||
|
||||
return True
|
||||
|
||||
# @calculate_time
|
||||
def data_raw_update(self, _id, _channel, _data: JSON_OBJECT):
|
||||
sql_str = 'UPDATE "public"."' + str(_channel) + '_recording_data_raws" SET '
|
||||
sql_set = []
|
||||
@@ -357,30 +360,36 @@ class DataBaseProcess(Process):
|
||||
sql_cursor.execute(sql_str, sql_set)
|
||||
self._psql_conn.commit()
|
||||
sql_cursor.close()
|
||||
|
||||
return None
|
||||
|
||||
def data_raw_recording(self, _id_dict, _channel_list, _data_dict):
|
||||
for _channel in _channel_list:
|
||||
compressed_value = _data_dict[_channel] + '"***"'
|
||||
# compressed_value = bytes(_data_dict[_channel],'utf-8')
|
||||
# compressed_value = zlib.compress(compressed_value)
|
||||
# compressed_value = base64.b64encode(compressed_value).decode() + '"***"'
|
||||
# compressed_value = _data + '"***"'
|
||||
sql_str = 'UPDATE "public"."' + str(_channel) + '_recording_data_raws" SET data = concat(data, %s) where id = %s'
|
||||
sql_set = [compressed_value, _id_dict[_channel]]
|
||||
|
||||
sql_cursor = self._psql_conn.cursor()
|
||||
sql_cursor.execute(sql_str, sql_set)
|
||||
self._psql_conn.commit()
|
||||
sql_cursor.close()
|
||||
|
||||
del _data_dict[_channel]
|
||||
del compressed_value
|
||||
gc.collect()
|
||||
# _conn.close()
|
||||
# @calculate_time
|
||||
def data_raw_recording(self, _id_dict, _channel_list, _data_dict, _id_db_save):
|
||||
try:
|
||||
with self._psql_conn as conn:
|
||||
with conn.cursor() as sql_cursor:
|
||||
para_list = []
|
||||
for _channel in _channel_list:
|
||||
temp_id = _id_dict[_channel] if _id_dict[_channel] != 0 else _id_db_save[_channel]
|
||||
para_list.append([_channel, _data_dict[_channel] + '"***"', temp_id])
|
||||
execute_batch(sql_cursor, self._data_raw_recording_sql_str, para_list)
|
||||
except psycopg2.Error as e:
|
||||
print('recording error', e)
|
||||
return None
|
||||
|
||||
|
||||
@calculate_time(1)
|
||||
def data_raw_recording_new(self, _id_dict, _channel_list, _data_dict, _end_time_dict, _size_dict):
|
||||
try:
|
||||
para_list = []
|
||||
for _channel in _channel_list:
|
||||
para_list.append([_channel, _data_dict[_channel] + '"***"', _end_time_dict[_channel], _size_dict[_channel], _id_dict[_channel]])
|
||||
with self._psql_conn as conn:
|
||||
with conn.cursor() as sql_cursor:
|
||||
execute_batch(sql_cursor, self._data_raw_recording_sql_str, para_list)
|
||||
except psycopg2.Error as e:
|
||||
print('recording error', e)
|
||||
return None
|
||||
|
||||
# @calculate_time
|
||||
def data_mini_create(self, _data_dict, _channel_list, _scale, device_id):
|
||||
for _channel in _channel_list:
|
||||
sql_str = 'INSERT INTO "public"."' + str(_channel) + '_recording_data_minis" ('
|
||||
@@ -414,42 +423,43 @@ class DataBaseProcess(Process):
|
||||
# _conn.close()
|
||||
return True
|
||||
|
||||
# @calculate_time
|
||||
def data_mini_recording(self, _id_dict, _channel_list, _start_time_dict, _data_mean_dict):
|
||||
for _channel in _channel_list:
|
||||
data = _data_mean_dict.get(_channel)
|
||||
if data is not None:
|
||||
if len(data) != 0:
|
||||
str_mean = [str(int) for int in _data_mean_dict[_channel]]
|
||||
data_mean = _start_time_dict[_channel] + ' ' + ' '.join(str_mean)
|
||||
# data_random = _start_time_dict[_channel] + ' ' + ' '.join(_data_random_dict[_channel])
|
||||
# data_bar = _start_time_dict[_channel] + ' ' + ' '.join(_data_bar_dict[_channel])
|
||||
with self._psql_conn as conn:
|
||||
with self._psql_conn.cursor() as sql_cursor:
|
||||
for _channel in _channel_list:
|
||||
data = _data_mean_dict.get(_channel)
|
||||
if data is not None:
|
||||
if len(data) != 0:
|
||||
str_mean = [str(int) for int in _data_mean_dict[_channel]]
|
||||
data_mean = _start_time_dict[_channel] + ' ' + ' '.join(str_mean)
|
||||
|
||||
compressed_mean = data_mean + '"***"'
|
||||
|
||||
# compressed_mean = bytes(data_mean,'utf-8')
|
||||
# compressed_mean = zlib.compress(compressed_mean)
|
||||
# compressed_mean = base64.b64encode(compressed_mean).decode() + '"***"'
|
||||
|
||||
# compressed_random = bytes(data_bar,'utf-8')
|
||||
# compressed_random = zlib.compress(compressed_random)
|
||||
# compressed_random = base64.b64encode(compressed_random).decode() + '"***"'
|
||||
|
||||
# compressed_random = bytes(data_random,'utf-8')
|
||||
# compressed_random = zlib.compress(compressed_random)
|
||||
# compressed_random = base64.b64encode(compressed_random).decode() + '"***"'
|
||||
sql_str = 'UPDATE "public"."' + str(_channel) + '_recording_data_minis" SET data_mean = concat(data_mean, %s) where id = %s'
|
||||
sql_set = [compressed_mean, _id_dict[_channel]]
|
||||
|
||||
sql_cursor = self._psql_conn.cursor()
|
||||
sql_set = [data_mean + '"***"', _id_dict[_channel]]
|
||||
sql_cursor.execute(sql_str, sql_set)
|
||||
self._psql_conn.commit()
|
||||
sql_cursor.close()
|
||||
|
||||
del str_mean, _start_time_dict[_channel], _data_mean_dict[_channel], data_mean, compressed_mean
|
||||
gc.collect()
|
||||
del str_mean, data_mean
|
||||
|
||||
for _channel in _channel_list:
|
||||
del _start_time_dict[_channel], _data_mean_dict[_channel]
|
||||
gc.collect()
|
||||
|
||||
return True
|
||||
|
||||
@calculate_time(1)
|
||||
def data_mini_recording_new(self, _id_dict, _channel_list, _data_mean_dict):
|
||||
try:
|
||||
para_list = []
|
||||
for _channel in _channel_list:
|
||||
para_list.append([_channel, _data_mean_dict[_channel], _id_dict[_channel]])
|
||||
with self._psql_conn as conn:
|
||||
with conn.cursor() as sql_cursor:
|
||||
execute_batch(sql_cursor, self._data_mini_recording_sql_str, para_list)
|
||||
except psycopg2.Error as e:
|
||||
print('recording error', e)
|
||||
return None
|
||||
|
||||
# @calculate_time
|
||||
def data_mini_update(self, _id, _channel, _data: JSON_OBJECT):
|
||||
sql_str = 'UPDATE "public"."' + str(_channel) + '_recording_data_minis" SET '
|
||||
sql_set = []
|
||||
@@ -469,3 +479,74 @@ class DataBaseProcess(Process):
|
||||
sql_cursor.close()
|
||||
|
||||
return True
|
||||
|
||||
def data_meta_update_raw_empty_channel(self, meta_id, channel_list):
|
||||
try:
|
||||
sql_str = "UPDATE recording_data_metas SET raw_data = jsonb_set(raw_data, '{%s}', '[]'), mini_data = jsonb_set(mini_data, '{%s}', '{\"10\": [], \"100\": [], \"1000\": []}') WHERE id = %s;"
|
||||
sql_set = []
|
||||
for channel in channel_list:
|
||||
sql_set.append([channel, channel, meta_id])
|
||||
|
||||
with self._psql_conn as conn:
|
||||
with conn.cursor() as sql_cursor:
|
||||
execute_batch(sql_cursor, sql_str, sql_set)
|
||||
except psycopg2.Error as e:
|
||||
print('e', e)
|
||||
|
||||
return True
|
||||
|
||||
# @calculate_time
|
||||
def data_meta_update_channel_raw_id(self, meta_id, channel, raw_id):
|
||||
try:
|
||||
with self._psql_conn as conn:
|
||||
with conn.cursor() as sql_cursor:
|
||||
sql_str = "UPDATE recording_data_metas SET raw_data = jsonb_insert(raw_data, '{%s, -1}', '%s', TRUE) WHERE id = %s;"
|
||||
sql_set = [channel, raw_id, 571]
|
||||
sql_cursor.execute(sql_str, sql_set)
|
||||
except psycopg2.Error as e:
|
||||
print('e', e)
|
||||
|
||||
return True
|
||||
|
||||
@calculate_time(1)
|
||||
def data_meta_update_all_channel_raw_id(self, meta_id:str, raw_id_dict:dict):
|
||||
try:
|
||||
sql_str = "UPDATE recording_data_metas SET raw_data = jsonb_insert(raw_data, '{%s, -1}', '%s', TRUE) WHERE id = %s;"
|
||||
sql_set = []
|
||||
for ch in raw_id_dict.keys():
|
||||
sql_set.append([ch, raw_id_dict[ch], meta_id])
|
||||
with self._psql_conn as conn:
|
||||
with conn.cursor() as sql_cursor:
|
||||
execute_batch(sql_cursor, sql_str, sql_set)
|
||||
except psycopg2.Error as e:
|
||||
print('e', e)
|
||||
|
||||
return True
|
||||
|
||||
def data_meta_update_channel_mini_id(self, meta_id, channel, scale, mini_id):
|
||||
try:
|
||||
with self._psql_conn as conn:
|
||||
with conn.cursor() as sql_cursor:
|
||||
sql_str = "UPDATE recording_data_metas SET mini_data = jsonb_insert(mini_data, '{%s, %s, -1}', '%s', TRUE) WHERE id = %s;"
|
||||
sql_set = [channel, scale, mini_id, meta_id]
|
||||
sql_cursor.execute(sql_str, sql_set)
|
||||
except psycopg2.Error as e:
|
||||
print('e', e)
|
||||
|
||||
return True
|
||||
|
||||
@calculate_time(1)
|
||||
def data_meta_update_all_channel_mini_id(self, meta_id, mini_id_dict):
|
||||
try:
|
||||
sql_str = "UPDATE recording_data_metas SET mini_data = jsonb_insert(mini_data, '{%s, %s, -1}', '%s', TRUE) WHERE id = %s;"
|
||||
sql_set = []
|
||||
for ch in mini_id_dict.keys():
|
||||
for scale in mini_id_dict[ch].keys():
|
||||
sql_set.append([ch, scale, mini_id_dict[ch][scale], 571])
|
||||
with self._psql_conn as conn:
|
||||
with conn.cursor() as sql_cursor:
|
||||
execute_batch(sql_cursor, sql_str, sql_set)
|
||||
except psycopg2.Error as e:
|
||||
print('e', e)
|
||||
|
||||
return True
|
||||
@@ -30,6 +30,7 @@ from .api import ApiRequests
|
||||
from biopro.api.auth import AuthAPI
|
||||
from biopro.api.controller import ControllerAPI
|
||||
from biopro.api.device import DeviceAPI
|
||||
from biopro.project.project_manager import ProjectManager
|
||||
### do not import Websocket mode
|
||||
###from .websocket import WebsocketThread
|
||||
|
||||
@@ -154,7 +155,8 @@ class ControlServer(SocketServer, ControlServerAPI, CacheAPI, CacheNotifyHandler
|
||||
# _api request build
|
||||
self._api = ApiRequests()
|
||||
|
||||
|
||||
self._project_manager = ProjectManager(self.device_manager, self.mqtt_thread)
|
||||
|
||||
|
||||
# init method
|
||||
|
||||
@@ -193,6 +195,11 @@ class ControlServer(SocketServer, ControlServerAPI, CacheAPI, CacheNotifyHandler
|
||||
def device_manager(self) -> DeviceManager:
|
||||
return self._device_manager
|
||||
|
||||
@property
|
||||
def project_manager(self) -> ProjectManager:
|
||||
return self._project_manager
|
||||
|
||||
|
||||
# server setup
|
||||
|
||||
def setup(self) -> None:
|
||||
@@ -1319,6 +1326,12 @@ class ControlServer(SocketServer, ControlServerAPI, CacheAPI, CacheNotifyHandler
|
||||
# p = self.exp_manager.create_protocol(content, user_name)
|
||||
return
|
||||
|
||||
@logging_info
|
||||
def run_project(self, project) -> bool:
|
||||
project = self._project_manager.create(project)
|
||||
self._project_manager.run(project)
|
||||
return False
|
||||
|
||||
# @logging_info
|
||||
# def exp_pro_options(self, protocol: int) -> List[ExpOption]:
|
||||
# return self.exp_manager.protocol_options(protocol)
|
||||
|
||||
@@ -98,6 +98,11 @@ class RecordingProcess(Process):
|
||||
self._last_cnt = [-1, -1, -1, -1, -1, -1, -1, -1]
|
||||
self._wrong_cnt = 0
|
||||
|
||||
# elite data length
|
||||
self._elite_data_len = 40
|
||||
self._mem_header_len = 3
|
||||
self._mem_tailer_len = 6
|
||||
self._single_data_len = self._elite_data_len + self._mem_header_len + self._mem_tailer_len
|
||||
|
||||
def ensure_data_format(self) -> DataDecodeFormat:
|
||||
if isinstance(self._data_format, (str, bytes)):
|
||||
@@ -160,7 +165,11 @@ class RecordingProcess(Process):
|
||||
"""
|
||||
q = None
|
||||
try:
|
||||
now = time()
|
||||
q = self._queue_rec.get()
|
||||
get_queue_time_cost = time() - now
|
||||
if get_queue_time_cost > 1.1:
|
||||
print('get queue cost time', get_queue_time_cost, 'q_size', self._queue_rec.qsize())
|
||||
except:
|
||||
return False
|
||||
finally:
|
||||
@@ -186,7 +195,7 @@ class RecordingProcess(Process):
|
||||
current_time = time()
|
||||
if self._timer is not None:
|
||||
if current_time - self._timer > 1.5:
|
||||
print('time, sync_data routine_time', current_time, current_time - self._timer)
|
||||
print('time, sync_data routine_time', 'device:', self._device, datetime.now(), current_time, current_time - self._timer)
|
||||
self._isTimeOut = True
|
||||
self._timer = current_time
|
||||
|
||||
@@ -286,6 +295,7 @@ class RecordingProcess(Process):
|
||||
self._last_cnt[7] = head_counter - 1
|
||||
last_data_cnt = self._last_cnt[7]
|
||||
|
||||
# dont save to section when head or id is wrong
|
||||
if (head != 255 or device_id != device):
|
||||
save = False
|
||||
last_data_cnt = last_data_cnt + 1
|
||||
@@ -328,61 +338,57 @@ class RecordingProcess(Process):
|
||||
|
||||
return save
|
||||
|
||||
def _check_jump_ram(self, raw_data: bytes, colum_now: int, colum_total: int, save: bool, device: int):
|
||||
i = colum_now
|
||||
def _check_jump_ram(self, raw_data: bytes, colum_now: int, colum_total: int, save: bool, device: int, data_len: int):
|
||||
col = colum_now
|
||||
save = False
|
||||
|
||||
if (raw_data[i][0] == 255 and raw_data[i][3] == device):
|
||||
if colum_total < 3:
|
||||
print('this ram data < 3 records, need to fix, colum_total = ', colum_total)
|
||||
if colum_total == 1:
|
||||
print('raw_data[0]', raw_data[0])
|
||||
if raw_data[col][0] != 255 or raw_data[col][3] != device:
|
||||
return save
|
||||
|
||||
elif colum_total == 2:
|
||||
print('raw_data[0]', raw_data[0])
|
||||
print('raw_data[1]', raw_data[1])
|
||||
if colum_total == 1:
|
||||
print('this ram data < 3 records, colum_total = ', colum_total)
|
||||
print('raw_data[0]', raw_data[0])
|
||||
return save
|
||||
|
||||
else:
|
||||
elif colum_total == 2:
|
||||
print('this ram data < 3 records, colum_total = ', colum_total)
|
||||
print('raw_data[0]', raw_data[0])
|
||||
print('raw_data[1]', raw_data[1])
|
||||
if (raw_data[col + 1][1] - raw_data[col][1] == 1) or (raw_data[col][1] == 255 and raw_data[col + 1][1] == 0):
|
||||
save = True
|
||||
|
||||
if((raw_data[i + 1][1] - raw_data[i][1] == 1 and raw_data[i + 2][1] - raw_data[i + 1][1] == 1) or
|
||||
(raw_data[i][1] == 255 and raw_data[i + 1][1] == 0 and raw_data[i + 2][1] == 1) or
|
||||
(raw_data[i][1] == 254 and raw_data[i + 1][1] == 255 and raw_data[i + 2][1] == 0)):
|
||||
elif colum_total >= 3:
|
||||
if (raw_data[col + 1][1] - raw_data[col][1] == 1 and raw_data[col + 2][1] - raw_data[col + 1][1] == 1) or\
|
||||
(raw_data[col][1] == 255 and raw_data[col + 1][1] == 0 and raw_data[col + 2][1] == 1) or\
|
||||
(raw_data[col][1] == 254 and raw_data[col + 1][1] == 255 and raw_data[col + 2][1] == 0):
|
||||
save = True
|
||||
|
||||
if ((raw_data[i][1] == 255 and raw_data[i + 1][1] == 0 and raw_data[i + 2][1] == 1) or
|
||||
(raw_data[i][1] == 254 and raw_data[i + 1][1] == 255 and raw_data[i + 2][1] == 0)):
|
||||
print('cnt = [254, 255, 0] or [255, 0, 1]')
|
||||
if save == True:
|
||||
self._skip_ram_cnt += 1
|
||||
last_data_cnt = raw_data[col][1]
|
||||
if (device == 4):
|
||||
print('self._last_cnt[4]:', self._last_cnt[4], ', last_data_cnt:', last_data_cnt)
|
||||
if (device == 5):
|
||||
print('self._last_cnt[5]:', self._last_cnt[5], ', last_data_cnt:', last_data_cnt)
|
||||
if (device == 6):
|
||||
print('self._last_cnt[6]:', self._last_cnt[6], ', last_data_cnt:', last_data_cnt)
|
||||
if (device == 7):
|
||||
print('self._last_cnt[7]:', self._last_cnt[7], ', last_data_cnt:', last_data_cnt)
|
||||
|
||||
print('skip RAM, but data is right, solve data', list(raw_data[col][0:3]),'|', list(raw_data[colum_total-1][0:3]), 'skip Ram', self._skip_ram_cnt, 'times \n')
|
||||
|
||||
save = True
|
||||
self._skip_ram_cnt += 1
|
||||
last_data_cnt = raw_data[i][1]
|
||||
if (device == 4):
|
||||
print('self._last_cnt[4]:', self._last_cnt[4], ', last_data_cnt:', last_data_cnt)
|
||||
if (device == 5):
|
||||
print('self._last_cnt[5]:', self._last_cnt[5], ', last_data_cnt:', last_data_cnt)
|
||||
if (device == 6):
|
||||
print('self._last_cnt[6]:', self._last_cnt[6], ', last_data_cnt:', last_data_cnt)
|
||||
if (device == 7):
|
||||
print('self._last_cnt[7]:', self._last_cnt[7], ', last_data_cnt:', last_data_cnt)
|
||||
|
||||
print('skip RAM, but data is right, solve data', list(raw_data[i][0:3]), 'skip Ram', self._skip_ram_cnt, 'times')
|
||||
# print('data:')
|
||||
# print('|', list(raw_data[0]))
|
||||
# print('|', list(raw_data[1]))
|
||||
# print('| ... ... ...')
|
||||
# print('| ... ... ...')
|
||||
# print('|', list(raw_data[colum_total-1]))
|
||||
print()
|
||||
if (device == 4):
|
||||
self._last_cnt[4] = last_data_cnt
|
||||
|
||||
if (device == 4):
|
||||
self._last_cnt[4] = last_data_cnt
|
||||
elif (device == 5):
|
||||
self._last_cnt[5] = last_data_cnt
|
||||
|
||||
elif (device == 5):
|
||||
self._last_cnt[5] = last_data_cnt
|
||||
elif (device == 6):
|
||||
self._last_cnt[6] = last_data_cnt
|
||||
|
||||
elif (device == 6):
|
||||
self._last_cnt[6] = last_data_cnt
|
||||
elif (device == 7):
|
||||
self._last_cnt[7] = last_data_cnt
|
||||
|
||||
elif (device == 7):
|
||||
self._last_cnt[7] = last_data_cnt
|
||||
return save
|
||||
|
||||
def _neu_foreach_data_section(self, data: bytes):
|
||||
@@ -497,50 +503,59 @@ class RecordingProcess(Process):
|
||||
:return:
|
||||
"""
|
||||
raw_data = []
|
||||
index = 0
|
||||
elite_data_len = 40
|
||||
mem_header_len = 3
|
||||
mem_tailer_len = 8
|
||||
single_data_len = elite_data_len + mem_header_len + mem_tailer_len
|
||||
device = self._device
|
||||
records = 0
|
||||
print_flag = False
|
||||
device = self._device
|
||||
single_data_len = self._single_data_len
|
||||
mem_header_len = self._mem_header_len
|
||||
|
||||
# packet section data use two microarray
|
||||
for i in range(0, len(data), single_data_len):
|
||||
index = index + 1
|
||||
for j in range(index, index + 1):
|
||||
raw_data.append(data[i : i + single_data_len])
|
||||
|
||||
records = records + 1
|
||||
raw_data.append(data[i : i + single_data_len])
|
||||
if len(data[i : i + 10]) < 10:
|
||||
print('data dont be package:', raw_data[records - 1], 'index:', records - 1)
|
||||
del raw_data[records - 1]
|
||||
records = records - 1
|
||||
|
||||
# check cnt
|
||||
for i in range(index):
|
||||
for i in range(records):
|
||||
|
||||
# if jump cnt, don't save data
|
||||
save = self._check_cnt(raw_data[i], device)
|
||||
|
||||
# # if jump Ram, also can handle data
|
||||
if save == False:
|
||||
save = self._check_jump_ram(raw_data, i, index, save, device)
|
||||
save = self._check_jump_ram(raw_data, i, records, save, device, single_data_len)
|
||||
|
||||
if (save == True):
|
||||
section = raw_data[i]
|
||||
|
||||
if (section[0 : mem_header_len] == section[single_data_len - 3: single_data_len]):
|
||||
section = section + b'\x00'
|
||||
|
||||
else:
|
||||
check_sum = sum(section[0 : single_data_len - 1]) & 0b11111111
|
||||
|
||||
if (check_sum != section[single_data_len - 1]):
|
||||
print('check number not match,',
|
||||
list(section[0 : mem_header_len]), section[-1], '!=', check_sum, 'device:', device, ',', datetime.now())
|
||||
if (i-1 >= 0):
|
||||
print('check number not match', list(raw_data[i-1]), 'raw:', i-1)
|
||||
|
||||
print('check number not match', list(raw_data[i]), 'raw:', i)
|
||||
|
||||
if (i+1 <= records):
|
||||
print('check number not match', list(raw_data[i+1]), 'raw:', i+1, '\n')
|
||||
section = section + b'\x01'
|
||||
print('header != tailer,',
|
||||
list(section[0 : mem_header_len]),
|
||||
list(section[single_data_len - 3: single_data_len]),
|
||||
'device:', device, ',', datetime.now())
|
||||
print('header != tailer', list(section), '\n')
|
||||
|
||||
section = section[3:]
|
||||
|
||||
print('delete data:', list(raw_data[i][0:3]), 'raw:', i, '\n')
|
||||
continue
|
||||
else:
|
||||
section = section + b'\x00'
|
||||
|
||||
# section = section[3:]
|
||||
yield None, section
|
||||
|
||||
else:
|
||||
print_flag = True
|
||||
print('delete data:', list(raw_data[i]))
|
||||
print('delete data:', list(raw_data[i][0:3]), 'raw:', i, '\n')
|
||||
|
||||
# if print_flag:
|
||||
# print('delete data context:')
|
||||
|
||||
@@ -3,6 +3,7 @@ import inspect
|
||||
import os
|
||||
import sys
|
||||
import threading as _threading
|
||||
from time import time
|
||||
from datetime import datetime
|
||||
from functools import wraps
|
||||
from typing import Any, Optional, Tuple, Union
|
||||
@@ -520,3 +521,17 @@ def logging_error(f):
|
||||
return f(self, *args, **kwargs)
|
||||
|
||||
return _logger
|
||||
|
||||
|
||||
def calculate_time(time_limit=None):
|
||||
def actual_calculate_time(func):
|
||||
def warp(*args, **kwargs):
|
||||
now = time()
|
||||
func(*args, **kwargs)
|
||||
if time_limit == None:
|
||||
print(func.__name__,'cost:', time() - now)
|
||||
else:
|
||||
if time() - now > time_limit:
|
||||
print(func.__name__,'cost:', time() - now)
|
||||
return warp
|
||||
return actual_calculate_time
|
||||
|
||||
Reference in New Issue
Block a user