feat: 修复一些已知问题
This commit is contained in:
parent
11c6b15d3e
commit
6d60e77743
@ -3,7 +3,7 @@
|
||||
"name": "腾智微丝产线包装系统",
|
||||
"version": "1.0.0",
|
||||
"features": {
|
||||
"enable_serial_ports": false,
|
||||
"enable_serial_ports": true,
|
||||
"enable_keyboard_listener": false,
|
||||
"enable_camera": false
|
||||
},
|
||||
@ -49,8 +49,8 @@
|
||||
"default_framerate": 30
|
||||
},
|
||||
"modbus": {
|
||||
"host": "192.168.2.88",
|
||||
"port": "502"
|
||||
"host": "localhost",
|
||||
"port": "5020"
|
||||
},
|
||||
"serial": {
|
||||
"keyboard": {
|
||||
@ -78,6 +78,15 @@
|
||||
"stable_threshold": 10,
|
||||
"stop_bits": 1,
|
||||
"timeout": 1
|
||||
},
|
||||
"scanner": {
|
||||
"code": "scanner",
|
||||
"data_bits": 8,
|
||||
"parity": "N",
|
||||
"port": "9600",
|
||||
"ser": "COM3",
|
||||
"stop_bits": 1,
|
||||
"timeout": 1
|
||||
}
|
||||
},
|
||||
"electricity": {
|
||||
|
||||
BIN
db/jtDB.db
BIN
db/jtDB.db
Binary file not shown.
@ -3,19 +3,19 @@ import time
|
||||
client = ModbusTcpClient('localhost', port=5020)
|
||||
client.connect()
|
||||
client.write_registers(address=11, values=[2248])
|
||||
client.write_registers(address=13, values=[0])
|
||||
client.write_registers(address=3, values=[0])
|
||||
|
||||
client.write_registers(address=21, values=[0])
|
||||
time.sleep(2)
|
||||
# client.write_registers(address=21, values=[1])
|
||||
# client.write_registers(address=20, values=[0])
|
||||
# time.sleep(2)
|
||||
# client.write_registers(address=20, values=[1])
|
||||
|
||||
# client.write_registers(address=30, values=[25])
|
||||
# client.write_registers(address=5, values=[16])
|
||||
# 贴标完成
|
||||
# client.write_registers(address=24, values=[1])s
|
||||
client.write_registers(address=13, values=[1])
|
||||
# client.write_registers(address=13, values=[1])
|
||||
|
||||
|
||||
result = client.read_holding_registers(address=1, count=1)
|
||||
result = client.read_holding_registers(address=3, count=1)
|
||||
print(result.registers[0],"123===")
|
||||
client.close()
|
||||
@ -28,7 +28,7 @@ class SerialSettingsUI(QWidget):
|
||||
enable_layout.addStretch()
|
||||
main_layout.addLayout(enable_layout)
|
||||
|
||||
# 创建串口设置组
|
||||
# # 创建串口设置组
|
||||
serial_group = QGroupBox("串口设置")
|
||||
serial_layout = QGridLayout(serial_group)
|
||||
|
||||
@ -39,6 +39,7 @@ class SerialSettingsUI(QWidget):
|
||||
# 串口选择
|
||||
mdz_port_layout = QHBoxLayout()
|
||||
self.mdz_port_combo = QComboBox()
|
||||
self.mdz_port_combo.addItem("不使用", "") # 添加空选项
|
||||
self.mdz_refresh_btn = QPushButton("刷新")
|
||||
mdz_port_layout.addWidget(self.mdz_port_combo)
|
||||
mdz_port_layout.addWidget(self.mdz_refresh_btn)
|
||||
@ -85,6 +86,7 @@ class SerialSettingsUI(QWidget):
|
||||
# 串口选择
|
||||
xj_port_layout = QHBoxLayout()
|
||||
self.xj_port_combo = QComboBox()
|
||||
self.xj_port_combo.addItem("不使用", "") # 添加空选项
|
||||
self.xj_refresh_btn = QPushButton("刷新")
|
||||
xj_port_layout.addWidget(self.xj_port_combo)
|
||||
xj_port_layout.addWidget(self.xj_refresh_btn)
|
||||
@ -114,10 +116,47 @@ class SerialSettingsUI(QWidget):
|
||||
self.xj_parity_combo.addItem(parity[0], parity[1])
|
||||
xj_layout.addRow("校验位:", self.xj_parity_combo)
|
||||
|
||||
# 扫码器串口设置
|
||||
scanner_group = QGroupBox("扫码器串口")
|
||||
scanner_layout = QFormLayout(scanner_group)
|
||||
|
||||
# 串口选择
|
||||
scanner_port_layout = QHBoxLayout()
|
||||
self.scanner_port_combo = QComboBox()
|
||||
self.scanner_port_combo.addItem("不使用", "") # 添加空选项
|
||||
self.scanner_refresh_btn = QPushButton("刷新")
|
||||
scanner_port_layout.addWidget(self.scanner_port_combo)
|
||||
scanner_port_layout.addWidget(self.scanner_refresh_btn)
|
||||
scanner_layout.addRow("串口:", scanner_port_layout)
|
||||
|
||||
# 波特率
|
||||
self.scanner_baud_combo = QComboBox()
|
||||
for baud in ["1200", "2400", "4800", "9600", "19200", "38400", "57600", "115200"]:
|
||||
self.scanner_baud_combo.addItem(baud)
|
||||
scanner_layout.addRow("波特率:", self.scanner_baud_combo)
|
||||
|
||||
# 数据位
|
||||
self.scanner_data_bits_combo = QComboBox()
|
||||
for bits in ["5", "6", "7", "8"]:
|
||||
self.scanner_data_bits_combo.addItem(bits)
|
||||
scanner_layout.addRow("数据位:", self.scanner_data_bits_combo)
|
||||
|
||||
# 停止位
|
||||
self.scanner_stop_bits_combo = QComboBox()
|
||||
for bits in ["1", "1.5", "2"]:
|
||||
self.scanner_stop_bits_combo.addItem(bits)
|
||||
scanner_layout.addRow("停止位:", self.scanner_stop_bits_combo)
|
||||
|
||||
# 校验位
|
||||
self.scanner_parity_combo = QComboBox()
|
||||
for parity in [("无校验", "N"), ("奇校验", "O"), ("偶校验", "E")]:
|
||||
self.scanner_parity_combo.addItem(parity[0], parity[1])
|
||||
scanner_layout.addRow("校验位:", self.scanner_parity_combo)
|
||||
|
||||
# 将三个组添加到布局
|
||||
serial_layout.addWidget(mdz_group, 0, 0)
|
||||
serial_layout.addWidget(xj_group, 0, 1)
|
||||
serial_layout.addWidget(scanner_group, 1, 0) # 添加扫码器串口设置,放在第二行第一列
|
||||
|
||||
# 设置列伸缩因子,使两列等宽(比例1:1)
|
||||
serial_layout.setColumnStretch(0, 1)
|
||||
@ -129,8 +168,10 @@ class SerialSettingsUI(QWidget):
|
||||
test_layout = QHBoxLayout()
|
||||
self.test_mdz_btn = QPushButton("测试米电阻串口")
|
||||
self.test_xj_btn = QPushButton("测试线径串口")
|
||||
self.test_scanner_btn = QPushButton("测试扫码器串口") # 添加测试扫码器串口按钮
|
||||
test_layout.addWidget(self.test_mdz_btn)
|
||||
test_layout.addWidget(self.test_xj_btn)
|
||||
test_layout.addWidget(self.test_scanner_btn) # 添加到布局
|
||||
test_layout.addStretch()
|
||||
main_layout.addLayout(test_layout)
|
||||
|
||||
|
||||
@ -486,22 +486,22 @@ class SettingsUI(QWidget):
|
||||
self.tab_widget.addTab(self.param_tab, "参数配置")
|
||||
|
||||
def create_electricity_tab(self):
|
||||
"""创建电量监控选项卡"""
|
||||
# 电量监控选项卡
|
||||
"""创建电力监控选项卡"""
|
||||
# 电力监控选项卡
|
||||
self.electricity_tab = QWidget()
|
||||
self.electricity_layout = QVBoxLayout(self.electricity_tab)
|
||||
self.electricity_layout.setContentsMargins(0, 0, 0, 0)
|
||||
self.electricity_layout.setSpacing(0)
|
||||
|
||||
# 添加一个临时提示标签,表示此处将由ElectricitySettingsUI替换
|
||||
self.electricity_placeholder = QLabel("正在加载电量监控设置...")
|
||||
self.electricity_placeholder = QLabel("正在加载电力监控设置...")
|
||||
self.electricity_placeholder.setFont(self.normal_font)
|
||||
self.electricity_placeholder.setAlignment(Qt.AlignCenter)
|
||||
self.electricity_placeholder.setStyleSheet("color: #888888; padding: 20px;")
|
||||
self.electricity_layout.addWidget(self.electricity_placeholder)
|
||||
|
||||
# 添加到选项卡
|
||||
self.tab_widget.addTab(self.electricity_tab, "电量监控")
|
||||
self.tab_widget.addTab(self.electricity_tab, "电力监控")
|
||||
|
||||
def create_pallet_type_tab(self):
|
||||
# 托盘类型设置选项卡
|
||||
|
||||
@ -54,7 +54,8 @@ class SerialManager:
|
||||
self.data = {
|
||||
'mdz': 0,
|
||||
'xj': 0, # 添加线径数据
|
||||
'cz': 0
|
||||
'cz': 0,
|
||||
'scanner': '' # 添加扫码器数据
|
||||
}
|
||||
|
||||
# 是否自动查询米电阻数据,默认为False,只通过PageUp键触发
|
||||
@ -102,6 +103,7 @@ class SerialManager:
|
||||
self.mdz_config = self.config.get_config('mdz')
|
||||
self.cz_config = self.config.get_config('cz')
|
||||
self.xj_config = self.config.get_config('xj') # 添加线径配置
|
||||
self.scanner_config = self.config.get_config('scanner') # 添加扫码器配置
|
||||
|
||||
# 检查操作系统类型,在macOS上处理COM端口名称问题
|
||||
os_type = platform.system()
|
||||
@ -118,7 +120,7 @@ class SerialManager:
|
||||
# 检查是否自动查询米电阻数据
|
||||
self.auto_query_mdz = self.config.get_value('serial.keyboard.auto_query', False)
|
||||
|
||||
logging.info(f"已加载串口配置:mdz={self.mdz_config}, xj={self.xj_config}, cz={self.cz_config}, data_file={self.data_file}")
|
||||
logging.info(f"已加载串口配置:mdz={self.mdz_config}, xj={self.xj_config}, cz={self.cz_config}, scanner={self.scanner_config}, data_file={self.data_file}")
|
||||
logging.info(f"米电阻自动查询: {'开启' if self.auto_query_mdz else '关闭'}")
|
||||
except Exception as e:
|
||||
logging.error(f"加载配置出错: {e}")
|
||||
@ -126,6 +128,8 @@ class SerialManager:
|
||||
self.data_file = os.path.abspath('data.txt')
|
||||
self.mdz_config = {'port': 9600, 'ser': 'COM5'}
|
||||
self.cz_config = {'port': 9600, 'ser': 'COM2', 'stable_threshold': 10}
|
||||
self.xj_config = {'port': 9600, 'ser': 'COM3'}
|
||||
self.scanner_config = {'port': 9600, 'ser': 'COM4'}
|
||||
self.stable_threshold = 10
|
||||
self.auto_query_mdz = False
|
||||
logging.info(f"使用默认配置,数据文件: {self.data_file}")
|
||||
@ -194,88 +198,105 @@ class SerialManager:
|
||||
|
||||
Args:
|
||||
port_name: 串口名称,如COM1
|
||||
port_type: 串口类型,'cz'表示称重,'mdz'表示米电阻, 'xj'表示线径
|
||||
port_type: 串口类型,'cz'表示称重,'mdz'表示米电阻, 'xj'表示线径, 'scanner'表示扫码器
|
||||
baud_rate: 波特率,如果为None则从配置文件读取
|
||||
data_bits: 数据位
|
||||
stop_bits: 停止位
|
||||
parity: 校验位,N-无校验,E-偶校验,O-奇校验
|
||||
parity: 校验位,'N'表示无校验,'O'表示奇校验,'E'表示偶校验
|
||||
timeout: 超时时间,单位秒
|
||||
callback: 数据回调函数,接收参数为(port_name, data)
|
||||
callback: 回调函数,接收(port_name, data)作为参数
|
||||
|
||||
Returns:
|
||||
是否成功打开
|
||||
bool: 成功返回True,失败返回False
|
||||
"""
|
||||
# 如果串口已经打开,先关闭
|
||||
if port_name in self.serial_ports and self.serial_ports[port_name]:
|
||||
try:
|
||||
# 如果波特率为None,从配置文件读取
|
||||
self.close_port(port_name)
|
||||
except Exception as e:
|
||||
logging.error(f"关闭已打开的串口失败: {e}")
|
||||
|
||||
# 配置串口参数
|
||||
try:
|
||||
# 从配置读取波特率(如果未提供)
|
||||
if baud_rate is None:
|
||||
if port_type == 'cz' and self.cz_config:
|
||||
baud_rate = self.cz_config.get('port', 9600)
|
||||
elif port_type == 'mdz' and self.mdz_config:
|
||||
baud_rate = self.mdz_config.get('port', 9600)
|
||||
elif port_type == 'xj' and self.xj_config: # 添加线径配置
|
||||
elif port_type == 'xj' and self.xj_config:
|
||||
baud_rate = self.xj_config.get('port', 9600)
|
||||
elif port_type == 'scanner' and self.scanner_config:
|
||||
baud_rate = self.scanner_config.get('port', 9600)
|
||||
else:
|
||||
baud_rate = 9600 # 默认波特率
|
||||
|
||||
# 如果串口已经打开,先关闭
|
||||
if port_name in self.serial_ports:
|
||||
self.close_port(port_name)
|
||||
# 转换校验位为PySerial常量
|
||||
if parity.upper() == 'N':
|
||||
parity_constant = serial.PARITY_NONE
|
||||
elif parity.upper() == 'O':
|
||||
parity_constant = serial.PARITY_ODD
|
||||
elif parity.upper() == 'E':
|
||||
parity_constant = serial.PARITY_EVEN
|
||||
else:
|
||||
parity_constant = serial.PARITY_NONE
|
||||
|
||||
# 打开串口
|
||||
ser = serial.Serial(
|
||||
self.serial_ports[port_name] = serial.Serial(
|
||||
port=port_name,
|
||||
baudrate=baud_rate,
|
||||
bytesize=data_bits,
|
||||
stopbits=stop_bits,
|
||||
parity=parity,
|
||||
parity=parity_constant,
|
||||
timeout=timeout
|
||||
)
|
||||
|
||||
if not ser.is_open:
|
||||
ser.open()
|
||||
|
||||
# 存储串口对象
|
||||
self.serial_ports[port_name] = ser
|
||||
logging.info(f"串行对象 for {port_name} 存储在 self.serial_ports 中. 当前活跃端口: {list(self.serial_ports.keys())}")
|
||||
logging.info(f"打开串口成功: {port_name}, 类型: {port_type}, 波特率: {baud_rate}")
|
||||
|
||||
# 设置回调
|
||||
if callback:
|
||||
self.callbacks[port_name] = callback
|
||||
|
||||
# 启动读取线程
|
||||
# 创建并启动读取线程
|
||||
self.running_flags[port_name] = True
|
||||
|
||||
# 根据串口类型选择不同的读取线程
|
||||
if port_type == 'cz':
|
||||
# 称重数据需要特殊处理
|
||||
thread = threading.Thread(target=self._read_weight_thread, args=(port_name, self.stable_threshold))
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
self.read_threads[port_name] = thread
|
||||
elif port_type == 'mdz':
|
||||
# 米电阻数据需要特殊处理
|
||||
thread = threading.Thread(target=self._read_resistance_thread, args=(port_name,))
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
self.read_threads[port_name] = thread
|
||||
elif port_type == 'xj': # 添加线径读取线程
|
||||
elif port_type == 'xj':
|
||||
# 线径数据需要特殊处理
|
||||
thread = threading.Thread(target=self._read_diameter_thread, args=(port_name,))
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
self.read_threads[port_name] = thread
|
||||
elif port_type == 'scanner':
|
||||
# 扫码器数据需要特殊处理
|
||||
thread = threading.Thread(target=self._read_scanner_thread, args=(port_name,))
|
||||
else:
|
||||
# 默认读取线程
|
||||
# 其他类型使用通用处理
|
||||
thread = threading.Thread(target=self._read_thread, args=(port_name,))
|
||||
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
self.read_threads[port_name] = thread
|
||||
|
||||
logging.info(f"串口 {port_name} ({port_type}) 已打开,波特率={baud_rate}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"打开串口 {port_name} 失败: {str(e)}")
|
||||
if port_name in self.serial_ports: # 清理,以防部分成功
|
||||
del self.serial_ports[port_name]
|
||||
logging.info(f"打开 {port_name} 失败后, 当前活跃端口: {list(self.serial_ports.keys())}")
|
||||
logging.error(f"打开串口失败: {port_name}, 错误: {e}")
|
||||
# 确保清理好资源
|
||||
if port_name in self.serial_ports:
|
||||
try:
|
||||
self.serial_ports[port_name].close()
|
||||
except:
|
||||
pass
|
||||
self.serial_ports.pop(port_name, None)
|
||||
|
||||
# 停止相关线程
|
||||
self.running_flags[port_name] = False
|
||||
if port_name in self.read_threads:
|
||||
self.read_threads.pop(port_name, None)
|
||||
|
||||
return False
|
||||
|
||||
def close_port(self, port_name: str) -> bool:
|
||||
@ -351,6 +372,35 @@ class SerialManager:
|
||||
logging.error(f"向串口 {port_name} 写入数据失败: {str(e)}")
|
||||
return False
|
||||
|
||||
def read_data(self, port_name: str, size: int = None) -> bytes:
|
||||
"""
|
||||
从串口读取数据
|
||||
|
||||
Args:
|
||||
port_name: 串口名称
|
||||
size: 要读取的字节数,如果为None则读取所有可用数据
|
||||
|
||||
Returns:
|
||||
读取的数据,如果失败则返回空字节
|
||||
"""
|
||||
try:
|
||||
if not self.is_port_open(port_name):
|
||||
logging.error(f"尝试从未打开的串口 {port_name} 读取数据")
|
||||
return b''
|
||||
|
||||
if size is None:
|
||||
# 读取所有可用数据
|
||||
if self.serial_ports[port_name].in_waiting > 0:
|
||||
return self.serial_ports[port_name].read(self.serial_ports[port_name].in_waiting)
|
||||
return b''
|
||||
else:
|
||||
# 读取指定数量的字节
|
||||
return self.serial_ports[port_name].read(size)
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"从串口 {port_name} 读取数据失败: {str(e)}")
|
||||
return b''
|
||||
|
||||
def _read_thread(self, port_name: str):
|
||||
"""
|
||||
串口读取线程
|
||||
@ -534,7 +584,7 @@ class SerialManager:
|
||||
return
|
||||
|
||||
# 构建数据字符串
|
||||
data_str = f"mdz:{self.data['mdz']}|cz:{self.data['cz']}|"
|
||||
data_str = f"mdz:{self.data['mdz']}|cz:{self.data['cz']}|scanner:{self.data['scanner']}|"
|
||||
|
||||
# 确保目录存在
|
||||
data_dir = os.path.dirname(self.data_file)
|
||||
@ -792,7 +842,7 @@ class SerialManager:
|
||||
"""通知所有相关回调函数"""
|
||||
try:
|
||||
# 端口特定回调 (通常用于原始串口数据)
|
||||
if port_name in self.callbacks and port_name not in ['mdz_data', 'xj_data']: # 避免重复处理
|
||||
if port_name in self.callbacks and port_name not in ['mdz_data', 'xj_data', 'scanner_data']: # 避免重复处理
|
||||
try:
|
||||
# 假设这种回调期望原始的 value (可能是字节串,也可能是其他类型)
|
||||
self.callbacks[port_name](port_name, value)
|
||||
@ -874,6 +924,37 @@ class SerialManager:
|
||||
else:
|
||||
logging.warning(f"回调失败: xj_data 中实际值为None. 初始 value: {value}")
|
||||
|
||||
# 全局回调, 特别处理 'scanner_data'
|
||||
if 'scanner_data' in self.callbacks and port_name == 'scanner_data':
|
||||
actual_scanner_value = None
|
||||
source_info = "unknown"
|
||||
|
||||
if isinstance(value, dict):
|
||||
actual_scanner_value = value.get('value')
|
||||
source_info = value.get('source', source_info)
|
||||
elif isinstance(value, (str, bytes)):
|
||||
if isinstance(value, bytes):
|
||||
try:
|
||||
actual_scanner_value = value.decode('utf-8').strip()
|
||||
except:
|
||||
actual_scanner_value = str(value)
|
||||
else:
|
||||
actual_scanner_value = value
|
||||
|
||||
if actual_scanner_value is not None:
|
||||
callback_data_str = f"扫码数据: {actual_scanner_value}"
|
||||
try:
|
||||
triggering_port = port_name if port_name not in ['scanner_data', 'scanner'] else self.scanner_config.get('ser', 'N/A') if self.scanner_config else 'N/A'
|
||||
if source_info.startswith("mock"):
|
||||
triggering_port = f"mock_{port_name}"
|
||||
|
||||
self.callbacks['scanner_data'](triggering_port, callback_data_str.encode('utf-8'))
|
||||
logging.info(f"通知 'scanner_data' 回调. 值: {actual_scanner_value}, 源: {source_info}, 触发源端口: {triggering_port}")
|
||||
except Exception as e:
|
||||
logging.error(f"调用全局回调 'scanner_data' 失败: {e}", exc_info=True)
|
||||
else:
|
||||
logging.warning(f"回调失败: scanner_data 中实际值为None. 初始 value: {value}")
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"通知回调失败: {e}", exc_info=True)
|
||||
|
||||
@ -893,14 +974,15 @@ class SerialManager:
|
||||
os_type = platform.system()
|
||||
if os_type == "Darwin" and (
|
||||
(self.mdz_config and 'ser' in self.mdz_config and self.mdz_config['ser'] and self.mdz_config['ser'].startswith('COM')) or
|
||||
(self.cz_config and 'ser' in self.cz_config and self.cz_config['ser'] and self.cz_config['ser'].startswith('COM'))
|
||||
(self.cz_config and 'ser' in self.cz_config and self.cz_config['ser'] and self.cz_config['ser'].startswith('COM')) or
|
||||
(self.scanner_config and 'ser' in self.scanner_config and self.scanner_config['ser'] and self.scanner_config['ser'].startswith('COM'))
|
||||
):
|
||||
logging.warning("检测到在macOS系统上配置了Windows格式的COM端口,这些端口将无法正常打开")
|
||||
logging.warning("macOS上的串口通常是/dev/tty.*或/dev/cu.*格式")
|
||||
# 继续尝试打开,但不影响程序流程
|
||||
|
||||
# 尝试打开线径串口
|
||||
if self.cz_config and 'ser' in self.cz_config and self.cz_config['ser']:
|
||||
if self.cz_config and 'ser' in self.cz_config and self.cz_config['ser'] and self.cz_config['ser'].strip():
|
||||
port_name = self.cz_config['ser']
|
||||
baud_rate = self.cz_config.get('port', 2400)
|
||||
|
||||
@ -917,10 +999,10 @@ class SerialManager:
|
||||
else:
|
||||
logging.info(f"线径串口 {port_name} 已经打开,无需重新打开")
|
||||
else:
|
||||
logging.warning("线径串口未配置,跳过自动打开")
|
||||
logging.warning("线径串口未配置或设置为不使用,跳过自动打开")
|
||||
|
||||
# 尝试打开米电阻串口
|
||||
if self.mdz_config and 'ser' in self.mdz_config and self.mdz_config['ser']:
|
||||
if self.mdz_config and 'ser' in self.mdz_config and self.mdz_config['ser'] and self.mdz_config['ser'].strip():
|
||||
port_name = self.mdz_config['ser']
|
||||
baud_rate = self.mdz_config.get('port', 9600)
|
||||
|
||||
@ -937,7 +1019,27 @@ class SerialManager:
|
||||
else:
|
||||
logging.info(f"米电阻串口 {port_name} 已经打开,无需重新打开")
|
||||
else:
|
||||
logging.warning("米电阻串口未配置,跳过自动打开")
|
||||
logging.warning("米电阻串口未配置或设置为不使用,跳过自动打开")
|
||||
|
||||
# 尝试打开扫码器串口
|
||||
if self.scanner_config and 'ser' in self.scanner_config and self.scanner_config['ser'] and self.scanner_config['ser'].strip():
|
||||
port_name = self.scanner_config['ser']
|
||||
baud_rate = self.scanner_config.get('port', 9600)
|
||||
|
||||
if not self.is_port_open(port_name):
|
||||
try:
|
||||
if self.open_port(port_name, 'scanner', baud_rate):
|
||||
logging.info(f"自动打开扫码器串口 {port_name} 成功")
|
||||
else:
|
||||
logging.error(f"自动打开扫码器串口 {port_name} 失败")
|
||||
success = False
|
||||
except Exception as e:
|
||||
logging.error(f"自动打开扫码器串口 {port_name} 时发生异常: {e}")
|
||||
success = False
|
||||
else:
|
||||
logging.info(f"扫码器串口 {port_name} 已经打开,无需重新打开")
|
||||
else:
|
||||
logging.warning("扫码器串口未配置或设置为不使用,跳过自动打开")
|
||||
|
||||
# 注意:不在这里启动键盘监听器,而是在MainWindow的handle_start方法中显式调用start_keyboard_listener
|
||||
|
||||
@ -1023,3 +1125,73 @@ class SerialManager:
|
||||
except Exception as e:
|
||||
logging.error(f"处理线径数据总体异常: {e}")
|
||||
return False
|
||||
|
||||
def _read_scanner_thread(self, port_name: str):
|
||||
"""
|
||||
扫码器串口读取线程
|
||||
|
||||
Args:
|
||||
port_name: 串口名称
|
||||
"""
|
||||
try:
|
||||
while self.running_flags.get(port_name, False):
|
||||
if not self.is_port_open(port_name):
|
||||
time.sleep(0.1)
|
||||
continue
|
||||
|
||||
# 检查是否有数据可读
|
||||
if self.serial_ports[port_name].in_waiting > 0:
|
||||
response = self.serial_ports[port_name].read(self.serial_ports[port_name].in_waiting)
|
||||
self._process_scanner_response(port_name, response)
|
||||
|
||||
time.sleep(0.1)
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"扫码器串口 {port_name} 读取线程异常: {e}")
|
||||
|
||||
def _process_scanner_response(self, port_name, response_bytes: bytes):
|
||||
"""处理扫码器响应数据"""
|
||||
try:
|
||||
if response_bytes: # 确保有响应数据
|
||||
try:
|
||||
# 尝试解码为字符串
|
||||
scanner_value = response_bytes.decode('utf-8').strip()
|
||||
|
||||
# 记录日志
|
||||
logging.info(f"[{port_name}] 扫码数据: {scanner_value}")
|
||||
|
||||
# 更新数据
|
||||
self.data['scanner'] = scanner_value
|
||||
|
||||
# 写入文件并通知回调
|
||||
self._write_data_to_file()
|
||||
# 使用"扫码数据: xxx"格式通知回调
|
||||
callback_data = f"扫码数据: {scanner_value}".encode('utf-8')
|
||||
if 'scanner_data' in self.callbacks:
|
||||
self.callbacks['scanner_data'](port_name, callback_data)
|
||||
return True
|
||||
except Exception as e:
|
||||
logging.error(f"处理扫码数据异常: {e}")
|
||||
# 解码失败,尝试直接使用字节数据
|
||||
# 记录日志(十六进制字符串)
|
||||
hex_str = ' '.join(f'{b:02X}' for b in response_bytes)
|
||||
logging.warning(f"[{port_name}] 扫码数据(十六进制): {hex_str}")
|
||||
|
||||
# 更新数据(使用十六进制字符串)
|
||||
self.data['scanner'] = hex_str
|
||||
|
||||
# 写入文件并通知回调
|
||||
self._write_data_to_file()
|
||||
# 使用"扫码数据: xxx"格式通知回调
|
||||
callback_data = f"扫码数据: {hex_str}".encode('utf-8')
|
||||
if 'scanner_data' in self.callbacks:
|
||||
self.callbacks['scanner_data'](port_name, callback_data)
|
||||
return True
|
||||
else:
|
||||
logging.warning("扫码响应数据为空")
|
||||
|
||||
# 如果无法解析,则直接返回失败
|
||||
return False
|
||||
except Exception as e:
|
||||
logging.error(f"处理扫码数据总体异常: {e}")
|
||||
return False
|
||||
@ -205,6 +205,10 @@ class MainWindow(MainWindowUI):
|
||||
|
||||
# 加载托盘号列表
|
||||
self.load_pallet_codes()
|
||||
|
||||
# 恢复开始按钮原始样式
|
||||
self.restore_start_button_style()
|
||||
|
||||
def get_axios_num(self,tray_id):
|
||||
"""获取托盘号对应的轴号"""
|
||||
from dao.inspection_dao import InspectionDAO
|
||||
@ -369,10 +373,13 @@ class MainWindow(MainWindowUI):
|
||||
# 更新串口管理器配置
|
||||
self.serial_manager.reload_config()
|
||||
|
||||
# 重新打开已配置的串口
|
||||
self.serial_manager.auto_open_configured_ports()
|
||||
|
||||
# 重新加载托盘号
|
||||
self.load_pallet_codes()
|
||||
|
||||
logging.info("设置已更新,重新加载配置")
|
||||
logging.info("设置已更新,重新加载配置并重新打开串口")
|
||||
|
||||
def handle_input(self):
|
||||
"""处理上料按钮点击事件"""
|
||||
@ -508,6 +515,49 @@ class MainWindow(MainWindowUI):
|
||||
logging.error(f"处理下料操作失败: {str(e)}")
|
||||
QMessageBox.critical(self, "错误", f"处理下料操作失败: {str(e)}")
|
||||
|
||||
def restore_start_button_style(self):
|
||||
"""恢复开始按钮的原始样式"""
|
||||
try:
|
||||
self.start_button.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: transparent;
|
||||
color: black;
|
||||
border: 1px solid #4caf50;
|
||||
border-radius: 4px;
|
||||
padding: 2px 10px;
|
||||
min-height: 29px;
|
||||
max-height: 29px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
""")
|
||||
except Exception as e:
|
||||
logging.error(f"{str(e)}")
|
||||
|
||||
def fill_start_button_style(self):
|
||||
"""填充开始按钮样式 - 绿色背景,白色字体"""
|
||||
try:
|
||||
# 填充按钮样式 - 绿色背景,白色字体,高度与下料按钮一致
|
||||
self.start_button.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: #4caf50;
|
||||
color: white;
|
||||
border: 1px solid #4caf50;
|
||||
border-radius: 4px;
|
||||
padding: 2px 10px;
|
||||
min-height: 24px;
|
||||
max-height: 24px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #4caf50;
|
||||
color: white;
|
||||
}
|
||||
""")
|
||||
logging.info("已填充开始按钮样式")
|
||||
except Exception as e:
|
||||
logging.error(f"填充开始按钮样式失败: {str(e)}")
|
||||
|
||||
def handle_start(self):
|
||||
"""
|
||||
处理开始按钮点击事件
|
||||
@ -522,11 +572,14 @@ class MainWindow(MainWindowUI):
|
||||
if self._current_unload_info and self._current_unload_num > 0:
|
||||
# 下料模式 - 开始下料操作
|
||||
# 确保寄存器3(下料启动)设为1,寄存器4已在handle_output中设置了当前层数
|
||||
success2 = modbus.write_register_until_success(client, 2, 1)
|
||||
success3 = modbus.write_register_until_success(client, 3, 1)
|
||||
|
||||
if success3:
|
||||
if success2 and success3:
|
||||
logging.info(f"开始下料操作:当前层数 {self._current_unload_num}/{self._total_unload_num}")
|
||||
QMessageBox.information(self, "操作提示", f"开始下料操作:当前第{self._current_unload_num}层")
|
||||
# 填充按钮样式
|
||||
self.fill_start_button_style()
|
||||
else:
|
||||
QMessageBox.warning(self, "错误", "开始下料操作失败")
|
||||
else:
|
||||
@ -538,8 +591,11 @@ class MainWindow(MainWindowUI):
|
||||
if success0 and success2:
|
||||
self._is_loading_active = True # 标记上料任务已开始
|
||||
logging.info(f"开始上料操作:当前层数 {self._current_stow_num}")
|
||||
# 填充按钮样式
|
||||
self.fill_start_button_style()
|
||||
else:
|
||||
QMessageBox.warning(self, "错误", "开始上料操作失败")
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"开始操作失败: {str(e)}")
|
||||
QMessageBox.critical(self, "错误", f"开始操作失败: {str(e)}")
|
||||
@ -559,6 +615,8 @@ class MainWindow(MainWindowUI):
|
||||
if success3:
|
||||
logging.info(f"停止下料操作:当前层数 {self._current_unload_num}/{self._total_unload_num}")
|
||||
QMessageBox.information(self, "操作提示", "已停止下料操作")
|
||||
# 恢复按钮原始样式
|
||||
self.restore_start_button_style()
|
||||
else:
|
||||
QMessageBox.warning(self, "错误", "停止下料操作失败")
|
||||
else:
|
||||
@ -569,8 +627,11 @@ class MainWindow(MainWindowUI):
|
||||
self._is_loading_active = False # 标记上料任务已停止
|
||||
logging.info("停止上料操作")
|
||||
QMessageBox.information(self, "操作提示", "已停止上料操作")
|
||||
# 恢复按钮原始样式
|
||||
self.restore_start_button_style()
|
||||
else:
|
||||
QMessageBox.warning(self, "错误", "停止上料操作失败")
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"停止操作失败: {str(e)}")
|
||||
QMessageBox.critical(self, "错误", f"停止操作失败: {str(e)}")
|
||||
@ -1943,21 +2004,19 @@ class MainWindow(MainWindowUI):
|
||||
def handle_register_change(self, address, value):
|
||||
"""处理寄存器变化"""
|
||||
logging.info(f"[处理] 寄存器D{address}变化: {value}")
|
||||
# 在这里可以添加通用寄存器变化处理逻辑
|
||||
pass
|
||||
# 这里可以添加通用寄存器变化处理逻辑
|
||||
|
||||
@Slot(int, str)
|
||||
def handle_loading_feedback(self, status, desc):
|
||||
"""处理上料信息反馈"""
|
||||
message = desc # Default message
|
||||
message = desc
|
||||
try:
|
||||
if status == 1:
|
||||
modbus = ModbusUtils()
|
||||
client = modbus.get_client()
|
||||
# 睡 0.5 秒,用于延缓modbus 监听
|
||||
time.sleep(0.5)
|
||||
modbus.write_register_until_success(client, 2, 0)
|
||||
modbus.close_client(client)
|
||||
|
||||
if self._current_stow_num > 0:
|
||||
completed_layer_num = self._current_stow_num
|
||||
self._current_stow_num -= 1
|
||||
@ -1966,11 +2025,24 @@ class MainWindow(MainWindowUI):
|
||||
self._loading_info = None
|
||||
logging.info("所有层拆垛完成,清空上料信息")
|
||||
message = f"第 {completed_layer_num} 层(最后一层)拆垛完成!"
|
||||
# 重置寄存器 0 和 2 为 0
|
||||
modbus.write_register_until_success(client, 0, 0)
|
||||
modbus.write_register_until_success(client, 2, 0)
|
||||
self.loading_feedback_signal.emit("input", message)
|
||||
# 恢复开始按钮原始样式
|
||||
self.restore_start_button_style()
|
||||
else:
|
||||
logging.info(f"当前层拆垛完成,剩余层数: {self._current_stow_num}")
|
||||
message = f"第 {completed_layer_num} 层拆垛完成。"
|
||||
|
||||
self.loading_feedback_signal.emit("input", message)
|
||||
#通知寄存器,进行第几层拆垛
|
||||
modbus.write_register_until_success(client,0 ,self._current_stow_num)
|
||||
except Exception as e:
|
||||
logging.error(f"处理上料信息反馈失败: {str(e)}")
|
||||
# 不在这里显示对话框,而是通过信号传递错误信息
|
||||
self.loading_feedback_signal.emit("error", f"处理上料信息反馈失败: {str(e)}")
|
||||
finally:
|
||||
modbus.close_client(client)
|
||||
|
||||
def _handle_loading_feedback_ui(self, status_type, desc):
|
||||
"""在主线程中处理上料UI更新"""
|
||||
@ -1996,6 +2068,8 @@ class MainWindow(MainWindowUI):
|
||||
client = modbus.get_client()
|
||||
|
||||
try:
|
||||
# 睡 0.5 秒,用于延缓modbus 监听
|
||||
time.sleep(0.5)
|
||||
# 临时重置寄存器3(下料启动)为0,等待用户下一次启动
|
||||
modbus.write_register_until_success(client, 3, 0)
|
||||
|
||||
@ -2013,6 +2087,9 @@ class MainWindow(MainWindowUI):
|
||||
# 通过信号触发UI更新 - 显示前一层完成的消息
|
||||
message = f"第{self._current_unload_num-1}层下料完成,请启动第{self._current_unload_num}层下料"
|
||||
self.unloading_feedback_signal.emit("output", message)
|
||||
|
||||
# 恢复开始按钮原始样式
|
||||
self.restore_start_button_style()
|
||||
else:
|
||||
# 所有层都下料完成,重置寄存器和计数器
|
||||
modbus.write_register_until_success(client, 3, 0) # 确保下料启动寄存器为0
|
||||
@ -2034,6 +2111,9 @@ class MainWindow(MainWindowUI):
|
||||
# 通过信号触发UI更新,而不是直接操作UI
|
||||
message = f"托盘 {tray_code} 的所有 {total_tier} 层下料已全部完成"
|
||||
self.unloading_feedback_signal.emit("output", message)
|
||||
|
||||
# 恢复开始按钮原始样式
|
||||
self.restore_start_button_style()
|
||||
except Exception as e:
|
||||
logging.error(f"处理下料反馈时发生错误: {str(e)}")
|
||||
# 不在这里显示对话框,而是通过信号传递错误信息
|
||||
@ -2292,6 +2372,9 @@ class MainWindow(MainWindowUI):
|
||||
# 注册线径数据回调
|
||||
self.serial_manager.callbacks['xj_data'] = self.on_diameter_data_received
|
||||
|
||||
# 注册扫码器数据回调
|
||||
self.serial_manager.callbacks['scanner_data'] = self.on_scanner_data_received
|
||||
|
||||
# 自动打开已配置的串口
|
||||
self.serial_manager.auto_open_configured_ports()
|
||||
|
||||
@ -2402,6 +2485,33 @@ class MainWindow(MainWindowUI):
|
||||
except Exception as e:
|
||||
logging.error(f"处理线径数据失败: {str(e)}")
|
||||
|
||||
def on_scanner_data_received(self, port_name, data):
|
||||
"""扫码器数据接收回调函数
|
||||
|
||||
Args:
|
||||
port_name: 串口名称
|
||||
data: 接收到的数据
|
||||
"""
|
||||
try:
|
||||
# 解析数据
|
||||
data_str = data.decode('utf-8') if isinstance(data, bytes) else str(data)
|
||||
logging.info(f"收到扫码器数据: {data_str} 来自 {port_name}")
|
||||
|
||||
# 提取扫码数据,格式为"扫码数据: xxx"
|
||||
if "扫码数据:" in data_str:
|
||||
gc_note = data_str.split("扫码数据:")[1].strip()
|
||||
logging.info(f"提取到工程号: {gc_note}")
|
||||
|
||||
# 设置工程号到输入框
|
||||
self.order_edit.setText(gc_note)
|
||||
|
||||
# 模拟按下回车键,触发handle_order_enter方法
|
||||
self.handle_order_enter()
|
||||
else:
|
||||
logging.warning(f"收到的数据不包含扫码数据标记: {data_str}")
|
||||
except Exception as e:
|
||||
logging.error(f"处理扫码器数据失败: {str(e)}")
|
||||
|
||||
def set_inspection_value(self, data_type, config, value):
|
||||
"""设置检验项目值到表格中
|
||||
|
||||
|
||||
@ -32,6 +32,10 @@ class SerialSettingsWidget(SerialSettingsUI):
|
||||
self.xj_refresh_btn.clicked.connect(self.refresh_ports)
|
||||
self.test_xj_btn.clicked.connect(self.test_xj_port)
|
||||
|
||||
# 扫码器串口
|
||||
self.scanner_refresh_btn.clicked.connect(self.refresh_ports)
|
||||
self.test_scanner_btn.clicked.connect(self.test_scanner_port)
|
||||
|
||||
# 保存按钮
|
||||
self.save_btn.clicked.connect(self.save_settings)
|
||||
|
||||
@ -46,9 +50,18 @@ class SerialSettingsWidget(SerialSettingsUI):
|
||||
try:
|
||||
# 保存当前选择
|
||||
current_mdz_port = self.mdz_port_combo.currentData()
|
||||
current_xj_port = self.xj_port_combo.currentData()
|
||||
current_scanner_port = self.scanner_port_combo.currentData()
|
||||
|
||||
# 清空列表
|
||||
self.mdz_port_combo.clear()
|
||||
self.xj_port_combo.clear()
|
||||
self.scanner_port_combo.clear()
|
||||
|
||||
# 添加"不使用"选项
|
||||
self.mdz_port_combo.addItem("不使用", "")
|
||||
self.xj_port_combo.addItem("不使用", "")
|
||||
self.scanner_port_combo.addItem("不使用", "")
|
||||
|
||||
# 获取可用串口
|
||||
ports = list(serial.tools.list_ports.comports())
|
||||
@ -56,15 +69,40 @@ class SerialSettingsWidget(SerialSettingsUI):
|
||||
for port in ports:
|
||||
port_name = port.device
|
||||
port_desc = f"{port_name} ({port.description})"
|
||||
|
||||
# 添加到米电阻下拉框
|
||||
self.mdz_port_combo.addItem(port_desc, port_name)
|
||||
|
||||
# 添加到线径下拉框
|
||||
self.xj_port_combo.addItem(port_desc, port_name)
|
||||
|
||||
# 添加到扫码器下拉框
|
||||
self.scanner_port_combo.addItem(port_desc, port_name)
|
||||
|
||||
# 恢复之前的选择
|
||||
if current_mdz_port:
|
||||
index = self.mdz_port_combo.findData(current_mdz_port)
|
||||
if index >= 0:
|
||||
self.mdz_port_combo.setCurrentIndex(index)
|
||||
else:
|
||||
# 如果之前没有选择,则设为"不使用"
|
||||
self.mdz_port_combo.setCurrentIndex(0)
|
||||
|
||||
if current_xj_port:
|
||||
index = self.xj_port_combo.findData(current_xj_port)
|
||||
if index >= 0:
|
||||
self.xj_port_combo.setCurrentIndex(index)
|
||||
else:
|
||||
# 如果之前没有选择,则设为"不使用"
|
||||
self.xj_port_combo.setCurrentIndex(0)
|
||||
|
||||
if current_scanner_port:
|
||||
index = self.scanner_port_combo.findData(current_scanner_port)
|
||||
if index >= 0:
|
||||
self.scanner_port_combo.setCurrentIndex(index)
|
||||
else:
|
||||
# 如果之前没有选择,则设为"不使用"
|
||||
self.scanner_port_combo.setCurrentIndex(0)
|
||||
|
||||
logging.info(f"已刷新串口列表,找到 {len(ports)} 个串口")
|
||||
except Exception as e:
|
||||
@ -155,6 +193,39 @@ class SerialSettingsWidget(SerialSettingsUI):
|
||||
if index >= 0:
|
||||
self.xj_parity_combo.setCurrentIndex(index)
|
||||
|
||||
# 加载扫码器设置
|
||||
scanner_config = self.config.get_config('scanner')
|
||||
if scanner_config:
|
||||
# 设置串口
|
||||
scanner_port = scanner_config.get('ser', '')
|
||||
index = self.scanner_port_combo.findData(scanner_port)
|
||||
if index >= 0:
|
||||
self.scanner_port_combo.setCurrentIndex(index)
|
||||
|
||||
# 设置波特率
|
||||
scanner_baud = str(scanner_config.get('port', '9600'))
|
||||
index = self.scanner_baud_combo.findText(scanner_baud)
|
||||
if index >= 0:
|
||||
self.scanner_baud_combo.setCurrentIndex(index)
|
||||
|
||||
# 设置数据位
|
||||
scanner_data_bits = str(scanner_config.get('data_bits', '8'))
|
||||
index = self.scanner_data_bits_combo.findText(scanner_data_bits)
|
||||
if index >= 0:
|
||||
self.scanner_data_bits_combo.setCurrentIndex(index)
|
||||
|
||||
# 设置停止位
|
||||
scanner_stop_bits = str(scanner_config.get('stop_bits', '1'))
|
||||
index = self.scanner_stop_bits_combo.findText(scanner_stop_bits)
|
||||
if index >= 0:
|
||||
self.scanner_stop_bits_combo.setCurrentIndex(index)
|
||||
|
||||
# 设置校验位
|
||||
scanner_parity = scanner_config.get('parity', 'N')
|
||||
index = self.scanner_parity_combo.findData(scanner_parity)
|
||||
if index >= 0:
|
||||
self.scanner_parity_combo.setCurrentIndex(index)
|
||||
|
||||
logging.info("已加载串口设置")
|
||||
except Exception as e:
|
||||
logging.error(f"加载串口设置失败: {e}")
|
||||
@ -180,7 +251,6 @@ class SerialSettingsWidget(SerialSettingsUI):
|
||||
mdz_query_interval = self.mdz_query_interval.value()
|
||||
|
||||
mdz_config = {
|
||||
'ser': mdz_port,
|
||||
'port': mdz_baud,
|
||||
'data_bits': mdz_data_bits,
|
||||
'stop_bits': mdz_stop_bits,
|
||||
@ -189,6 +259,10 @@ class SerialSettingsWidget(SerialSettingsUI):
|
||||
'query_interval': mdz_query_interval
|
||||
}
|
||||
|
||||
# 只有当用户选择了串口时才保存串口配置
|
||||
if mdz_port:
|
||||
mdz_config['ser'] = mdz_port
|
||||
|
||||
self.config.set_config('mdz', mdz_config)
|
||||
|
||||
# 保存线径设置
|
||||
@ -199,17 +273,37 @@ class SerialSettingsWidget(SerialSettingsUI):
|
||||
xj_parity = self.xj_parity_combo.currentData()
|
||||
|
||||
xj_config = {
|
||||
'ser': xj_port,
|
||||
'port': xj_baud,
|
||||
'data_bits': xj_data_bits,
|
||||
'stop_bits': xj_stop_bits,
|
||||
'parity': xj_parity
|
||||
}
|
||||
|
||||
# 只有当用户选择了串口时才保存串口配置
|
||||
if xj_port:
|
||||
xj_config['ser'] = xj_port
|
||||
|
||||
self.config.set_config('xj', xj_config)
|
||||
|
||||
# 保存扫码器设置
|
||||
scanner_port = self.scanner_port_combo.currentData()
|
||||
scanner_baud = int(self.scanner_baud_combo.currentText())
|
||||
scanner_data_bits = int(self.scanner_data_bits_combo.currentText())
|
||||
scanner_stop_bits = float(self.scanner_stop_bits_combo.currentText())
|
||||
scanner_parity = self.scanner_parity_combo.currentData()
|
||||
|
||||
scanner_config = {
|
||||
'port': scanner_baud,
|
||||
'data_bits': scanner_data_bits,
|
||||
'stop_bits': scanner_stop_bits,
|
||||
'parity': scanner_parity
|
||||
}
|
||||
|
||||
# 只有当用户选择了串口时才保存串口配置
|
||||
if scanner_port:
|
||||
scanner_config['ser'] = scanner_port
|
||||
|
||||
self.config.set_config('scanner', scanner_config)
|
||||
|
||||
# 发送设置变更信号
|
||||
self.settings_changed.emit()
|
||||
@ -224,15 +318,16 @@ class SerialSettingsWidget(SerialSettingsUI):
|
||||
"""测试米电阻串口"""
|
||||
try:
|
||||
port = self.mdz_port_combo.currentData()
|
||||
|
||||
if not port:
|
||||
QMessageBox.warning(self, "测试失败", "请先选择串口,当前设置为\"不使用\"")
|
||||
return
|
||||
|
||||
baud = int(self.mdz_baud_combo.currentText())
|
||||
data_bits = int(self.mdz_data_bits_combo.currentText())
|
||||
stop_bits = float(self.mdz_stop_bits_combo.currentText())
|
||||
parity = self.mdz_parity_combo.currentData()
|
||||
|
||||
if not port:
|
||||
QMessageBox.warning(self, "测试失败", "请选择串口")
|
||||
return
|
||||
|
||||
# 关闭可能已经打开的串口
|
||||
if self.serial_manager.is_port_open(port):
|
||||
self.serial_manager.close_port(port)
|
||||
@ -248,44 +343,46 @@ class SerialSettingsWidget(SerialSettingsUI):
|
||||
if query_cmd:
|
||||
try:
|
||||
# 转换查询指令为字节
|
||||
query_bytes = bytes.fromhex(query_cmd.replace(' ', ''))
|
||||
cmd_bytes = bytes.fromhex(query_cmd.replace(' ', ''))
|
||||
self.serial_manager.write_data(port, cmd_bytes)
|
||||
time.sleep(0.1) # 等待响应
|
||||
|
||||
# 发送查询指令
|
||||
self.serial_manager.write_data(port, query_bytes)
|
||||
|
||||
# 等待一段时间
|
||||
time.sleep(0.5)
|
||||
# 读取响应
|
||||
response = self.serial_manager.read_data(port)
|
||||
if response:
|
||||
# 将字节转换为十六进制字符串
|
||||
hex_str = ' '.join(f'{b:02X}' for b in response)
|
||||
QMessageBox.information(self, "测试成功", f"串口打开成功,收到响应:\n{hex_str}")
|
||||
else:
|
||||
QMessageBox.information(self, "测试成功", "串口打开成功,但未收到响应")
|
||||
except Exception as e:
|
||||
QMessageBox.warning(self, "测试结果", f"串口打开成功,但发送指令失败: {e}")
|
||||
else:
|
||||
QMessageBox.information(self, "测试成功", "串口打开成功")
|
||||
|
||||
# 关闭串口
|
||||
self.serial_manager.close_port(port)
|
||||
else:
|
||||
QMessageBox.critical(self, "测试失败", f"无法打开串口 {port}")
|
||||
|
||||
QMessageBox.information(self, "测试成功", f"米电阻串口 {port} 测试成功,已发送查询指令")
|
||||
except Exception as e:
|
||||
self.serial_manager.close_port(port)
|
||||
QMessageBox.warning(self, "测试失败", f"发送查询指令失败: {e}")
|
||||
else:
|
||||
self.serial_manager.close_port(port)
|
||||
QMessageBox.information(self, "测试成功", f"米电阻串口 {port} 打开成功,但未发送查询指令")
|
||||
else:
|
||||
QMessageBox.warning(self, "测试失败", f"无法打开米电阻串口 {port}")
|
||||
except Exception as e:
|
||||
logging.error(f"测试米电阻串口失败: {e}")
|
||||
QMessageBox.warning(self, "测试失败", f"测试米电阻串口失败: {e}")
|
||||
|
||||
QMessageBox.critical(self, "测试失败", f"测试米电阻串口失败: {e}")
|
||||
|
||||
def test_xj_port(self):
|
||||
"""测试线径串口"""
|
||||
try:
|
||||
port = self.xj_port_combo.currentData()
|
||||
|
||||
if not port:
|
||||
QMessageBox.warning(self, "测试失败", "请先选择串口,当前设置为\"不使用\"")
|
||||
return
|
||||
|
||||
baud = int(self.xj_baud_combo.currentText())
|
||||
data_bits = int(self.xj_data_bits_combo.currentText())
|
||||
stop_bits = float(self.xj_stop_bits_combo.currentText())
|
||||
parity = self.xj_parity_combo.currentData()
|
||||
|
||||
if not port:
|
||||
QMessageBox.warning(self, "测试失败", "请选择串口")
|
||||
return
|
||||
|
||||
# 关闭可能已经打开的串口
|
||||
if self.serial_manager.is_port_open(port):
|
||||
self.serial_manager.close_port(port)
|
||||
@ -296,15 +393,68 @@ class SerialSettingsWidget(SerialSettingsUI):
|
||||
)
|
||||
|
||||
if success:
|
||||
# 等待一段时间
|
||||
time.sleep(2)
|
||||
QMessageBox.information(self, "测试成功", f"串口 {port} 打开成功")
|
||||
|
||||
# 关闭串口
|
||||
self.serial_manager.close_port(port)
|
||||
|
||||
QMessageBox.information(self, "测试成功", f"线径串口 {port} 测试成功")
|
||||
else:
|
||||
QMessageBox.warning(self, "测试失败", f"无法打开线径串口 {port}")
|
||||
QMessageBox.critical(self, "测试失败", f"无法打开串口 {port}")
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"测试线径串口失败: {e}")
|
||||
QMessageBox.warning(self, "测试失败", f"测试线径串口失败: {e}")
|
||||
QMessageBox.critical(self, "测试失败", f"测试线径串口失败: {e}")
|
||||
|
||||
def test_scanner_port(self):
|
||||
"""测试扫码器串口"""
|
||||
try:
|
||||
port = self.scanner_port_combo.currentData()
|
||||
|
||||
if not port:
|
||||
QMessageBox.warning(self, "测试失败", "请先选择串口,当前设置为\"不使用\"")
|
||||
return
|
||||
|
||||
baud = int(self.scanner_baud_combo.currentText())
|
||||
data_bits = int(self.scanner_data_bits_combo.currentText())
|
||||
stop_bits = float(self.scanner_stop_bits_combo.currentText())
|
||||
parity = self.scanner_parity_combo.currentData()
|
||||
|
||||
# 关闭可能已经打开的串口
|
||||
if self.serial_manager.is_port_open(port):
|
||||
self.serial_manager.close_port(port)
|
||||
|
||||
# 尝试打开串口
|
||||
success = self.serial_manager.open_port(
|
||||
port, 'scanner', baud, data_bits, stop_bits, parity, 1.0
|
||||
)
|
||||
|
||||
if success:
|
||||
QMessageBox.information(self, "测试成功", f"串口 {port} 打开成功\n请触发扫码器进行扫描测试")
|
||||
|
||||
# 尝试读取数据(短暂等待扫码器输入)
|
||||
start_time = time.time()
|
||||
timeout = 5.0 # 5秒超时
|
||||
|
||||
while time.time() - start_time < timeout:
|
||||
response = self.serial_manager.read_data(port)
|
||||
if response:
|
||||
# 尝试将字节解码为字符串
|
||||
try:
|
||||
text = response.decode('utf-8').strip()
|
||||
QMessageBox.information(self, "测试成功", f"收到扫码数据:\n{text}")
|
||||
break
|
||||
except:
|
||||
# 如果解码失败,显示十六进制
|
||||
hex_str = ' '.join(f'{b:02X}' for b in response)
|
||||
QMessageBox.information(self, "测试成功", f"收到扫码数据 (十六进制):\n{hex_str}")
|
||||
break
|
||||
|
||||
time.sleep(0.1) # 短暂休眠,减少CPU占用
|
||||
|
||||
# 关闭串口
|
||||
self.serial_manager.close_port(port)
|
||||
else:
|
||||
QMessageBox.critical(self, "测试失败", f"无法打开串口 {port}")
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"测试扫码器串口失败: {e}")
|
||||
QMessageBox.critical(self, "测试失败", f"测试扫码器串口失败: {e}")
|
||||
@ -85,28 +85,28 @@ class SettingsWidget(SettingsUI):
|
||||
self.pallet_type_settings = PalletTypeSettingsWidget(self)
|
||||
self.plc_settings = PLCSettingsWidget(self)
|
||||
|
||||
# 创建电量监控设置组件
|
||||
# 创建电力监控设置组件
|
||||
try:
|
||||
self.electricity_settings = ElectricitySettingsUI(self)
|
||||
logging.info("电量监控设置组件创建成功")
|
||||
logging.info("电力监控设置组件创建成功")
|
||||
|
||||
# 移除临时占位符标签并添加电量监控设置部件
|
||||
# 移除临时占位符标签并添加电力监控设置部件
|
||||
if hasattr(self, 'electricity_placeholder'):
|
||||
logging.info("移除电量监控临时占位符")
|
||||
logging.info("移除电力监控临时占位符")
|
||||
self.electricity_layout.removeWidget(self.electricity_placeholder)
|
||||
self.electricity_placeholder.hide()
|
||||
self.electricity_placeholder.deleteLater()
|
||||
else:
|
||||
logging.warning("未找到电量监控临时占位符标签")
|
||||
logging.warning("未找到电力监控临时占位符标签")
|
||||
|
||||
# 检查布局是否可用
|
||||
if hasattr(self, 'electricity_layout'):
|
||||
logging.info("添加电量监控设置部件到布局")
|
||||
logging.info("添加电力监控设置部件到布局")
|
||||
self.electricity_layout.addWidget(self.electricity_settings)
|
||||
else:
|
||||
logging.error("无法找到electricity_layout布局")
|
||||
except Exception as e:
|
||||
logging.error(f"初始化电量监控设置组件失败: {e}")
|
||||
logging.error(f"初始化电力监控设置组件失败: {e}")
|
||||
|
||||
# 移除临时占位符标签并添加检验设置部件
|
||||
if hasattr(self, 'inspection_placeholder'):
|
||||
@ -172,13 +172,13 @@ class SettingsWidget(SettingsUI):
|
||||
self.pallet_type_settings.settings_changed.connect(self.on_settings_changed)
|
||||
self.plc_settings.settings_changed.connect(self.on_settings_changed)
|
||||
|
||||
# 连接电量监控设置信号
|
||||
# 连接电力监控设置信号
|
||||
if hasattr(self, 'electricity_settings'):
|
||||
try:
|
||||
self.electricity_settings.settings_changed.connect(self.on_settings_changed)
|
||||
logging.info("已连接电量监控设置信号")
|
||||
logging.info("已连接电力监控设置信号")
|
||||
except Exception as e:
|
||||
logging.error(f"连接电量监控设置信号时出错: {e}")
|
||||
logging.error(f"连接电力监控设置信号时出错: {e}")
|
||||
|
||||
# 不再在这里连接刷新按钮,避免重复连接
|
||||
logging.info("刷新按钮已在初始化时连接,不再重复连接")
|
||||
|
||||
@ -28,54 +28,23 @@ class SettingsWindow(QDialog):
|
||||
self.settings_widget = SettingsWidget(self)
|
||||
main_layout.addWidget(self.settings_widget)
|
||||
|
||||
# 添加串口设置到标签页
|
||||
self.serial_settings = SerialSettingsWidget(self)
|
||||
self.settings_widget.tab_widget.addTab(self.serial_settings, "串口设置")
|
||||
|
||||
# 应用相机刷新按钮修复
|
||||
try:
|
||||
# 先尝试直接找到刷新按钮并添加事件处理
|
||||
logging.info("尝试直接查找刷新按钮并添加事件处理...")
|
||||
from PySide6.QtWidgets import QPushButton
|
||||
|
||||
# 在整个UI层次中查找刷新设备按钮
|
||||
refresh_buttons = []
|
||||
for widget in self.findChildren(QPushButton):
|
||||
if widget.text() == "刷新设备":
|
||||
refresh_buttons.append(widget)
|
||||
|
||||
if refresh_buttons:
|
||||
logging.info(f"找到 {len(refresh_buttons)} 个刷新设备按钮")
|
||||
for i, button in enumerate(refresh_buttons):
|
||||
try:
|
||||
# 断开现有连接
|
||||
button.clicked.disconnect()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 连接到相机设置的刷新方法
|
||||
if hasattr(self.settings_widget, 'camera_settings') and hasattr(self.settings_widget.camera_settings, 'refresh_devices'):
|
||||
button.clicked.connect(self.settings_widget.camera_settings.refresh_devices)
|
||||
logging.info(f"已将刷新按钮 #{i+1} 连接到refresh_devices方法")
|
||||
|
||||
# 尝试调用一次
|
||||
self.settings_widget.camera_settings.refresh_devices()
|
||||
logging.info("已手动调用refresh_devices方法初始化设备列表")
|
||||
|
||||
# 使用导入的修复模块作为备选方案
|
||||
try:
|
||||
# 使用相对导入,更可靠
|
||||
from . import refresh_devices_fix
|
||||
refresh_devices_fix.fix_camera_refresh_button(self.settings_widget)
|
||||
logging.info("已应用相机刷新按钮修复(通过相对导入)")
|
||||
except ImportError:
|
||||
# 如果相对导入失败,尝试绝对导入
|
||||
try:
|
||||
import refresh_devices_fix
|
||||
refresh_devices_fix.fix_camera_refresh_button(self.settings_widget)
|
||||
logging.info("已应用相机刷新按钮修复(通过绝对导入)")
|
||||
except ImportError:
|
||||
# 如果绝对导入也失败,直接内联实现修复逻辑
|
||||
logging.warning("导入refresh_devices_fix失败,使用内联修复")
|
||||
self._fix_camera_refresh_button()
|
||||
except Exception as e:
|
||||
logging.error(f"应用相机刷新按钮修复失败: {str(e)}")
|
||||
|
||||
# 添加按钮
|
||||
self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
|
||||
self.button_box.accepted.connect(self.accept)
|
||||
self.button_box.rejected.connect(self.reject)
|
||||
main_layout.addWidget(self.button_box)
|
||||
|
||||
# 连接信号
|
||||
self.serial_settings.settings_changed.connect(self.settings_changed.emit)
|
||||
|
||||
logging.info("SettingsWindow初始化完成")
|
||||
|
||||
def _fix_camera_refresh_button(self):
|
||||
"""内联实现的刷新按钮修复逻辑,用于导入模块失败的情况"""
|
||||
@ -135,26 +104,6 @@ class SettingsWindow(QDialog):
|
||||
except Exception as e:
|
||||
logging.error(f"内联修复相机刷新按钮时发生错误: {str(e)}")
|
||||
|
||||
# 添加串口设置到标签页
|
||||
self.serial_settings = SerialSettingsWidget(self)
|
||||
self.settings_widget.tab_widget.addTab(self.serial_settings, "串口设置")
|
||||
|
||||
# 添加电力监控设置到标签页
|
||||
self.electricity_settings = ElectricitySettingsUI(self)
|
||||
self.settings_widget.tab_widget.addTab(self.electricity_settings, "电力监控")
|
||||
|
||||
# 添加按钮
|
||||
self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
|
||||
self.button_box.accepted.connect(self.accept)
|
||||
self.button_box.rejected.connect(self.reject)
|
||||
main_layout.addWidget(self.button_box)
|
||||
|
||||
# 连接信号
|
||||
self.serial_settings.settings_changed.connect(self.settings_changed.emit)
|
||||
self.electricity_settings.settings_changed.connect(self.settings_changed.emit)
|
||||
|
||||
logging.info("SettingsWindow初始化完成")
|
||||
|
||||
def accept(self):
|
||||
"""确认按钮处理,保存所有设置并发送设置变更信号"""
|
||||
# 通知设置已变更
|
||||
|
||||
Loading…
Reference in New Issue
Block a user