diff --git a/.gitignore b/.gitignore index 6fb6717..4570eb6 100644 --- a/.gitignore +++ b/.gitignore @@ -32,4 +32,6 @@ dist/ PyQt_Fluent_Widgets.egg-info/ PySide6_Fluent_Widgets.egg-info/ PyQt6_Fluent_Widgets.egg-info/ -PySide2_Fluent_Widgets.egg-info/ \ No newline at end of file +PySide2_Fluent_Widgets.egg-info/ +/hardware/__pycache__ +__pycache__ diff --git a/hardware/__pycache__/__init__.cpython-39.pyc b/hardware/__pycache__/__init__.cpython-39.pyc deleted file mode 100644 index c70084f..0000000 Binary files a/hardware/__pycache__/__init__.cpython-39.pyc and /dev/null differ diff --git a/hardware/__pycache__/inverter.cpython-39.pyc b/hardware/__pycache__/inverter.cpython-39.pyc deleted file mode 100644 index d3fae76..0000000 Binary files a/hardware/__pycache__/inverter.cpython-39.pyc and /dev/null differ diff --git a/hardware/__pycache__/relay.cpython-39.pyc b/hardware/__pycache__/relay.cpython-39.pyc deleted file mode 100644 index 3bd4bf5..0000000 Binary files a/hardware/__pycache__/relay.cpython-39.pyc and /dev/null differ diff --git a/hardware/__pycache__/transmitter.cpython-39.pyc b/hardware/__pycache__/transmitter.cpython-39.pyc deleted file mode 100644 index bbd5444..0000000 Binary files a/hardware/__pycache__/transmitter.cpython-39.pyc and /dev/null differ diff --git a/hardware/transmitter.py b/hardware/transmitter.py index dd72798..1bd2ef4 100644 --- a/hardware/transmitter.py +++ b/hardware/transmitter.py @@ -20,7 +20,8 @@ class TransmitterController: } } - def read_data_back(self, transmitter_id): + # 备份 (modbus 读取数据) + def read_data_bak(self, transmitter_id): """读取变送器数据""" try: if transmitter_id not in self.config: @@ -68,7 +69,7 @@ class TransmitterController: finally: self.relay_controller.modbus_client.close() - # 直接读取 变送器返回的数据 + # 直接读取 变送器返回的数据并解析 def read_data(self, transmitter_id): """ Args: transmitter_id 为1 表示上料斗, 为2 表示下料斗 @@ -79,6 +80,7 @@ class TransmitterController: IP = "192.168.250.63" PORT = 502 TIMEOUT = 5 # 超时时间为 5秒 + BUFFER_SIZE= 1024 weight = None import socket @@ -86,34 +88,83 @@ class TransmitterController: try: s.settimeout(TIMEOUT) s.connect((IP, PORT)) - print(f"✅ 连接 {IP}:{PORT} 成功") + # print(f"连接上料斗变送器 {IP}:{PORT} 成功") - # 接收数据(变送器主动推送,单次recv即可获取一条完整数据) - data = s.recv(1024) + # 接收数据(变送器主动推送,recv即可获取数据) + data = s.recv(BUFFER_SIZE) if data: # print(f"收到原始数据:{data}") - weight = self.parse_weight(data) + + # 提取出完整的一个数据包 (\r\n结尾) + packet = self.get_latest_valid_packet(data) + if not packet: + print("未获取到有效数据包!!") + return None + # 解析重量 + weight = self.parse_weight(packet) else: - print("❌ 未收到设备数据") + print("未收到设备数据") except ConnectionRefusedError: - print(f"❌ 连接失败:{IP}:{PORT} 拒绝连接(设备离线/端口错误)") + print(f"连接失败:{IP}:{PORT} 拒绝连接(设备离线/端口错误)") except socket.timeout: - print(f"❌ 超时:{TIMEOUT}秒内未收到数据") + print(f"超时:{TIMEOUT}秒内未收到数据") except Exception as e: - print(f"❌ 读取异常:{e}") + print(f"读取异常:{e}") # 成功返回重量(int),失败返回None return weight + + def get_latest_valid_packet(self, raw_data): + """ + 解决TCP粘包: + 从原始数据中,筛选所有有效包,返回最新的一个有效包 + 有效包标准: 1. 能UTF-8解码 2. 按逗号拆分≥3个字段 3. 第三个字段含数字(重量) + """ + DELIMITER = b'\r\n' + # 1. 按分隔符拆分,过滤空包 + packets = [p for p in raw_data.split(DELIMITER) if p] + if not packets: + return None - def parse_weight(raw_data): - """解析函数:提取重量数值(如从 b'ST,NT,+0000175\r\n' 中提取 175)""" + valid_packets = [] + for packet in packets: + try: + # 过滤无效ASCII字符(只保留可见字符) + valid_chars = [c for c in packet if 32 <= c <= 126] + filtered_packet = bytes(valid_chars) + # 2. 验证解码 + data_str = filtered_packet.decode('utf-8').strip() + # 3. 验证字段数量 + parts = data_str.split(',') + if len(parts) < 3: + continue + # 4. 验证重量字段含数字 + weight_part = parts[2].strip() + if not any(char.isdigit() for char in weight_part): + continue + # 满足所有条件,加入有效包列表 + valid_packets.append(packet) + except (UnicodeDecodeError, IndexError): + # 解码失败或字段异常,跳过该包 + continue + + # 返回最后一个有效包(最新),无有效包则返回None + return valid_packets[-1] if valid_packets else None + + def parse_weight(self, packet_data): + """解析重量函数:提取重量数值(如从 b'ST,NT,+0000175\r\n' 中提取 175)""" try: - data_str = raw_data.decode('utf-8').strip() + data_str = packet_data.decode('utf-8').strip() parts = data_str.split(',') + # 确保有完整的数据包,三个字段 + if len(parts) < 3: + print(f"parse_weight: 包格式错误(字段不足):{data_str}") + return None + weight_part = parts[2].strip() return int(''.join(filter(str.isdigit, weight_part))) except (IndexError, ValueError, UnicodeDecodeError) as e: - # print(f"数据解析失败:{e},原始数据:{raw_data}") - # 注意:可能会出现解析失败的情况,此时返回None,界面不用更新数据就行 - return None \ No newline at end of file + # print(f"数据解析失败:{e},原始数据包:{packet_data}") + return None + \ No newline at end of file