131 lines
5.2 KiB
Python
131 lines
5.2 KiB
Python
import serial
|
||
import serial.tools.list_ports
|
||
import time
|
||
import datetime
|
||
import struct
|
||
import threading
|
||
import json
|
||
|
||
class SensorDetector:
|
||
def __init__(self, log_path, sensor_configs):
|
||
"""
|
||
初始化方法,支持多传感器配置
|
||
:param log_path: 日志路径
|
||
:param sensor_configs: 传感器配置列表,格式如[{"port": "COM6", "id": "X11223366S_1"}, {"port": "COM7", "id": "X11223366S_2"}]
|
||
"""
|
||
self.log_path = log_path
|
||
self.sensor_configs = sensor_configs # 新增:多传感器配置
|
||
self.serials = {} # 新增:存储多个串口连接
|
||
self.data3 = []
|
||
self.latest_data = {} # 新增:存储每个传感器的最新数据
|
||
self.running = True # 新增:轮询控制标志
|
||
|
||
# 确保日志目录存在
|
||
import os
|
||
if not os.path.exists(self.log_path):
|
||
os.makedirs(self.log_path)
|
||
|
||
def _open_serial_port(self, port, baudrate=38400, timeout=1):
|
||
"""修改:支持指定端口打开串口"""
|
||
try:
|
||
ser = serial.Serial(port=port, baudrate=baudrate, timeout=timeout)
|
||
if ser.isOpen():
|
||
print(f"Successfully open serial port {port}")
|
||
return ser
|
||
else:
|
||
print(f"Failure to open serial port {port}")
|
||
return None
|
||
except Exception as e:
|
||
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||
with open(f"{self.log_path}/Exception_log.txt", "a") as f:
|
||
f.write(f"{now} open serial port {port} error:{e}\n")
|
||
return None
|
||
|
||
def _send_command(self, ser, data):
|
||
"""修改:接受串口对象作为参数"""
|
||
try:
|
||
send_data = struct.pack("%dB" % (len(data)), *data)
|
||
ser.write(send_data)
|
||
except Exception as e:
|
||
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||
with open(f"{self.log_path}/Exception_log.txt", "a") as f:
|
||
f.write(f"{now} send command error:{e}\n")
|
||
|
||
def _sensor_worker(self, sensor_id, port, callback):
|
||
"""新增:单个传感器的工作线程"""
|
||
ser = self._open_serial_port(port)
|
||
if not ser:
|
||
return
|
||
|
||
self.serials[sensor_id] = ser
|
||
# 发送启动指令
|
||
self._send_command(ser, [0x8A])
|
||
|
||
current_second_data = []
|
||
last_second = time.time()
|
||
|
||
while self.running:
|
||
try:
|
||
count0 = ser.inWaiting()
|
||
current_time = time.time()
|
||
|
||
if count0 > 0:
|
||
read_buffer = ser.read(88)
|
||
if len(read_buffer) == 88 and read_buffer[0] == 0xff: # 增加长度校验,修复索引错误
|
||
sensor_data = {
|
||
'sensor_id': sensor_id, # 新增:标记传感器ID
|
||
'heart_rate': read_buffer[65],
|
||
'blood_oxygen': read_buffer[66],
|
||
'micro_circulation': read_buffer[67],
|
||
'fatigue_index': read_buffer[68],
|
||
'systolic_pressure': read_buffer[71],
|
||
'diastolic_pressure': read_buffer[72],
|
||
'cardiac_output': read_buffer[73]
|
||
}
|
||
current_second_data.append(sensor_data)
|
||
|
||
# 每秒回调一次数据
|
||
if current_time - last_second >= 1:
|
||
callback(current_second_data)
|
||
current_second_data = []
|
||
last_second = current_time
|
||
time.sleep(0.01) # 降低CPU占用
|
||
except Exception as e:
|
||
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||
with open(f"{self.log_path}/Exception_log.txt", "a") as f:
|
||
f.write(f"{now} sensor {sensor_id} data reading error:{e}\n")
|
||
time.sleep(1)
|
||
|
||
def detect_sensors(self, callback):
|
||
"""修改:启动多传感器轮询线程"""
|
||
try:
|
||
ports = list(serial.tools.list_ports.comports())
|
||
for p in ports:
|
||
print(p)
|
||
|
||
# 为每个传感器启动工作线程
|
||
threads = []
|
||
for config in self.sensor_configs:
|
||
t = threading.Thread(
|
||
target=self._sensor_worker,
|
||
args=(config["id"], config["port"], callback),
|
||
daemon=True
|
||
)
|
||
threads.append(t)
|
||
t.start()
|
||
|
||
# 保持主线程运行
|
||
while self.running:
|
||
time.sleep(1)
|
||
|
||
except Exception as e:
|
||
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||
with open(f"{self.log_path}/Exception_log.txt", "a") as f:
|
||
f.write(f"{now} overall sensor detection error:{e}\n")
|
||
|
||
def stop(self):
|
||
"""新增:停止所有传感器线程"""
|
||
self.running = False
|
||
for ser in self.serials.values():
|
||
if ser and ser.isOpen():
|
||
ser.close() |