1190 lines
52 KiB
Python
1190 lines
52 KiB
Python
import asyncio
|
||
import copy
|
||
import re
|
||
import threading
|
||
|
||
import numpy as np
|
||
|
||
from andon_flask_client import SimpleAndonSender
|
||
from calculate import BatteryStackAnalyzer
|
||
from dataTransmission import data_transmission
|
||
from plc_client import *
|
||
from dao.dbutils import *
|
||
import time
|
||
import flet as ft
|
||
import struct
|
||
from typing import List, Tuple, Dict, Any, Optional
|
||
import requests
|
||
from collections import defaultdict
|
||
import sys
|
||
sys.path.append(r'D:\battery')
|
||
# 创建 BatteryDatabase 实例
|
||
battery_db = BatteryDatabase()
|
||
sender = SimpleAndonSender()
|
||
print("=== Andon 发送端测试 ===")
|
||
|
||
|
||
class PlcDataProcessor:
|
||
def __init__(self, ip_address: str, port: int, tcp_host: str = "0.0.0.0", tcp_port: int = 1024):
|
||
self.plc = PlcClient(ip_address, port)
|
||
self.real_time_data = [] # 示例数据
|
||
self._get_130_data = []
|
||
self.read_attempts = 5 # 读取尝试次数
|
||
self.battery_data_with_list_130 = [] # 130数据录入缓存
|
||
self.battery_data_with_list_566 = [] # 566据录入缓存
|
||
self.battery_data_with_list_130 = battery_db.get_latest_battery_data(limit=2000)
|
||
self.tcp_host = tcp_host
|
||
self.tcp_port = tcp_port
|
||
self.server_socket = None
|
||
self.is_running = False
|
||
self.data_manager = []
|
||
self.temp_data = ''
|
||
self.sel_version = '2.0'
|
||
self.run_thread()
|
||
# def read_and_process_data(self, page: ft.Page):
|
||
# """主循环函数,读取并处理PLC数据"""
|
||
# while True:
|
||
# try:
|
||
# # 发送实时数据到UI页面
|
||
# if page:
|
||
# page.pubsub.send_all(self.real_time_data)
|
||
# self._process_cycle()
|
||
# except Exception as e:
|
||
# print(f"发生错误: {e}")
|
||
# time.sleep(3)
|
||
|
||
def read_and_process_data(self, page: ft.Page):
|
||
"""主循环函数,读取并处理PLC数据"""
|
||
while True:
|
||
try:
|
||
# 获取不同类型的数据
|
||
data_130 = self._get_130_data
|
||
real_time_data = self.real_time_data
|
||
|
||
# 发送到不同的消息频道
|
||
if page:
|
||
# 发送130数据到特定频道
|
||
page.pubsub.send_all({
|
||
'message_type': 'data_130',
|
||
'payload': data_130,
|
||
'timestamp': time.time()
|
||
})
|
||
page.pubsub.send_all({
|
||
'message_type': 'real_time',
|
||
'payload': real_time_data,
|
||
'timestamp': time.time()
|
||
})
|
||
|
||
self._process_cycle()
|
||
except Exception as e:
|
||
print(f"发生错误: {e}")
|
||
time.sleep(3)
|
||
|
||
def _get_updated_real_time_data(self, shen_7, data_all):
|
||
"""获取更新的实时数据"""
|
||
# 这里可以根据实际需求从PLC或其他数据源获取实时数据
|
||
# 示例:返回当前时间戳和一些模拟数据
|
||
return {'shen_7': shen_7, 'all': data_all}
|
||
|
||
def read_main_data(self):
|
||
"""主循环函数,读取并处理PLC数据"""
|
||
while True:
|
||
self._process_cycle()
|
||
time.sleep(3)
|
||
|
||
def _process_cycle(self):
|
||
|
||
"""处理一个完整的数据读取周期"""
|
||
m_values, err = self.plc.read_multiple_m(1000, 25)
|
||
print(m_values, "mmmmmmmmmm")
|
||
ok, errr = self.plc.write_m(1003, False)
|
||
if ok:
|
||
print(f"M1003 写入成功")
|
||
if err:
|
||
print("读取M值错误")
|
||
return
|
||
|
||
# 一次性发送所有状态
|
||
sender.send_mes_thread(m_values)
|
||
|
||
if m_values[0]:
|
||
# 处理不同的M值条件
|
||
sel_version = '' # 是否上料130片
|
||
sel_566_version = '' # 是否上料566片
|
||
if m_values[5]:
|
||
sel_version = '2.0'
|
||
self.sel_version = '2.0'
|
||
elif m_values[6]:
|
||
sel_version = '2.5'
|
||
self.sel_version = '2.5'
|
||
|
||
if sel_version == '2.0':
|
||
bat_data = self._process_zr_data(sel_version)
|
||
print('bat_data', bat_data)
|
||
if bat_data is not None:
|
||
P_A_130, P_C_130, source_code_130 = BatteryStackAnalyzer.convert_battery_data_simple_130(
|
||
parse_all_battery_data_130(bat_data))
|
||
T_10_130 = [1.0] * len(P_A_130) # 使用默认厚度值
|
||
analyzer_130 = BatteryStackAnalyzer(P_A_130, P_C_130, T_10_130, source_code_130)
|
||
results_130 = analyzer_130.analyze_all()
|
||
data_list = (results_130['all_invalid_positions']["阳极压损不满足"] +
|
||
results_130['all_invalid_positions']["阴极压损不满足"] +
|
||
results_130['all_invalid_positions']["精度检测不满足"])
|
||
|
||
if data_list:
|
||
self.plc.write_m(1026, True)
|
||
self.data_write_130(1000, list(set(data_list)))
|
||
self.data_write_130(1800, results_130['all_invalid_positions']["重复数据"])
|
||
else:
|
||
# 写入数据
|
||
battery_data_130 = parse_all_battery_data_130(bat_data)
|
||
self._get_130_data = battery_data_130
|
||
list_data = battery_data_130['box_data_1']['battery_data_1'] + \
|
||
battery_data_130['box_data_2']['battery_data_2']
|
||
list_data = list_data[::-1]
|
||
battery_data_130_save = {
|
||
'cah_no': '',
|
||
'box_data_1': {
|
||
'box_data_1_no': '',
|
||
'battery_data_1': []
|
||
},
|
||
'box_data_2': {
|
||
'box_data_2_no': '',
|
||
'battery_data_2': []
|
||
},
|
||
}
|
||
battery_data_with = []
|
||
for i in range(1, 131):
|
||
item = list_data[i - 1]
|
||
# 创建基础字典
|
||
new_item = {
|
||
'code': item.get('serial_number', ''),
|
||
'top_qr_code': item.get('Up_QR', ''),
|
||
'bottom_qr_code': item.get('Below_QR', ''),
|
||
'h2_value': item.get('H2', 0),
|
||
'o2_value': item.get('02', 0),
|
||
'symbol': item.get('Cell_ran', ''),
|
||
'thickness': item.get('thick', ''),
|
||
'notes': item.get('source_code', ''),
|
||
'magazine_code': battery_data_130['cah_no'],
|
||
'magazine_index': i,
|
||
}
|
||
new_item_save = {
|
||
'serial_number': item.get('serial_number', ''),
|
||
'Up_QR': item.get('Up_QR', ''),
|
||
'Below_QR': item.get('Below_QR', ''),
|
||
'H2': item.get('H2', 0),
|
||
'02': item.get('02', 0),
|
||
'Cell_ran': item.get('Cell_ran', ''),
|
||
'thick': item.get('thick', ''),
|
||
'source_code': item.get('source_code', ''),
|
||
'magazine_index': i,
|
||
}
|
||
battery_data_130_save['cah_no'] = battery_data_130['cah_no']
|
||
battery_data_130_save['box_data_1']['box_data_1_no'] = battery_data_130['box_data_1'][
|
||
'box_data_1_no']
|
||
battery_data_130_save['box_data_2']['box_data_2_no'] = battery_data_130['box_data_2'][
|
||
'box_data_2_no']
|
||
# 添加box_code
|
||
if i <= 65:
|
||
new_item['box_code'] = battery_data_130['box_data_1']['box_data_1_no']
|
||
new_item['box_index'] = 1
|
||
new_item_save['box_index'] = 1
|
||
battery_data_130_save['box_data_1']['battery_data_1'].append(new_item_save)
|
||
else:
|
||
new_item['box_code'] = battery_data_130['box_data_2']['box_data_2_no']
|
||
new_item['box_index'] = 2
|
||
new_item_save['box_index'] = 2
|
||
battery_data_130_save['box_data_2']['battery_data_2'].append(new_item_save)
|
||
battery_data_with.append(new_item)
|
||
if len(self.battery_data_with_list_130) < 3000:
|
||
self.battery_data_with_list_130.extend(battery_data_with)
|
||
else:
|
||
self.battery_data_with_list_130.pop(0)
|
||
self.battery_data_with_list_130.extend(battery_data_with)
|
||
try:
|
||
magazine_id = battery_db.create_magazine(
|
||
magazine_code=battery_data_130_save['cah_no'],
|
||
description=""
|
||
)
|
||
box_data = [battery_data_130_save["box_data_1"]["box_data_1_no"],
|
||
battery_data_130_save["box_data_2"]["box_data_2_no"]]
|
||
box_ids = []
|
||
for desc in box_data:
|
||
try:
|
||
box_id = battery_db.create_box(magazine_id, desc)
|
||
box_ids.append(box_id)
|
||
except ValueError as e:
|
||
print(f"{desc} 创建失败: {e}")
|
||
|
||
battery_data = [
|
||
{"id": box_ids[0], "data": battery_data_130_save['box_data_1']['battery_data_1']},
|
||
{"id": box_ids[1], "data": battery_data_130_save['box_data_2']['battery_data_2']},
|
||
]
|
||
for battery in battery_data:
|
||
battery_db.add_batch_batteries(
|
||
battery['id'],
|
||
battery['data']
|
||
)
|
||
print("写入数据")
|
||
except ValueError as e:
|
||
print(f"创建失败: {e}")
|
||
self.plc.write_m(1005, False)
|
||
self.plc.write_m(1022, True)
|
||
elif sel_version == '2.5':
|
||
bat_data = self._process_zr_data(sel_version)
|
||
if bat_data is not None:
|
||
P_A_130, P_C_130, source_code_130 = BatteryStackAnalyzer.convert_battery_data_simple_130(
|
||
parse_all_battery_data_130(bat_data))
|
||
T_10_130 = [1.0] * len(P_A_130) # 使用默认厚度值
|
||
analyzer_130 = BatteryStackAnalyzer(P_A_130, P_C_130, T_10_130, source_code_130)
|
||
results_130 = analyzer_130.analyze_all()
|
||
data_list = (results_130['all_invalid_positions']["阳极压损不满足"] +
|
||
results_130['all_invalid_positions']["阴极压损不满足"] +
|
||
results_130['all_invalid_positions']["精度检测不满足"])
|
||
|
||
if data_list:
|
||
self.plc.write_m(1027, True)
|
||
self.data_write_130(2000, list(set(data_list)))
|
||
self.data_write_130(2800, results_130['all_invalid_positions']["重复数据"])
|
||
else:
|
||
|
||
# 写入数据
|
||
|
||
battery_data_130 = parse_all_battery_data_130(bat_data)
|
||
self._get_130_data = battery_data_130
|
||
list_data = battery_data_130['box_data_1']['battery_data_1'] + \
|
||
battery_data_130['box_data_2']['battery_data_2']
|
||
list_data = list_data[::-1]
|
||
battery_data_130_save = {
|
||
'cah_no': '',
|
||
'box_data_1': {
|
||
'box_data_1_no': '',
|
||
'battery_data_1': []
|
||
},
|
||
'box_data_2': {
|
||
'box_data_2_no': '',
|
||
'battery_data_2': []
|
||
},
|
||
}
|
||
battery_data_with = []
|
||
for i in range(1, 131):
|
||
item = list_data[i - 1]
|
||
# 创建基础字典
|
||
new_item = {
|
||
'code': item.get('serial_number', ''),
|
||
'top_qr_code': item.get('Up_QR', ''),
|
||
'bottom_qr_code': item.get('Below_QR', ''),
|
||
'h2_value': item.get('H2', 0),
|
||
'o2_value': item.get('02', 0),
|
||
'symbol': item.get('Cell_ran', ''),
|
||
'thickness': item.get('thick', ''),
|
||
'notes': item.get('source_code', ''),
|
||
'magazine_code': battery_data_130['cah_no'],
|
||
'magazine_index': i,
|
||
}
|
||
new_item_save = {
|
||
'serial_number': item.get('serial_number', ''),
|
||
'Up_QR': item.get('Up_QR', ''),
|
||
'Below_QR': item.get('Below_QR', ''),
|
||
'H2': item.get('H2', 0),
|
||
'02': item.get('02', 0),
|
||
'Cell_ran': item.get('Cell_ran', ''),
|
||
'thick': item.get('thick', ''),
|
||
'source_code': item.get('source_code', ''),
|
||
'magazine_index': i,
|
||
}
|
||
battery_data_130_save['cah_no'] = battery_data_130['cah_no']
|
||
battery_data_130_save['box_data_1']['box_data_1_no'] = battery_data_130['box_data_1'][
|
||
'box_data_1_no']
|
||
battery_data_130_save['box_data_2']['box_data_2_no'] = battery_data_130['box_data_2'][
|
||
'box_data_2_no']
|
||
# 添加box_code
|
||
if i <= 65:
|
||
new_item['box_code'] = battery_data_130['box_data_1']['box_data_1_no']
|
||
new_item['box_index'] = 1
|
||
new_item_save['box_index'] = 1
|
||
battery_data_130_save['box_data_1']['battery_data_1'].append(new_item_save)
|
||
else:
|
||
new_item['box_code'] = battery_data_130['box_data_2']['box_data_2_no']
|
||
new_item['box_index'] = 2
|
||
new_item_save['box_index'] = 2
|
||
battery_data_130_save['box_data_2']['battery_data_2'].append(new_item_save)
|
||
battery_data_with.append(new_item)
|
||
if len(self.battery_data_with_list_130) < 3000:
|
||
self.battery_data_with_list_130.extend(battery_data_with)
|
||
else:
|
||
self.battery_data_with_list_130.pop(0)
|
||
self.battery_data_with_list_130.extend(battery_data_with)
|
||
try:
|
||
magazine_id = battery_db.create_magazine(
|
||
magazine_code=battery_data_130_save['cah_no'],
|
||
description=""
|
||
)
|
||
box_data = [battery_data_130_save["box_data_1"]["box_data_1_no"],
|
||
battery_data_130_save["box_data_2"]["box_data_2_no"]]
|
||
box_ids = []
|
||
for desc in box_data:
|
||
try:
|
||
box_id = battery_db.create_box(magazine_id, desc)
|
||
box_ids.append(box_id)
|
||
except ValueError as e:
|
||
print(f"{desc} 创建失败: {e}")
|
||
|
||
battery_data = [
|
||
{"id": box_ids[0], "data": battery_data_130_save['box_data_1']['battery_data_1']},
|
||
{"id": box_ids[1], "data": battery_data_130_save['box_data_2']['battery_data_2']},
|
||
]
|
||
for battery in battery_data:
|
||
battery_db.add_batch_batteries(
|
||
battery['id'],
|
||
battery['data']
|
||
)
|
||
print("写入数据")
|
||
except ValueError as e:
|
||
print(f"创建失败: {e}")
|
||
self.plc.write_m(1006, False)
|
||
self.plc.write_m(1023, True)
|
||
if m_values[4]:
|
||
if m_values[7]:
|
||
sel_566_version = '2.0'
|
||
elif m_values[8]:
|
||
sel_566_version = '2.5'
|
||
if sel_566_version == '2.0':
|
||
data_566 = self._process_zr_566_data(sel_566_version)
|
||
print('data_566',data_566)
|
||
if data_566 and data_566.get('cah_data'):
|
||
data_566['cah_data'] = [item.replace('\x00', '') for item in data_566['cah_data']]
|
||
P_A_566, P_C_566, source_code_566 = BatteryStackAnalyzer.convert_battery_data_simple_566(
|
||
parse_all_battery_data_566(data_566))
|
||
T_10_566 = [1.0] * len(P_A_566) # 使用默认厚度值
|
||
analyzer_566 = BatteryStackAnalyzer(P_A_566, P_C_566, T_10_566, source_code_566)
|
||
results_566 = analyzer_566.analyze_all()
|
||
# 修复后的代码
|
||
result_data566 = []
|
||
# 使用可哈希的字段作为键,比如source_code
|
||
dj_lookup = {item['notes']: item for item in self.battery_data_with_list_130}
|
||
|
||
for sublist in parse_all_battery_data_566(data_566)['cah_data']:
|
||
# sublist现在是字典,我们需要用它的某个字段来匹配
|
||
# 根据你的数据结构,应该使用source_code字段
|
||
source_code = sublist.get('source_code', '')
|
||
if source_code in dj_lookup:
|
||
matched_dj = dj_lookup[source_code]
|
||
result_data566.append(matched_dj)
|
||
|
||
# 按 magazine_code 分组
|
||
grouped_data = defaultdict(list)
|
||
for item in result_data566:
|
||
grouped_data[item['magazine_code']].append(item)
|
||
|
||
# 对每个杂志内的数据倒序排列
|
||
result = []
|
||
for magazine_code, items in grouped_data.items():
|
||
reversed_items = list(reversed(items))
|
||
result.extend(reversed_items)
|
||
|
||
print('result_data566', result)
|
||
if results_566["低压电池"] != '满足条件的单电池数量不足7片(只有0片)':
|
||
self.real_time_data = self._get_updated_real_time_data(results_566["低压电池"],
|
||
result)
|
||
self.shen_7_data_write(results_566["低压电池"])
|
||
self.plc.write_m(1024, True)
|
||
elif sel_566_version == '2.5':
|
||
data_566 = self._process_zr_566_data(sel_566_version)
|
||
if data_566 and data_566.get('cah_data'):
|
||
data_566['cah_data'] = [item.replace('\x00', '') for item in data_566['cah_data']]
|
||
P_A_566, P_C_566, source_code_566 = BatteryStackAnalyzer.convert_battery_data_simple_566(
|
||
parse_all_battery_data_566(data_566))
|
||
T_10_566 = [1.0] * len(P_A_566) # 使用默认厚度值
|
||
analyzer_566 = BatteryStackAnalyzer(P_A_566, P_C_566, T_10_566, source_code_566)
|
||
results_566 = analyzer_566.analyze_all()
|
||
result_data566 = []
|
||
dj_lookup = {item['notes']: item for item in self.battery_data_with_list_130}
|
||
for sublist in parse_all_battery_data_566(data_566)['cah_data']:
|
||
matched_dj = dj_lookup[sublist]
|
||
if sublist in dj_lookup:
|
||
result_data566.append(matched_dj)
|
||
# 按 magazine_code 分组
|
||
grouped_data = defaultdict(list)
|
||
for item in result_data566:
|
||
grouped_data[item['magazine_code']].append(item)
|
||
|
||
# 对每个杂志内的数据倒序排列
|
||
result = []
|
||
for magazine_code, items in grouped_data.items():
|
||
reversed_items = list(reversed(items))
|
||
result.extend(reversed_items)
|
||
if results_566["低压电池"] != '满足条件的单电池数量不足7片(只有0片)':
|
||
self.real_time_data = self._get_updated_real_time_data(results_566["低压电池"],
|
||
result)
|
||
self.shen_7_data_write(results_566["低压电池"])
|
||
self.plc.write_m(1024, True)
|
||
if m_values[9]:
|
||
print('data_566_2发送')
|
||
data_566_2 = self._process_zr_566_manage_data("2.0")
|
||
print('data_566_2', data_566_2)
|
||
if data_566_2 and data_566_2.get('cah_data'):
|
||
data_566_2['cah_data'] = [item.replace('\x00', '') for item in data_566_2['cah_data']]
|
||
result = {'cah_data': []}
|
||
for index, data_string in enumerate(data_566_2['cah_data']):
|
||
# 每46个字符分一份
|
||
chunks = [data_string[i:i + 46] for i in range(0, len(data_string), 46)]
|
||
if index < 69:
|
||
chunks = chunks[:8]
|
||
else:
|
||
chunks = chunks[:7]
|
||
result['cah_data'].append(chunks)
|
||
|
||
self.battery_data_with_list_566 = parse_all_battery_data_566_2(result)['cah_data']
|
||
# 首先将嵌套的dj展平为一维列表
|
||
dj_lookup = {item['notes']: item for item in self.battery_data_with_list_130}
|
||
# 处理dj1中的数据
|
||
for sublist in self.battery_data_with_list_566: # 遍历dj1中的每个子列表
|
||
for item in sublist: # 遍历子列表中的每个字典
|
||
source_code = item['source_code']
|
||
if source_code in dj_lookup:
|
||
# 获取dj中对应的完整数据
|
||
matched_dj = dj_lookup[source_code]
|
||
# 将dj中多出的字段添加到dj1
|
||
item['magazine_code'] = matched_dj['magazine_code']
|
||
item['magazine_index'] = matched_dj['magazine_index']
|
||
item['box_code'] = matched_dj['box_code']
|
||
item['box_index'] = matched_dj['box_index']
|
||
data_566_2_list = {'cah_data': self.battery_data_with_list_566}
|
||
try:
|
||
# 创建批次
|
||
batch_id = battery_db.create_batch(
|
||
batch_name='',
|
||
description=""
|
||
)
|
||
|
||
# 定义分组规则
|
||
groups = list(range(1, 72)) # 对应的group_id
|
||
|
||
# 准备批量数据
|
||
battery_data_list = []
|
||
battery_data_with_groups = []
|
||
|
||
data_index = 1
|
||
# 遍历所有数据行
|
||
for i, battery_row in enumerate(data_566_2_list['cah_data']):
|
||
# 跳过空行
|
||
if not battery_row:
|
||
continue
|
||
|
||
# 分配group_id(如果组数不够,使用默认值1)
|
||
group_id = groups[i] if i < len(groups) else 1
|
||
|
||
# 遍历每行中的电池数据
|
||
for battery_encoded in battery_row[::-1]:
|
||
# 解析电池数据
|
||
battery_data = self.parse_battery_data(battery_encoded)
|
||
if battery_data:
|
||
# 准备电池数据字典
|
||
battery_dict = {
|
||
'code': battery_data['serial_number'],
|
||
'top_qr_code': battery_data.get('Below_QR', '').strip(),
|
||
'bottom_qr_code': battery_data.get('Up_QR', '').strip(),
|
||
'h2_value': float(battery_data.get('H2', 0)),
|
||
'o2_value': float(battery_data.get('O2', 0)),
|
||
'symbol': battery_data.get('Cell_ran', ''),
|
||
'thickness': float(battery_data.get('thick', 0)),
|
||
'notes': battery_data.get('source_code', ''),
|
||
'status': 'normal',
|
||
'data_index': data_index,
|
||
'box_code': battery_data['box_code'],
|
||
'box_index': float(battery_data.get('box_index', 0)),
|
||
'magazine_code': battery_data['magazine_code'],
|
||
'magazine_index': float(battery_data.get('magazine_index', 0)),
|
||
}
|
||
|
||
# 添加到批量列表
|
||
battery_data_list.append(battery_dict)
|
||
battery_data_with_groups.append((battery_dict, group_id))
|
||
data_index += 1
|
||
record_ids = battery_db.add_save_battery_data_batch_with_groups(batch_id, battery_data_with_groups)
|
||
print(f"成功批量添加 {len(record_ids)} 条电池数据到数据库")
|
||
data_list = []
|
||
P_A = [] # 阳极压损 - 使用H2字段
|
||
P_C = [] # 阴极压损 - 使用02字段
|
||
for battery_data, group_id in battery_data_with_groups:
|
||
P_A.append(battery_data['h2_value'])
|
||
P_C.append(battery_data['o2_value'])
|
||
P_A_ww = np.mean(P_A)
|
||
P_C_ww = np.mean(P_C)
|
||
|
||
for battery_data, group_id in battery_data_with_groups:
|
||
is_shen7 = False
|
||
if battery_data['data_index'] > (len(battery_data_with_groups) - 7):
|
||
is_shen7 = True
|
||
PA_ratios_h2, PC_ratios_02, PA_invalid_indices, PC_invalid_indices = check_pressure_requirements(
|
||
battery_data['h2_value'], battery_data['o2_value'], P_A_ww, P_C_ww)
|
||
|
||
data_list.append(
|
||
{'cell_counter': int(battery_data['magazine_index']),
|
||
"separator1": battery_data['bottom_qr_code'],
|
||
"separator2": battery_data['top_qr_code'], "delta_P_h2": battery_data['h2_value'],
|
||
"delta_P_o2": battery_data['o2_value'],
|
||
"cell_rank": battery_data['symbol'], "thickness": battery_data['thickness'],
|
||
"god_seven_mark": is_shen7,
|
||
"cell_index": battery_data['data_index'],
|
||
"h2_compute": round(float(PA_ratios_h2), 2),
|
||
"h2_result": PA_invalid_indices, "o2_compute": round(float(PC_ratios_02), 2),
|
||
"o2_result": PC_invalid_indices,
|
||
'clip_barcode': battery_data["magazine_code"]
|
||
})
|
||
asyncio.run(data_transmission(data_list))
|
||
self.battery_data_with_list_566 = []
|
||
print('顺序566保存完成')
|
||
self.plc.write_m(1025, True)
|
||
except KeyError as e:
|
||
print(f"数据字段错误: {e}")
|
||
except Exception as e:
|
||
print(f"添加电池数据时发生错误: {e}")
|
||
import traceback
|
||
print(f"详细错误信息: {traceback.format_exc()}")
|
||
# 重置标志位
|
||
self.plc.write_m(1000, False)
|
||
|
||
def parse_battery_data(self, encoded_string):
|
||
"""
|
||
解析电池数据编码字符串
|
||
"""
|
||
try:
|
||
parsed_data = {
|
||
'serial_number': encoded_string['serial_number'],
|
||
'Below_QR': encoded_string['Below_QR'],
|
||
'Up_QR': encoded_string['Up_QR'],
|
||
'H2': encoded_string['H2'],
|
||
'O2': encoded_string['02'],
|
||
'Cell_ran': encoded_string['Cell_ran'],
|
||
'thick': encoded_string['thick'],
|
||
'box_code': encoded_string['box_code'],
|
||
'box_index': encoded_string['box_index'],
|
||
'source_code': encoded_string['source_code'],
|
||
'magazine_code': encoded_string['magazine_code'],
|
||
'magazine_index': encoded_string['magazine_index'],
|
||
}
|
||
return parsed_data
|
||
except Exception as e:
|
||
print(f"解析电池数据时发生错误: {e}")
|
||
return None
|
||
|
||
def _process_zr_data(self, version):
|
||
"""读取并处理 不同版本 弹夹位置"""
|
||
if version == '2.0':
|
||
address = 200000
|
||
count = 4100
|
||
elif version == '2.5':
|
||
address = 205000
|
||
count = 4100
|
||
else:
|
||
return None
|
||
|
||
# 单次最多读 500
|
||
zr_data = []
|
||
for i in range(0, count, 500):
|
||
if i < count - 500:
|
||
temp_data, _ = self.plc.read_r_batch(address + i, 500)
|
||
else:
|
||
temp_data, _ = self.plc.read_r_batch(address + i, count - i)
|
||
if temp_data:
|
||
zr_data.extend(temp_data)
|
||
else:
|
||
print(f"ZR{address + i} 批量读取失败")
|
||
return None
|
||
|
||
print(f"ZR{address} 原始数据长度: {len(zr_data)}")
|
||
if not zr_data:
|
||
print(f"读取ZR{address}数据失败")
|
||
return None
|
||
|
||
# 分别提取不同参数的数据
|
||
cah_data = self.connect_data(zr_data, 1, 0, count=100) # 弹夹数据
|
||
cah_data = cah_data.replace("\r", "").replace("\x00", "").replace('\x07', '')
|
||
temp_str = ''.join(zr_data)
|
||
data_string = temp_str.replace('\x00', '').replace('\r', '').replace('\n', '').replace('â\x01', '')
|
||
|
||
json_datas = split_json_objects(data_string)
|
||
if len(json_datas) != 4:
|
||
return None
|
||
|
||
box_data_1_no = json_datas[0].get("header", None)
|
||
battery_data_1 = []
|
||
if box_data_1_no:
|
||
box_data_1_no = box_data_1_no.get("filename", None)
|
||
battery_data_1_1 = json_datas[0].get('data')
|
||
battery_data_1_2 = json_datas[1].get('data')
|
||
if battery_data_1_1 and battery_data_1_2:
|
||
battery_data_1 = battery_data_1_1 + battery_data_1_2
|
||
battery_data_1 = [battery_data_1[i:i + 46] for i in range(0, len(battery_data_1), 46)]
|
||
|
||
box_data_2_no = json_datas[2].get("header", None)
|
||
if box_data_2_no:
|
||
box_data_2_no = box_data_2_no.get("filename", None)
|
||
battery_data_2_1 = json_datas[2].get('data')
|
||
battery_data_2_2 = json_datas[3].get('data')
|
||
battery_data_2 = []
|
||
if battery_data_2_1 and battery_data_2_2:
|
||
battery_data_2 = battery_data_2_1 + battery_data_2_2
|
||
battery_data_2 = [battery_data_2[i:i + 46] for i in range(0, len(battery_data_2), 46)]
|
||
|
||
data = {"cah_no": cah_data,
|
||
"box_data_1": {
|
||
"box_data_1_no": box_data_1_no,
|
||
"battery_data_1": battery_data_1},
|
||
"box_data_2": {
|
||
"box_data_2_no": box_data_2_no,
|
||
"battery_data_2": battery_data_2},
|
||
}
|
||
return data
|
||
|
||
def _process_zr_566_data(self, version):
|
||
"""读取并处理 566 数据"""
|
||
if version == '2.0':
|
||
address = 210000
|
||
count = 13019
|
||
elif version == '2.5':
|
||
address = 230000
|
||
count = 13019
|
||
else:
|
||
return None
|
||
|
||
# 单次最多读 500
|
||
zr_data_566 = []
|
||
for i in range(0, count, 500):
|
||
if i < count - 500:
|
||
temp_data, _ = self.plc.read_r_batch(address + i, 500)
|
||
else:
|
||
temp_data, _ = self.plc.read_r_batch(address + i, count - i)
|
||
|
||
if temp_data:
|
||
zr_data_566.extend(temp_data)
|
||
else:
|
||
print(f"ZR{address + i} 批量读取失败")
|
||
|
||
if not zr_data_566:
|
||
print(f"读取ZR{address}数据失败")
|
||
return None
|
||
|
||
# 提取 电池信息
|
||
cah_data = self.connect_data_2_list(zr_data_566, 23, 0, count=13019) # 弹夹数据
|
||
data = {
|
||
"cah_data": cah_data
|
||
}
|
||
# 添加到结果列表
|
||
return data
|
||
|
||
def _process_zr_566_manage_data(self, version):
|
||
""" 566 数据 处理后 有分组"""
|
||
if version == '2.0':
|
||
address = 250000
|
||
count = 14201
|
||
elif version == '2.5':
|
||
address = 230000
|
||
count = 13018
|
||
else:
|
||
return None
|
||
|
||
# 单次最多读 500
|
||
zr_data_566 = []
|
||
for i in range(0, count, 500):
|
||
if i < count - 500:
|
||
temp_data, _ = self.plc.read_r_batch(address + i, 500)
|
||
else:
|
||
temp_data, _ = self.plc.read_r_batch(address + i, count - i)
|
||
|
||
if temp_data:
|
||
zr_data_566.extend(temp_data)
|
||
else:
|
||
print(f"ZR{address + i} 批量读取失败")
|
||
|
||
if not zr_data_566:
|
||
print(f"读取ZR{address}数据失败")
|
||
return None
|
||
# 提取 电池信息
|
||
cah_data = self.connect_data_2_list(zr_data_566, 200, 0, count=200 * 69 + 1)
|
||
cah_data1 = self.connect_data_2_list(zr_data_566, 200, 200 * 69, count=401)
|
||
# 弹夹数据
|
||
cah_data.extend(cah_data1)
|
||
data = {
|
||
"cah_data": cah_data
|
||
}
|
||
# 添加到结果列表
|
||
return data
|
||
|
||
@staticmethod
|
||
def extract_data_pairs(zr_data: List[str], interval: int = 25,
|
||
start_offset: int = 15, count: int = 2) -> List[Dict[str, Any]]:
|
||
"""
|
||
按照指定间隔和起始偏移提取多个数据
|
||
|
||
参数:
|
||
zr_data: 原始数据列表
|
||
interval: 数据间隔
|
||
start_offset: 起始偏移位置
|
||
count: 要提取的数据数量
|
||
|
||
返回格式: [{'values': [v1, v2, v3], 'positions': [p1, p2, p3], 'float_values': [f1, f2, f3]}, ...]
|
||
"""
|
||
extracted_groups = []
|
||
max_groups = (len(zr_data) - start_offset - count + 1) // interval
|
||
|
||
for group_index in range(max_groups + 1):
|
||
base_index = group_index * interval
|
||
positions = [base_index + start_offset + i for i in range(count)]
|
||
|
||
# 检查所有位置是否有效
|
||
if all(pos < len(zr_data) for pos in positions):
|
||
values = [zr_data[pos] for pos in positions]
|
||
|
||
# 对每两个相邻的值进行浮点数转换(如果有偶数个值)
|
||
float_values = []
|
||
for i in range(0, len(values) - 1, 2):
|
||
float_val = PlcDataProcessor.combine_to_float(values[i], values[i + 1])
|
||
float_values.append(float_val)
|
||
|
||
extracted_groups.append({
|
||
'values': values,
|
||
'positions': positions,
|
||
'float_values': float_values,
|
||
'group_index': group_index
|
||
})
|
||
|
||
return extracted_groups
|
||
|
||
@staticmethod
|
||
def connect_data(zr_data: List[str], interval: int = 25,
|
||
start_offset: int = 15, count: int = 2):
|
||
"""
|
||
按照指定间隔和起始偏移提取多个数据
|
||
|
||
参数:
|
||
zr_data: 原始数据列表
|
||
interval: 数据间隔
|
||
start_offset: 起始偏移位置
|
||
count: 要提取的数据数量
|
||
|
||
返回格式: [{'values': [v1, v2, v3], 'positions': [p1, p2, p3], 'float_values': [f1, f2, f3]}, ...]
|
||
"""
|
||
end_offset = start_offset + count if (start_offset + count) < len(zr_data) else len(zr_data)
|
||
values = ''
|
||
for group_index in range(start_offset, end_offset):
|
||
values += str(zr_data[group_index])
|
||
|
||
return values
|
||
|
||
@staticmethod
|
||
def connect_data_2_list(zr_data: List[str], interval,
|
||
start_offset, count: int = 2):
|
||
"""
|
||
按照指定间隔和起始偏移提取多个数据
|
||
|
||
参数:
|
||
zr_data: 原始数据列表
|
||
interval: 数据间隔
|
||
start_offset: 起始偏移位置
|
||
count: 要提取的数据数量
|
||
"""
|
||
end_offset = start_offset + count if (start_offset + count) < len(zr_data) else len(zr_data)
|
||
data_list = []
|
||
index = 0
|
||
values = ''
|
||
for group_index in range(start_offset, end_offset):
|
||
|
||
if index % interval == 0 and group_index != start_offset:
|
||
data_list.append(values)
|
||
values = ''
|
||
values += str(zr_data[group_index])
|
||
index += 1
|
||
|
||
return data_list
|
||
|
||
@staticmethod
|
||
def combine_to_int32(low_word: int, high_word: int) -> int:
|
||
"""将两个16位整数合成32位有符号整数"""
|
||
return (high_word << 16) | (low_word & 0xFFFF)
|
||
|
||
@staticmethod
|
||
def combine_to_float(low_word: int, high_word: int) -> float:
|
||
"""将两个16位整数合成32位浮点数"""
|
||
int32_value = PlcDataProcessor.combine_to_int32(low_word, high_word)
|
||
try:
|
||
float_bytes = struct.pack('>I', int32_value & 0xFFFFFFFF)
|
||
return struct.unpack('>f', float_bytes)[0]
|
||
except (struct.error, TypeError):
|
||
return float('nan')
|
||
|
||
@staticmethod
|
||
def data_calculate():
|
||
|
||
pass
|
||
|
||
@staticmethod
|
||
# 数据保存
|
||
def data_saving(batch_name: str, description: str):
|
||
# 创建数据库实例
|
||
db = BatteryDatabase()
|
||
# 创建新批次
|
||
batch_id = db.create_batch(batch_name, description)
|
||
print(f"创建批次成功,批次ID: {batch_id}")
|
||
return batch_id
|
||
|
||
def shen_7_data_write(self, shen_7_data):
|
||
|
||
# shen_7_data: 7片低压QR数据
|
||
shen_7_data_str = ''
|
||
for qr_data in shen_7_data:
|
||
shen_7_data_str += qr_data
|
||
res, _ = self.plc.write_d_shen_7_batch(start_address=1200, values=shen_7_data_str)
|
||
if res:
|
||
print("shen 7 低压损2.0写人成功")
|
||
else:
|
||
print("shen 7 低压损2.0写人失败")
|
||
|
||
def shen_7_data_write_25(self, shen_7_data):
|
||
# shen_7_data: 7片低压QR数据
|
||
shen_7_data_str = ''
|
||
for qr_data in shen_7_data:
|
||
shen_7_data_str += qr_data
|
||
res, _ = self.plc.write_d_shen_7_batch(start_address=2200, values=shen_7_data_str)
|
||
if res:
|
||
print("shen 7 低压损2.5写人成功")
|
||
else:
|
||
print("shen 7 低压损2.5写人失败")
|
||
|
||
def data_write_130(self, start_address, data):
|
||
# shen_7_data: 7片低压QR数据
|
||
data_str = ''
|
||
for qr_data in data:
|
||
data_str += qr_data
|
||
res, _ = self.plc.write_d_130_batch(start_address=start_address, values=data_str)
|
||
if res:
|
||
print("shen 7 上料扫码NG2.0人成功")
|
||
else:
|
||
print("shen 7 上料扫码NG2.0写人失败")
|
||
|
||
# def shen_7_data_write_13025(self, shen_7_data):
|
||
# # shen_7_data: 7片低压QR数据
|
||
# shen_7_data_str = ''
|
||
# for qr_data in shen_7_data:
|
||
# shen_7_data_str += qr_data
|
||
# res, _ = self.plc.write_d_shen_7_batch(start_address=2000, values=shen_7_data_str)
|
||
# if res:
|
||
# print("shen 7 上料扫码NG2.5人成功")
|
||
# else:
|
||
# print("shen 7 上料扫码NG2.5写人失败")
|
||
|
||
# 下方为TCP 服务器端程序
|
||
def handle_client(self, client_socket, client_address):
|
||
"""处理客户端连接"""
|
||
client_id = f"{client_address[0]}:{client_address[1]}"
|
||
logger.info(f"客户端连接: {client_id}")
|
||
|
||
client_ip = client_address[0]
|
||
try:
|
||
while self.is_running:
|
||
# 根据ip将不同数据进行筛选
|
||
if (self.sel_version == '2.0' and (client_ip == '192.168.2.14')) \
|
||
or (self.sel_version == '2.5' and (client_ip == '192.168.2.15')):
|
||
data = client_socket.recv(2048)
|
||
logger.info(f"收到数据: {data}")
|
||
if not data:
|
||
break
|
||
recv_content = data.decode("utf-8")
|
||
self.temp_data += recv_content
|
||
if recv_content.endswith("\r"):
|
||
# 结束符
|
||
# 数据处理 往plc中写入 todo
|
||
# 2.0丛D4001开始 到 D5999
|
||
# 2.5从D6000开始 到 D7999
|
||
self.write_130_batch(self.temp_data, self.sel_version)
|
||
|
||
|
||
send_content = "recv ok"
|
||
# 对字符串进行编码成为二进制数据
|
||
response = send_content.encode("utf-8")
|
||
if response:
|
||
client_socket.send(response)
|
||
else:
|
||
# 默认响应
|
||
client_socket.send(f"收到: {recv_content}".encode("utf-8"))
|
||
|
||
except Exception as e:
|
||
logger.error(f"客户端处理错误: {e}")
|
||
finally:
|
||
client_socket.close()
|
||
logger.info(f"客户端断开: {client_id}")
|
||
|
||
def run(self):
|
||
"""运行服务器"""
|
||
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||
self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||
self.server_socket.bind((self.tcp_host, self.tcp_port))
|
||
self.server_socket.listen(128)
|
||
self.server_socket.settimeout(1.0)
|
||
|
||
self.is_running = True
|
||
logger.info(f"服务器启动: {self.tcp_host}:{self.tcp_port}")
|
||
|
||
try:
|
||
while self.is_running:
|
||
try:
|
||
client_socket, client_address = self.server_socket.accept()
|
||
thread = threading.Thread(
|
||
target=self.handle_client,
|
||
args=(client_socket, client_address),
|
||
daemon=True
|
||
)
|
||
thread.start()
|
||
except socket.timeout:
|
||
continue
|
||
except KeyboardInterrupt:
|
||
logger.info("服务器关闭")
|
||
finally:
|
||
self.stop()
|
||
|
||
def write_130_batch(self, write_data, sel_version):
|
||
# 写入后需要改变 标记位寄存器的值, 写入前需要查询标记位数寄存器 的值
|
||
# print(write_data)
|
||
if self.sel_version == '2.0':
|
||
m_values, err = self.plc.read_multiple_m(1013, 1)
|
||
elif self.sel_version == '2.5':
|
||
m_values, err = self.plc.read_multiple_m(1014, 1)
|
||
else:
|
||
m_values = None
|
||
print('&&&&&')
|
||
print(m_values)
|
||
if m_values and m_values[0] == 1:
|
||
temp_list = []
|
||
if len(write_data) > 1000:
|
||
for i in range(0, len(write_data), 1000):
|
||
temp_list.append(write_data[i:i+1000])
|
||
else:
|
||
temp_list.append(write_data)
|
||
for index, data_item in enumerate(temp_list):
|
||
if sel_version == '2.0':
|
||
res, _ = self.plc.write_d_130_ascii_batch(start_address=4001 + index * 500, values=data_item)
|
||
if res:
|
||
print("130 上料扫码NG2.0人成功")
|
||
else:
|
||
print("130 上料扫码NG2.0写人失败")
|
||
d4038, d_err = self.plc.read_d(4038)
|
||
if d_err:
|
||
print(f"回读 D4038 失败: {d_err}")
|
||
else:
|
||
c1 = chr(d4038 & 0xFF) if 32 <= (d4038 & 0xFF) < 127 else '.'
|
||
c2 = chr((d4038 >> 8) & 0xFF) if 32 <= ((d4038 >> 8) & 0xFF) < 127 else '.'
|
||
print(f"回读 D4038: raw={d4038} hex={d4038:04X} ascii='{c1}{c2}'")
|
||
elif sel_version == '2.5':
|
||
res, _ = self.plc.write_d_130_ascii_batch(start_address=6000 + index * 500, values=data_item)
|
||
if res:
|
||
print("130 上料扫码NG2.5人成功")
|
||
else:
|
||
print("130 上料扫码NG2.5写人失败")
|
||
elif m_values and m_values[0] == 0:
|
||
temp_list = []
|
||
if len(write_data) > 1000:
|
||
for i in range(0, len(write_data), 1000):
|
||
temp_list.append(write_data[i:i+1000])
|
||
else:
|
||
temp_list.append(write_data)
|
||
for index, data_item in enumerate(temp_list):
|
||
if sel_version == '2.0':
|
||
res, _ = self.plc.write_d_130_ascii_batch(start_address=4001 + index * 500, values=data_item)
|
||
if res:
|
||
print("130 上料扫码NG2.0人成功")
|
||
else:
|
||
print("130 上料扫码NG2.0写人失败")
|
||
d4038, d_err = self.plc.read_d(4038)
|
||
if d_err:
|
||
print(f"回读 D4038 失败: {d_err}")
|
||
else:
|
||
c1 = chr(d4038 & 0xFF) if 32 <= (d4038 & 0xFF) < 127 else '.'
|
||
c2 = chr((d4038 >> 8) & 0xFF) if 32 <= ((d4038 >> 8) & 0xFF) < 127 else '.'
|
||
print(f"回读 D4038: raw={d4038} hex={d4038:04X} ascii='{c1}{c2}'")
|
||
elif sel_version == '2.5':
|
||
res, _ = self.plc.write_d_130_ascii_batch(start_address=6000 + index * 500, values=data_item)
|
||
if res:
|
||
print("130 上料扫码NG2.5人成功")
|
||
else:
|
||
print("130 上料扫码NG2.5写人失败")
|
||
# 数据置空
|
||
self.temp_data = ''
|
||
|
||
def stop(self):
|
||
"""停止服务器"""
|
||
self.is_running = False
|
||
if self.server_socket:
|
||
self.server_socket.close()
|
||
|
||
def run_thread(self):
|
||
thread = threading.Thread(target=self.run)
|
||
thread.start()
|
||
|
||
|
||
# 通用方法
|
||
def check_pressure_requirements(P_A, P_C, P_A_ww, P_C_ww):
|
||
# 检查阳极压损比例要求
|
||
PA_ratios_h2 = P_A / P_A_ww
|
||
PA_invalid_indices = (PA_ratios_h2 > 0.80) and (PA_ratios_h2 < 1.125)
|
||
if PA_invalid_indices:
|
||
PA_invalid_indices = 'OK'
|
||
else:
|
||
PA_invalid_indices = 'NG'
|
||
# 检查阴极压损比例要求
|
||
PC_ratios_02 = P_C / P_C_ww
|
||
PC_invalid_indices = (PC_ratios_02 > 0.80) and (PC_ratios_02 < 1.20)
|
||
if PA_invalid_indices:
|
||
PC_invalid_indices = 'OK'
|
||
else:
|
||
PC_invalid_indices = 'NG'
|
||
return PA_ratios_h2, PC_ratios_02, PA_invalid_indices, PC_invalid_indices
|
||
|
||
|
||
def parse_all_battery_data_130(data):
|
||
"""
|
||
解析所有battery_data,将字符串格式转换为结构化字典
|
||
"""
|
||
if data is None:
|
||
return None
|
||
# 创建数据的深拷贝
|
||
import copy
|
||
parsed_data = copy.deepcopy(data)
|
||
# 解析 battery_data_1 (57条数据)
|
||
parsed_battery_data_1 = []
|
||
for item in data['box_data_1']['battery_data_1']:
|
||
parsed_item = {
|
||
'serial_number': item[0:2],
|
||
'Up_QR': item[2:17],
|
||
'Below_QR': item[17:32],
|
||
'H2': int(item[32:36]) / 100,
|
||
'02': int(item[36:40]) / 100,
|
||
'Cell_ran': item[40],
|
||
'thick': int(item[41:]) / 10000,
|
||
'source_code': item,
|
||
}
|
||
parsed_battery_data_1.append(parsed_item)
|
||
|
||
# 解析 battery_data_2 (8条数据)
|
||
parsed_battery_data_2 = []
|
||
for item in data['box_data_2']['battery_data_2']:
|
||
parsed_item = {
|
||
'serial_number': item[0:2],
|
||
'Up_QR': item[2:17],
|
||
'Below_QR': item[17:32],
|
||
'H2': int(item[32:36]) / 100,
|
||
'02': int(item[36:40]) / 100,
|
||
'Cell_ran': item[40],
|
||
'thick': int(item[41:]) / 10000,
|
||
'source_code': item,
|
||
}
|
||
parsed_battery_data_2.append(parsed_item)
|
||
|
||
# 替换battery_data部分
|
||
parsed_data['box_data_1']['battery_data_1'] = parsed_battery_data_1
|
||
parsed_data['box_data_2']['battery_data_2'] = parsed_battery_data_2
|
||
return parsed_data
|
||
|
||
|
||
def parse_all_battery_data_566(data):
|
||
"""
|
||
解析所有battery_data,将字符串格式转换为结构化字典
|
||
"""
|
||
if data is not None:
|
||
# 创建数据的深拷贝
|
||
import copy
|
||
parsed_data = copy.deepcopy(data)
|
||
parsed_battery_data_3 = []
|
||
for item in data['cah_data']:
|
||
parsed_item = {
|
||
'serial_number': item[0:2],
|
||
'Up_QR': item[2:17],
|
||
'Below_QR': item[17:32],
|
||
'H2': int(item[32:36]) / 100,
|
||
'02': int(item[36:40]) / 100,
|
||
'Cell_ran': item[40],
|
||
'thick': item[41:],
|
||
'source_code': item,
|
||
}
|
||
parsed_battery_data_3.append(parsed_item)
|
||
parsed_data['cah_data'] = parsed_battery_data_3
|
||
return parsed_data
|
||
return None
|
||
|
||
|
||
def parse_all_battery_data_566_2(data):
|
||
"""
|
||
解析所有battery_data,将字符串格式转换为结构化字典
|
||
"""
|
||
result = {'cah_data': []}
|
||
for battery_list in data['cah_data']:
|
||
if not battery_list: # 如果是空列表
|
||
result['cah_data'].append([])
|
||
continue
|
||
|
||
parsed_battery_data = []
|
||
for item in battery_list:
|
||
parsed_item = {
|
||
'serial_number': item[0:2],
|
||
'Up_QR': item[2:17],
|
||
'Below_QR': item[17:32],
|
||
'H2': int(item[32:36]) / 100,
|
||
'02': int(item[36:40]) / 100,
|
||
'Cell_ran': item[40],
|
||
'thick': int(item[41:]) / 10000,
|
||
'source_code': item,
|
||
}
|
||
parsed_battery_data.append(parsed_item)
|
||
|
||
result['cah_data'].append(parsed_battery_data)
|
||
|
||
return result
|
||
|
||
|
||
def split_json_objects(data_string):
|
||
# 匹配以 { 开头,到 } 结束的完整对象
|
||
if not data_string:
|
||
return []
|
||
|
||
brace_count = 0
|
||
current_object = ''
|
||
json_objects = []
|
||
in_object = False
|
||
for char in data_string:
|
||
if char == '{':
|
||
if not in_object:
|
||
in_object = True
|
||
brace_count += 1
|
||
if in_object:
|
||
current_object += char
|
||
if char == '}':
|
||
brace_count -= 1
|
||
if brace_count == 0 and in_object:
|
||
# 找到一个完整的JSON对象
|
||
json_objects.append(current_object)
|
||
current_object = ''
|
||
in_object = False
|
||
try:
|
||
json_objects = [json.loads(str_data) for str_data in json_objects]
|
||
except Exception as e:
|
||
print(e, '&&&')
|
||
return []
|
||
return json_objects
|
||
|
||
|
||
def start(page: ft.Page):
|
||
"""启动函数"""
|
||
processor = PlcDataProcessor('192.168.2.1', 4995)
|
||
processor.read_and_process_data(page)
|
||
|
||
def main():
|
||
"""启动函数"""
|
||
processor = PlcDataProcessor('192.168.2.1', 4995)
|
||
processor.read_main_data()
|
||
#
|
||
#
|
||
if __name__ == "__main__":
|
||
main()
|