积累修改;
This commit is contained in:
35739
source/Interactive-2.ipynb
Normal file
35739
source/Interactive-2.ipynb
Normal file
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ from pathlib import Path
|
|||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
import matplotlib.dates as mdates
|
import matplotlib.colors as mcolors
|
||||||
from sqlalchemy import create_engine
|
from sqlalchemy import create_engine
|
||||||
from sqlalchemy import MetaData, Table, Column, String, Float, Integer, DateTime
|
from sqlalchemy import MetaData, Table, Column, String, Float, Integer, DateTime
|
||||||
|
|
||||||
@@ -45,6 +45,20 @@ SemaMap_adapter = {
|
|||||||
'curr_out': ('0305121001', 'adapter', True, "输出电流"),
|
'curr_out': ('0305121001', 'adapter', True, "输出电流"),
|
||||||
'power_out': ('0305122001', 'adapter', True, "输出功率"),
|
'power_out': ('0305122001', 'adapter', True, "输出功率"),
|
||||||
}
|
}
|
||||||
|
semamap_combiner = {
|
||||||
|
|
||||||
|
'IMSI': ('0305102001', 'combiner', False, "IMSI"),
|
||||||
|
'ICCID': ('0305103001', 'combiner', False, "SIM卡ICCID"),
|
||||||
|
'MSISDN': ('0305104001', 'combiner', False, "MSISDN"),
|
||||||
|
'dev_type': ('0305101001', 'combiner', False, "系统类型"),
|
||||||
|
'facturer': ('0305107001', 'combiner', False, "汇流箱厂家"),
|
||||||
|
'model': ('0305108001', 'combiner', False, "汇流箱型号"),
|
||||||
|
'ver_software': ('0305105001', 'combiner', False, "软件版本"),
|
||||||
|
'ver_hardware': ('0305106001', 'combiner', False, "硬件版本"),
|
||||||
|
'power_total': ('0305109001', 'combiner', True, "系统总功率"),
|
||||||
|
'energy_total': ('0305110001', 'combiner', True, "系统累计发电量"),
|
||||||
|
'energy_daily': ('0305111001', 'combiner', True, "系统日发电量"),
|
||||||
|
}
|
||||||
SemaMap_meter = {
|
SemaMap_meter = {
|
||||||
'mtr_id': ('0305123001', 'meter', False, "电表号"),
|
'mtr_id': ('0305123001', 'meter', False, "电表号"),
|
||||||
'mtr_volt': ('0305124001', 'meter', True, "直流电压"),
|
'mtr_volt': ('0305124001', 'meter', True, "直流电压"),
|
||||||
@@ -198,8 +212,9 @@ class Lamina_Data(object):
|
|||||||
print(f"Get data success, len={len(json_data['data'])}")
|
print(f"Get data success, len={len(json_data['data'])}")
|
||||||
table_data = pd.DataFrame(json_data['data'])
|
table_data = pd.DataFrame(json_data['data'])
|
||||||
column_name = sorted(table_data.columns)
|
column_name = sorted(table_data.columns)
|
||||||
|
table_data['dev'] = device_id
|
||||||
table_data['time'] = table_data['updateTime'].apply(lambda x: int(time.mktime(time.strptime(x, r"%Y-%m-%d %H:%M:%S"))))
|
table_data['time'] = table_data['updateTime'].apply(lambda x: int(time.mktime(time.strptime(x, r"%Y-%m-%d %H:%M:%S"))))
|
||||||
table_data = table_data[['time', *column_name]].drop(columns='updateTime')
|
table_data = table_data[['time', 'dev', *column_name]].drop(columns='updateTime')
|
||||||
return table_data
|
return table_data
|
||||||
else:
|
else:
|
||||||
print(f"Get data fail, code={json_data['code']}, msg=\n\t{json_data['message']}")
|
print(f"Get data fail, code={json_data['code']}, msg=\n\t{json_data['message']}")
|
||||||
@@ -345,12 +360,13 @@ class Lamina_Data(object):
|
|||||||
|
|
||||||
dev_meter = []
|
dev_meter = []
|
||||||
dev_adapter = []
|
dev_adapter = []
|
||||||
|
dev_info = []
|
||||||
try:
|
try:
|
||||||
for dev in sorted(json_data['rows'], key=lambda x: x['devCode']):
|
for dev in sorted(json_data['rows'], key=lambda x: x['devCode']):
|
||||||
print(f"Dev: {dev['devTypeName']}, id={dev['devCode']}")
|
print(f"Dev: {dev['devTypeName']}, id={dev['devCode']}")
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
fsu_id = dev['parentCode'] if 'parentCode' in dev.keys() else None
|
fsu_id = dev['parentCode'] if 'parentCode' in dev.keys() else None
|
||||||
self.get_real_data_by_net(dev['devCode'], fsu_id, header=header)
|
dev_info.append(self.get_real_data_by_net(dev['devCode'], fsu_id, header=header))
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
match dev['devType']:
|
match dev['devType']:
|
||||||
case "0101":
|
case "0101":
|
||||||
@@ -366,6 +382,7 @@ class Lamina_Data(object):
|
|||||||
result = {
|
result = {
|
||||||
'result': True,
|
'result': True,
|
||||||
'station': station_id,
|
'station': station_id,
|
||||||
|
'information': pd.concat(dev_info, ignore_index=True),
|
||||||
'adapter': pd.concat(dev_adapter, ignore_index=True),
|
'adapter': pd.concat(dev_adapter, ignore_index=True),
|
||||||
'meter': pd.concat(dev_meter, ignore_index=True),
|
'meter': pd.concat(dev_meter, ignore_index=True),
|
||||||
}
|
}
|
||||||
@@ -493,8 +510,6 @@ def save_station_by_file2(data_lamina: Lamina_Data, file_path):
|
|||||||
file_input = Path(file_path)
|
file_input = Path(file_path)
|
||||||
file_output = file_input.parent / (file_input.stem + '_output.xlsx')
|
file_output = file_input.parent / (file_input.stem + '_output.xlsx')
|
||||||
df_input = pd.read_excel(file_input)
|
df_input = pd.read_excel(file_input)
|
||||||
time_start_timestamp = df_input['开始时间'][0].tz_localize('Asia/Shanghai').timestamp()
|
|
||||||
time_end_timestamp = df_input['结束时间'][0].tz_localize('Asia/Shanghai').timestamp()
|
|
||||||
if file_output.exists():
|
if file_output.exists():
|
||||||
finished_station = pd.read_excel(file_output, sheet_name=None)
|
finished_station = pd.read_excel(file_output, sheet_name=None)
|
||||||
finished_station["Station"]['station'] = finished_station["Station"]['station'].astype('str')
|
finished_station["Station"]['station'] = finished_station["Station"]['station'].astype('str')
|
||||||
@@ -506,11 +521,16 @@ def save_station_by_file2(data_lamina: Lamina_Data, file_path):
|
|||||||
remain_station = df_input
|
remain_station = df_input
|
||||||
|
|
||||||
dataset = []
|
dataset = []
|
||||||
|
df_input = df_input.set_index('点位名称')
|
||||||
for name in remain_station['点位名称']:
|
for name in remain_station['点位名称']:
|
||||||
print(f"Station: {name}")
|
print(f"Station: {name}")
|
||||||
|
time_start_timestamp = df_input['开始时间'][name].tz_localize('Asia/Shanghai').timestamp()
|
||||||
|
time_end_timestamp = df_input['结束时间'][name].tz_localize('Asia/Shanghai').timestamp()
|
||||||
data = data_lamina.spider_station(name, time_start_timestamp, time_end_timestamp)
|
data = data_lamina.spider_station(name, time_start_timestamp, time_end_timestamp)
|
||||||
if data['result']:
|
if data['result']:
|
||||||
dataset.append(data)
|
dataset.append(data)
|
||||||
|
analysis_info1(data)
|
||||||
|
plt.waitforbuttonpress()
|
||||||
elif data['token']:
|
elif data['token']:
|
||||||
""" Token 失效 """
|
""" Token 失效 """
|
||||||
data_lamina.api_origin['header']['authorization'] = data['token']
|
data_lamina.api_origin['header']['authorization'] = data['token']
|
||||||
@@ -536,9 +556,99 @@ def save_station_by_file2(data_lamina: Lamina_Data, file_path):
|
|||||||
df_meter.to_excel(writer, sheet_name='Meter', index=False, columns=column_meter)
|
df_meter.to_excel(writer, sheet_name='Meter', index=False, columns=column_meter)
|
||||||
|
|
||||||
print(f"数据已成功保存到 {file_output}")
|
print(f"数据已成功保存到 {file_output}")
|
||||||
|
return result
|
||||||
|
|
||||||
|
def analysis_info(df_station: pd.DataFrame):
|
||||||
|
""" 站点Log数据分析 """
|
||||||
|
map_mid = {}
|
||||||
|
for k, v in SemaMap_adapter.items():
|
||||||
|
map_mid[v[0]] = v[3]
|
||||||
|
for k, v in SemaMap_meter.items():
|
||||||
|
map_mid[v[0]] = v[3]
|
||||||
|
map_dev = {
|
||||||
|
'TTE0102': 'Adapter',
|
||||||
|
'TTE0103': 'Meter',
|
||||||
|
}
|
||||||
|
data = df_station.assign(
|
||||||
|
timestamp = lambda df: pd.to_datetime(df['time'], unit='s', utc=True).apply(lambda x: x.tz_convert('Asia/Shanghai')),
|
||||||
|
type = lambda df: df['dev'].apply(lambda x: map_dev[x[:7]]),
|
||||||
|
date = lambda df: df['timestamp'].apply(lambda x: x.date()),
|
||||||
|
name = lambda df: df['mid'].map(map_mid),
|
||||||
|
value = lambda df: pd.to_numeric(df['value'])
|
||||||
|
)
|
||||||
|
data_daliy = data.loc[(data['dev'] == 'TTE0102DX2406272727') & (data['date'] == np.datetime64('2024-12-25')) & (data['type'] == 'Adapter')]
|
||||||
|
fig, axes = plt.subplots(3, 2)
|
||||||
|
axes = axes.flatten()
|
||||||
|
i = 0
|
||||||
|
for name, df_plot in data_daliy.set_index('timestamp').sort_index()[['name', 'value']].groupby('name'):
|
||||||
|
df_plot.plot(ax=axes[i], title=name)
|
||||||
|
i += 1
|
||||||
|
plt.show()
|
||||||
|
|
||||||
|
def analysis_info1(data_station: dict):
|
||||||
|
""" 站点spider返回数据分析 """
|
||||||
|
# 创建双色颜色过渡
|
||||||
|
color_map = mcolors.LinearSegmentedColormap.from_list("mycmap", ["blue", "red"])
|
||||||
|
|
||||||
|
for dev_id in data_station['information']['dev'].unique():
|
||||||
|
data_dev = data_station['information'].loc[data_station['information']['dev'] == dev_id]
|
||||||
|
print(f"Device: {dev_id}")
|
||||||
|
match dev_id[:7]:
|
||||||
|
case "TTE0101": # 汇流箱
|
||||||
|
pass
|
||||||
|
case "TTE0102": # 适配器
|
||||||
|
pass
|
||||||
|
history_dev = data_station['adapter'].assign(
|
||||||
|
date = lambda df: df['time'].apply(lambda x: x.date()),
|
||||||
|
)
|
||||||
|
case "TTE0103": # 电表
|
||||||
|
pass
|
||||||
|
history_dev = data_station['meter'].assign(
|
||||||
|
date = lambda df: df['time'].apply(lambda x: x.date()),
|
||||||
|
id_group = lambda df: df['date'].diff().ne(0).cumsum(),
|
||||||
|
)
|
||||||
|
# 按日期分组并绘制折线图
|
||||||
|
fig, axs = plt.subplots(3, 1)
|
||||||
|
axs = axs.flatten()
|
||||||
|
for date, group in history_dev.groupby('date'):
|
||||||
|
# 计算当天的起始时间
|
||||||
|
start_time = pd.Timestamp(date)
|
||||||
|
# 调整时间索引,使其从当天的起始时间开始
|
||||||
|
adjusted_time = group['time'] - start_time
|
||||||
|
|
||||||
|
# 计算颜色和不透明度
|
||||||
|
color = color_map(group['id_group'] / history_dev['id_group'][-1])
|
||||||
|
alpha = 0.5
|
||||||
|
|
||||||
|
group.set_index(adjusted_time)['volt'].plot(ax=axs[0], label=str(date), color=color, alpha=alpha)
|
||||||
|
group.set_index(adjusted_time)['curr'].plot(ax=axs[1], label=str(date), color=color, alpha=alpha)
|
||||||
|
group.set_index(adjusted_time)['power'].plot(ax=axs[2], label=str(date), color=color, alpha=alpha)
|
||||||
|
|
||||||
|
# 添加图例
|
||||||
|
axs[0].legend(title='Date')
|
||||||
|
|
||||||
|
# 添加标题和标签
|
||||||
|
axs[0].set_title('Value over Time by Date')
|
||||||
|
axs[0].set_xlabel('Timestamp')
|
||||||
|
axs[0].set_ylabel('Value')
|
||||||
|
plt.show()
|
||||||
|
plt.savefig(Path(f"result\Analysis\{dev_id}.png"))
|
||||||
|
print(data_dev.head())
|
||||||
|
|
||||||
if __name__=='__main__':
|
if __name__=='__main__':
|
||||||
""" 主体调用流程 """
|
""" 主体调用流程 """
|
||||||
|
# plt中文显示
|
||||||
|
plt.rcParams['font.sans-serif'] = ['SimHei']
|
||||||
|
# 坐标轴负数显示
|
||||||
|
plt.rcParams['axes.unicode_minus'] = False
|
||||||
|
|
||||||
|
if not hasattr(__builtins__,"__IPYTHON__") and 0:
|
||||||
|
import pickle
|
||||||
|
path_data1 = Path(r"result\Analysis\station_data1.pkl")
|
||||||
|
with open(path_data1, 'rb') as f:
|
||||||
|
loaded_data = pickle.load(f)
|
||||||
|
analysis_info1(loaded_data)
|
||||||
|
|
||||||
if hasattr(__builtins__,"__IPYTHON__"):
|
if hasattr(__builtins__,"__IPYTHON__"):
|
||||||
path_db = '../result/chinatowercom.db'
|
path_db = '../result/chinatowercom.db'
|
||||||
else:
|
else:
|
||||||
@@ -547,22 +657,22 @@ if __name__=='__main__':
|
|||||||
if not (file_db:= Path(path_db)).exists():
|
if not (file_db:= Path(path_db)).exists():
|
||||||
file_db.touch()
|
file_db.touch()
|
||||||
|
|
||||||
API_HEADER['Cookie'] = "HWWAFSESID=7e7df7972959068f88; HWWAFSESTIME=1736230263315; dc04ed2361044be8a9355f6efb378cf2=WyIzNTI0NjE3OTgzIl0"
|
API_HEADER['Cookie'] = "HWWAFSESTIME=1737167522632; HWWAFSESID=6cb0288b7bc75e5a66; dc04ed2361044be8a9355f6efb378cf2=WyIzNTI0NjE3OTgzIl0"
|
||||||
API_HEADER['authorization'] = 'Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiIl0sInVzZXJfbmFtZSI6IndlYl9tYW5hZ2V8d2FuZ2xlaTQiLCJzY29wZSI6WyJhbGwiXSwiZXhwIjoxNzM2MjM3NTMxLCJ1c2VySWQiOjI0Mjg1LCJqdGkiOiIzMWRlNDRiMy05ZTNjLTQwOTEtOWUzMS0wYWFjNTYzZDljZWIiLCJjbGllbnRfaWQiOiJ3ZWJfbWFuYWdlIn0.INV4DumSZkZZ68TW0DTF1XlIIFuoHD90_JefmmOBxcHPDxHAZPzG4JX9BEcEPrRLfSENtfYW7XNCluzB9nxs_pBTT9iu--tPZwlLAiPD7LZ552VdoAFEsYaigFmwxtedTLTzzm2GVbUReInd1dARjgaK0mKxljkKfGkTJURobpHC9Aw5mu25fSWjv7U9sZ0gOmpCuFr_OukEssi0hV8lvztfN5Ax_E1NObbteY2e8tUh6xVj49pHwDPnQScofGTaSviuMO46zmim6X3AKUJ-jDa95dOygKhk704AiA2nVCHXrlVkJI7zYLZB_zZTw3EhyonpksYS8NPp9wLlearWqg'
|
API_HEADER['authorization'] = 'Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiIl0sInVzZXJfbmFtZSI6IndlYl9tYW5hZ2V8d2FuZ2xlaTQiLCJzY29wZSI6WyJhbGwiXSwiZXhwIjoxNzM3MzQxNDg4LCJ1c2VySWQiOjI0Mjg1LCJqdGkiOiIwOGFlZDdjYy1hZGE2LTQ4ZWQtYmQyZS0xYjY3NGRkZmVmMWMiLCJjbGllbnRfaWQiOiJ3ZWJfbWFuYWdlIn0.CnfJh2ie0D0dOG1yELiQPuXCwez_nzeYD8rXTL0ILSeq31kmTnhOJJTA6aI8JTEtDVgFyqC084uDR1KvDgwKL5aXXzKwCNqBxziJQbA2AuBRdDgdWXM0r_3qrBGL-0MuYB2jygJaNwue2GIh_3PYsMQGRqHBeyJ9JUgdiWYUVpmbYInSyOlY2l_QtzQTFlz8L7eUC0sDeAWSPNamvYczLas0MtuQquH6JM_-WaFfc-6TblmFp6qSxZHJT-0dy7LLTw5zpXbh3QnbjgBARCaOvzLaDtfArgU20Hq3AqAIwvTVOQFeI4jChFIRvyXwnnUDX-IrFru_sOYLX1jcc88cPA'
|
||||||
data_lamina = Lamina_Data('sqlite:///' + path_db)
|
data_lamina = Lamina_Data('sqlite:///' + path_db)
|
||||||
|
|
||||||
# 依据站点内设备爬取整个站点的实时与历史数据
|
# 依据站点内设备爬取整个站点的实时与历史数据
|
||||||
# today = datetime.datetime.today()
|
# today = datetime.datetime.today()
|
||||||
# yesterday = today - datetime.timedelta(days=1)
|
# yesterday = today - datetime.timedelta(days=30)
|
||||||
# today_midnight = today.replace(hour=0, minute=0, second=0, microsecond=0)
|
# today_midnight = today.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||||
# yesterday_midnight = yesterday.replace(hour=0, minute=0, second=0, microsecond=0)
|
# yesterday_midnight = yesterday.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||||
# today_midnight_timestamp = time.mktime(today_midnight.timetuple())
|
# today_midnight_timestamp = time.mktime(today_midnight.timetuple())
|
||||||
# yesterday_midnight_timestamp = time.mktime(yesterday_midnight.timetuple())
|
# yesterday_midnight_timestamp = time.mktime(yesterday_midnight.timetuple())
|
||||||
# data = data_lamina.spider_station('TTE0102DX2410091439', yesterday_midnight_timestamp, today_midnight_timestamp)
|
# data = data_lamina.spider_station("乐亭后庞河村", yesterday_midnight_timestamp, today_midnight_timestamp)
|
||||||
|
|
||||||
# 读取站点历史数据
|
# 读取站点历史数据
|
||||||
# save_station_by_file1(data_lamina)
|
# save_station_by_file1(data_lamina)
|
||||||
save_station_by_file2(data_lamina, "result\station_Q0107.xlsx")
|
result = save_station_by_file2(data_lamina, "result\station_Q0120.xlsx")
|
||||||
|
|
||||||
# 网站令牌更新
|
# 网站令牌更新
|
||||||
body = {
|
body = {
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import time
|
import time
|
||||||
|
import warnings
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from device.LaminaAdapter import LaminaAdapter
|
from device.LaminaAdapter import LaminaAdapter
|
||||||
from device.LaminaAdapter import GeneratePackage_SLCP001_p4a0, GeneratePackage_SLCP101_p460, GeneratePackage_DLSY001_p460
|
|
||||||
from device.LaminaAdapter import GeneratePackage_SLCP102_p460
|
|
||||||
from device.tools.ByteConv import trans_list_to_str, trans_str_to_list
|
from device.tools.ByteConv import trans_list_to_str, trans_str_to_list
|
||||||
|
|
||||||
def test_communication(time_out=2):
|
def test_communication(time_out=2):
|
||||||
@@ -192,6 +191,42 @@ def test():
|
|||||||
dev_lamina.frame_read(0x0E, 0x20)
|
dev_lamina.frame_read(0x0E, 0x20)
|
||||||
dev_lamina.flag_print = True
|
dev_lamina.flag_print = True
|
||||||
|
|
||||||
|
if 0: # 程序升级
|
||||||
|
dev_lamina.frame_update(file_hex, makefile=True)
|
||||||
|
time.sleep(4.5)
|
||||||
|
dev_lamina.frame_read(0x100, 0x20)
|
||||||
|
if 0: # 曲线扫描
|
||||||
|
dev_lamina.flag_print = False
|
||||||
|
action_list = [(0x50, 1), (0x50, 0), (0xA8, 0), (0x50, 1)]
|
||||||
|
dev_lamina.frame_write_one(0x50, 0)
|
||||||
|
time.sleep(0.5)
|
||||||
|
dev_lamina.frame_write_one(0x52, 1)
|
||||||
|
time.sleep(4.5)
|
||||||
|
dev_lamina.frame_read(0x60, 0x60)
|
||||||
|
step = 0
|
||||||
|
time_start = time.time()
|
||||||
|
time_interval = 120
|
||||||
|
while True:
|
||||||
|
time.sleep(1)
|
||||||
|
print(time.ctime())
|
||||||
|
dev_lamina.frame_read(0x0E, 0x20)
|
||||||
|
if time.time() - time_start > time_interval:
|
||||||
|
if step >= len(action_list):
|
||||||
|
break
|
||||||
|
time.sleep(0.5)
|
||||||
|
time_start = time.time()
|
||||||
|
result = dev_lamina.frame_write_one(*action_list[step])
|
||||||
|
print(f"Write Value: {action_list[step][1]} in Addr: 0x{action_list[step][0]:x} by Time: {time.ctime(time_start)}. \n\tresult: {'Seccusss' if result else 'Fail'}.")
|
||||||
|
step += 1
|
||||||
|
dev_lamina.flag_print = True
|
||||||
|
if 0: # 数据读写验证
|
||||||
|
addr, value = 0x61, 29.9
|
||||||
|
dlen = 1
|
||||||
|
result = dev_lamina.frame_write(addr, dlen, value)
|
||||||
|
print(f"Write Result: \n0x{addr:04x}:\t{value}\t{'Seccusss' if result else 'Fail'}.")
|
||||||
|
time.sleep(0.5)
|
||||||
|
dev_lamina.frame_read(addr, dlen)
|
||||||
|
|
||||||
if __name__=='__main__':
|
if __name__=='__main__':
|
||||||
mode_config = {
|
mode_config = {
|
||||||
"Log": {'com_name': None,
|
"Log": {'com_name': None,
|
||||||
@@ -201,19 +236,15 @@ if __name__=='__main__':
|
|||||||
# 'addr_645': [0x01, 0x02, 0x03, 0x04, 0x05, 0x06],
|
# 'addr_645': [0x01, 0x02, 0x03, 0x04, 0x05, 0x06],
|
||||||
'frame_print': True,
|
'frame_print': True,
|
||||||
'time_out': 0.5, 'retry': 1, 'retry_sub': 10},
|
'time_out': 0.5, 'retry': 1, 'retry_sub': 10},
|
||||||
"HPLC": {'com_name': 'COM9', 'baudrate': 9600, 'parity': 'E', 'bytesize': 8, 'stopbits': 1,
|
"HPLC": {'com_name': 'COM8', 'baudrate': 9600, 'parity': 'E', 'bytesize': 8, 'stopbits': 1,
|
||||||
'addr_645': trans_str_to_list("02 01 00 00 24 20"),
|
'addr_645': trans_str_to_list("02 01 00 00 24 20"),
|
||||||
'frame_print': True,
|
'frame_print': True,
|
||||||
'time_out': 3, 'time_gap': 0.1, 'retry': 3, 'retry_sub': 10},
|
'time_out': 3, 'time_gap': 0.1, 'retry': 3, 'retry_sub': 10},
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_lamina = LaminaAdapter(type_dev="SLCP101", **mode_config['Debug'])
|
dev_lamina = LaminaAdapter(type_dev="SLCP001", **mode_config['Debug'])
|
||||||
|
|
||||||
dev_lamina.frame_read(0x0100, 0x20)
|
dev_lamina.frame_read(0x0100, 0x30)
|
||||||
# dev_lamina.frame_write_one(0x51, 0x01)
|
|
||||||
# dev_lamina.frame_read(0x1A0, 0x20)
|
|
||||||
# dev_lamina.frame_log()
|
|
||||||
# dev_lamina.frame_read(0x1A0, 0x20)
|
|
||||||
|
|
||||||
# 工程-即时转换
|
# 工程-即时转换
|
||||||
if dev_lamina.device == 'SLCP001':
|
if dev_lamina.device == 'SLCP001':
|
||||||
@@ -227,7 +258,9 @@ if __name__=='__main__':
|
|||||||
else:
|
else:
|
||||||
file_hex = Path(r"D:\WorkingProject\LightStackAdapter\software\lamina_adapter\lamina_adapter\Debug\lamina_adapter.hex")
|
file_hex = Path(r"D:\WorkingProject\LightStackAdapter\software\lamina_adapter\lamina_adapter\Debug\lamina_adapter.hex")
|
||||||
if not file_hex.exists():
|
if not file_hex.exists():
|
||||||
raise Exception("工程编译目标文件不存在.")
|
warnings.warn("工程编译目标文件不存在.", UserWarning)
|
||||||
|
if dev_lamina.output['Regs'][0x100][1].split('_')[0] != dev_lamina.device:
|
||||||
|
warnings.warn("设备型号不匹配.", UserWarning)
|
||||||
print(dev_lamina.device)
|
print(dev_lamina.device)
|
||||||
print(file_hex)
|
print(file_hex)
|
||||||
|
|
||||||
|
|||||||
8187
source/dev_LaminaAdapter1.ipynb
Normal file
8187
source/dev_LaminaAdapter1.ipynb
Normal file
File diff suppressed because it is too large
Load Diff
@@ -269,13 +269,30 @@ if __name__ == '__main__':
|
|||||||
"dev22": {'device_id': 'TTE0101DX2406300067', # (新版限功率升级)
|
"dev22": {'device_id': 'TTE0101DX2406300067', # (新版限功率升级)
|
||||||
'frame_print': True,
|
'frame_print': True,
|
||||||
'time_out': 6, 'retry': 1},
|
'time_out': 6, 'retry': 1},
|
||||||
|
"dev23": {'device_id': 'TTE0101HP2411260059', # 孟村董林小区/移动
|
||||||
|
'frame_print': True,
|
||||||
|
'time_out': 6, 'retry': 1},
|
||||||
|
"dev24": {'device_id': 'TTE0101DX2406280016', # 复兴村-光伏
|
||||||
|
'frame_print': True,
|
||||||
|
'time_out': 6, 'retry': 1},
|
||||||
|
"dev25": {'device_id': 'TTE0101HP2411180035', # 霸州-纸房头
|
||||||
|
'frame_print': True,
|
||||||
|
'time_out': 6, 'retry': 1},
|
||||||
|
"dev26": {'device_id': 'TTE0101DX2408010159', # 句容市小衣庄基站机房
|
||||||
|
'frame_print': True,
|
||||||
|
'time_out': 6, 'retry': 1},
|
||||||
|
"dev27": {'device_id': 'TTE0101HP2411180003', # 文安何庄村新建1
|
||||||
|
'frame_print': True,
|
||||||
|
'time_out': 6, 'retry': 1},
|
||||||
}
|
}
|
||||||
dev_lamina = LaminaStation(**mode_config["dev22"])
|
dev_lamina = LaminaStation(**mode_config["dev27"])
|
||||||
|
|
||||||
dev_lamina.frame_read(0x0000, 0x20)
|
dev_lamina.frame_read(0x0000, 0x20)
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
dev_lamina.frame_read(0x857, 0x40)
|
dev_lamina.frame_read(0x857, 0x40)
|
||||||
|
|
||||||
|
dev_lamina.frame_read_adapter(0, 0x0E, 0x20)
|
||||||
|
|
||||||
if not hasattr(__builtins__,"__IPYTHON__"):
|
if not hasattr(__builtins__,"__IPYTHON__"):
|
||||||
pass
|
pass
|
||||||
dev_lamina.frame_read(0x400E + 0x200 * (6-1), 0x20)
|
dev_lamina.frame_read(0x400E + 0x200 * (6-1), 0x20)
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class DeviceMQTT:
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
def open_connection(self, broker, port, account=None, **kwargs) ->bool:
|
def open_connection(self, broker, port, account=None, **kwargs):
|
||||||
""" 创建链接 """
|
""" 创建链接 """
|
||||||
def on_connect(client, userdata, flags, rc, properties):
|
def on_connect(client, userdata, flags, rc, properties):
|
||||||
""" 回调函数-创建链接 """
|
""" 回调函数-创建链接 """
|
||||||
@@ -87,15 +87,18 @@ class DeviceMQTT:
|
|||||||
if account is not None:
|
if account is not None:
|
||||||
client.username_pw_set(account[0], account[1])
|
client.username_pw_set(account[0], account[1])
|
||||||
client.on_connect = on_connect if 'func_on_connect' not in kwargs.keys() else kwargs['func_on_connect']
|
client.on_connect = on_connect if 'func_on_connect' not in kwargs.keys() else kwargs['func_on_connect']
|
||||||
# client.on_disconnect = on_disconnect if 'func_on_disconnect' not in kwargs.keys() else kwargs['func_on_disconnect']
|
client.on_disconnect = on_disconnect if 'func_on_disconnect' not in kwargs.keys() else kwargs['func_on_disconnect']
|
||||||
client.on_message = on_message if 'func_on_message' not in kwargs.keys() else kwargs['func_on_message']
|
client.on_message = on_message if 'func_on_message' not in kwargs.keys() else kwargs['func_on_message']
|
||||||
client.connect(broker, port)
|
client.connect(broker, port)
|
||||||
|
client.loop_start()
|
||||||
return client
|
return client
|
||||||
|
|
||||||
|
|
||||||
def close_connection(self) ->bool:
|
def close_connection(self) ->bool:
|
||||||
""" 关闭连接 """
|
""" 关闭连接 """
|
||||||
|
self.client.loop_close()
|
||||||
self.client.disconnect()
|
self.client.disconnect()
|
||||||
|
return True
|
||||||
|
|
||||||
def _subscribe(self, device_id):
|
def _subscribe(self, device_id):
|
||||||
""" 订阅主题 """
|
""" 订阅主题 """
|
||||||
|
|||||||
@@ -174,15 +174,7 @@ class DeviceSerial:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def frame_write_one(self, daddr=0x85, dval=-900) -> bool:
|
def frame_write(self, daddr, dlen=1, dval=None) -> bool:
|
||||||
pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def frame_write_dual(self, daddr=0x91, dval=600) -> bool:
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def frame_write_str(self, daddr=0x82, dval=[0x06, 0x05, 0x04, 0x03, 0x02, 0x01]) -> bool:
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import time
|
import time
|
||||||
|
import warnings
|
||||||
import hashlib
|
import hashlib
|
||||||
from math import ceil
|
from math import ceil
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
@@ -113,7 +114,7 @@ ParamMap_LaminaAdapter = {
|
|||||||
0xA7: ["电池电压判断限值", 2, 10],
|
0xA7: ["电池电压判断限值", 2, 10],
|
||||||
0xA8: ["MPPT追踪模式", 1],
|
0xA8: ["MPPT追踪模式", 1],
|
||||||
0xA9: ["ADC参考电压", 2, 1000],
|
0xA9: ["ADC参考电压", 2, 1000],
|
||||||
0xAA: ["保留", 1],
|
0xAA: ["硬件版本", 1],
|
||||||
0xAB: ["保留", 1],
|
0xAB: ["保留", 1],
|
||||||
0xAC: ["保留", 1],
|
0xAC: ["保留", 1],
|
||||||
0xAD: ["保留", 1],
|
0xAD: ["保留", 1],
|
||||||
@@ -204,25 +205,44 @@ class LaminaAdapter(DeviceSerial):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def frame_read(self, daddr=0x60, dlen=0x50) -> bool:
|
def frame_read(self, daddr=0x60, dlen=0x50) -> bool:
|
||||||
|
""" 通用参数读取 """
|
||||||
self.block['data']['type'] = 'read'
|
self.block['data']['type'] = 'read'
|
||||||
self.block['data']['data_addr'] = daddr
|
self.block['data']['data_addr'] = daddr
|
||||||
self.block['data']['data_len'] = dlen
|
self.block['data']['data_len'] = dlen
|
||||||
return self._transfer_data()
|
return self._transfer_data()
|
||||||
|
|
||||||
|
def frame_write(self, daddr, dlen=1, dval=None) -> bool:
|
||||||
|
""" 通用参数写入 """
|
||||||
|
if daddr in self.block['data']['data_define'].keys():
|
||||||
|
param_define = self.block['data']['data_define'][daddr]
|
||||||
|
else:
|
||||||
|
param_define = [f'未知参数{daddr}', 1]
|
||||||
|
match param_define[1]:
|
||||||
|
case 1 | 2:
|
||||||
|
return self.frame_write_one(daddr, 0 if dval is None else dval)
|
||||||
|
case 3:
|
||||||
|
return self.frame_write_dual(daddr, 0 if dval is None else dval)
|
||||||
|
case 4 | 5 | 6:
|
||||||
|
return self.frame_write_str(daddr, [] if dval is None else dval)
|
||||||
|
case 6 | 7 | 8:
|
||||||
|
type_param_define = next(v for k, v in protocols.modbus_map.items() if v == param_define[1])
|
||||||
|
warnings.warn(f"DataType unsupport write: {type_param_define}")
|
||||||
|
return False
|
||||||
|
case _:
|
||||||
|
return self.frame_write_one(daddr, 0 if dval is None else dval)
|
||||||
|
|
||||||
def frame_write_one(self, daddr=0x85, dval=-900) -> bool:
|
def frame_write_one(self, daddr=0x85, dval=-900) -> bool:
|
||||||
self.block['data']['type'] = 'write_one'
|
self.block['data']['type'] = 'write_one'
|
||||||
self.block['data']['data_addr'] = daddr
|
self.block['data']['data_addr'] = daddr
|
||||||
self.block['data']['data_val'] = dval
|
|
||||||
item_coff = self.block['data']['data_define'][daddr][2] if len(self.block['data']['data_define'][daddr]) > 2 else 1
|
item_coff = self.block['data']['data_define'][daddr][2] if len(self.block['data']['data_define'][daddr]) > 2 else 1
|
||||||
self.block['data_val'] = int(dval * item_coff)
|
self.block['data']['data_val'] = int(dval * item_coff)
|
||||||
return self._transfer_data()
|
return self._transfer_data()
|
||||||
|
|
||||||
def frame_write_dual(self, daddr=0x91, dval=600) -> bool:
|
def frame_write_dual(self, daddr=0x91, dval=600) -> bool:
|
||||||
self.block['data']['type'] = 'write_dual'
|
self.block['data']['type'] = 'write_dual'
|
||||||
self.block['data']['data_addr'] = daddr
|
self.block['data']['data_addr'] = daddr
|
||||||
self.block['data']['data_val'] = dval
|
|
||||||
item_coff = self.block['data']['data_define'][daddr][2] if len(self.block['data']['data_define'][daddr]) > 2 else 1
|
item_coff = self.block['data']['data_define'][daddr][2] if len(self.block['data']['data_define'][daddr]) > 2 else 1
|
||||||
self.block['data_val'] = int(dval * item_coff)
|
self.block['data']['data_val'] = int(dval * item_coff)
|
||||||
return self._transfer_data()
|
return self._transfer_data()
|
||||||
|
|
||||||
def frame_write_str(self, daddr=0x82, dval=[0x06, 0x05, 0x04, 0x03, 0x02, 0x01]) -> bool:
|
def frame_write_str(self, daddr=0x82, dval=[0x06, 0x05, 0x04, 0x03, 0x02, 0x01]) -> bool:
|
||||||
@@ -302,6 +322,8 @@ def GeneratePackage(type_dev: str, path_hex: Path, **kwargs) -> bytearray:
|
|||||||
'prog_id': list(type_dev.encode('ascii')), # 程序识别号
|
'prog_id': list(type_dev.encode('ascii')), # 程序识别号
|
||||||
'prog_type': 'app', # 程序类型
|
'prog_type': 'app', # 程序类型
|
||||||
'area_code': [0x00, 0x00], # 地区
|
'area_code': [0x00, 0x00], # 地区
|
||||||
|
# 升级方式(0-片外缓冲, 1-片内缓冲, 2-升级备份)
|
||||||
|
'upgrade_type': [0x02, 0x00] if 'upgrade_backup' in kwargs.keys() else [0x00, 0x00],
|
||||||
}
|
}
|
||||||
match type_dev:
|
match type_dev:
|
||||||
case 'SLCP001':
|
case 'SLCP001':
|
||||||
@@ -421,277 +443,6 @@ def GenerateImage(type_dev: str, path_boot: Path, path_main: Path, path_back: Pa
|
|||||||
|
|
||||||
return bytearray(Image)
|
return bytearray(Image)
|
||||||
|
|
||||||
def GeneratePackage_SLCP001_p4a0(path_hex: Path):
|
|
||||||
""" 叠光适配器-460平台版本 生成升级包 """
|
|
||||||
config = {
|
|
||||||
'prod_type': [0x45, 0x00], # 产品类型
|
|
||||||
'method_compress': False, # 文件压缩
|
|
||||||
'prog_id': list(b"SLCP001"), # 程序识别号
|
|
||||||
'prog_type': 'app', # 程序类型
|
|
||||||
'area_code': [0x00, 0x00], # 地区
|
|
||||||
}
|
|
||||||
bin_main = IntelHex.file_IntelHex_to_Bin(path_hex.read_text(), len_max=0x040000)
|
|
||||||
encrypt_main = file_upgrade.file_encryption(bin_main)
|
|
||||||
|
|
||||||
md5_ctx = hashlib.md5()
|
|
||||||
md5_ctx.update(bin_main)
|
|
||||||
config["md5"] = list(md5_ctx.digest())
|
|
||||||
config['file_length'] = ByteConv.conv_int_to_array(len(bin_main))
|
|
||||||
config['hex_name'] = list(path_hex.name.encode())[:64]
|
|
||||||
config['hex_name'] += [0] * (64 - len(config['hex_name']))
|
|
||||||
if (main_header:=file_upgrade.build_header_new(config)) is None:
|
|
||||||
raise Exception("Header tag oversize. ")
|
|
||||||
|
|
||||||
print("Package generated successfully.")
|
|
||||||
print(f"File name: {path_hex.name}")
|
|
||||||
print(f"File Info:")
|
|
||||||
print(f"\t header_length={len(main_header)}, bin_length={len(bin_main)}[{hex(len(bin_main))}]")
|
|
||||||
|
|
||||||
# 组装镜像
|
|
||||||
Image = [0xFF] * (len(main_header) + len(encrypt_main))
|
|
||||||
offset_image = 0
|
|
||||||
Image[offset_image: offset_image + len(main_header)] = main_header
|
|
||||||
offset_image += len(main_header)
|
|
||||||
Image[offset_image: offset_image + len(encrypt_main)] = encrypt_main
|
|
||||||
|
|
||||||
return bytearray(Image), bin_main
|
|
||||||
|
|
||||||
def GeneratePackage_SLCP101_p460(path_hex: Path):
|
|
||||||
""" 叠光适配器-460平台版本 生成升级包 """
|
|
||||||
config = {
|
|
||||||
'prod_type': [0x45, 0x00], # 产品类型
|
|
||||||
'method_compress': False, # 文件压缩
|
|
||||||
'prog_id': list(b"SLCP101"), # 程序识别号
|
|
||||||
'prog_type': 'app', # 程序类型
|
|
||||||
'area_code': [0x00, 0x00], # 地区
|
|
||||||
}
|
|
||||||
bin_main = IntelHex.file_IntelHex_to_Bin(path_hex.read_text(), len_max=0x024000)
|
|
||||||
encrypt_main = file_upgrade.file_encryption(bin_main)
|
|
||||||
|
|
||||||
md5_ctx = hashlib.md5()
|
|
||||||
md5_ctx.update(bin_main)
|
|
||||||
config["md5"] = list(md5_ctx.digest())
|
|
||||||
config['file_length'] = ByteConv.conv_int_to_array(len(bin_main))
|
|
||||||
config['hex_name'] = list(path_hex.name.encode())[:64]
|
|
||||||
config['hex_name'] += [0] * (64 - len(config['hex_name']))
|
|
||||||
if (main_header:=file_upgrade.build_header_new(config)) is None:
|
|
||||||
raise Exception("Header tag oversize. ")
|
|
||||||
|
|
||||||
print("Package generated successfully.")
|
|
||||||
print(f"File name: {path_hex.name}")
|
|
||||||
print(f"File Info:")
|
|
||||||
print(f"\t header_length={len(main_header)}, bin_length={len(bin_main)}[{hex(len(bin_main))}]")
|
|
||||||
|
|
||||||
# 组装镜像
|
|
||||||
Image = [0xFF] * (len(main_header) + len(encrypt_main))
|
|
||||||
offset_image = 0
|
|
||||||
Image[offset_image: offset_image + len(main_header)] = main_header
|
|
||||||
offset_image += len(main_header)
|
|
||||||
Image[offset_image: offset_image + len(encrypt_main)] = encrypt_main
|
|
||||||
|
|
||||||
return bytearray(Image), bin_main
|
|
||||||
|
|
||||||
|
|
||||||
def GeneratePackage_SLCP102_p460(path_hex: Path):
|
|
||||||
""" 叠光适配器-460平台版本 生成升级包 """
|
|
||||||
config = {
|
|
||||||
'prod_type': [0x45, 0x00], # 产品类型
|
|
||||||
'method_compress': False, # 文件压缩
|
|
||||||
'prog_id': list(b"SLCP102"), # 程序识别号
|
|
||||||
'prog_type': 'app', # 程序类型
|
|
||||||
'area_code': [0x00, 0x00], # 地区
|
|
||||||
}
|
|
||||||
bin_main = IntelHex.file_IntelHex_to_Bin(path_hex.read_text(), len_max=0x024000)
|
|
||||||
encrypt_main = file_upgrade.file_encryption(bin_main)
|
|
||||||
|
|
||||||
md5_ctx = hashlib.md5()
|
|
||||||
md5_ctx.update(bin_main)
|
|
||||||
config["md5"] = list(md5_ctx.digest())
|
|
||||||
config['file_length'] = ByteConv.conv_int_to_array(len(bin_main))
|
|
||||||
config['hex_name'] = list(path_hex.name.encode())[:64]
|
|
||||||
config['hex_name'] += [0] * (64 - len(config['hex_name']))
|
|
||||||
if (main_header:=file_upgrade.build_header_new(config)) is None:
|
|
||||||
raise Exception("Header tag oversize. ")
|
|
||||||
|
|
||||||
print("Package generated successfully.")
|
|
||||||
print(f"File name: {path_hex.name}")
|
|
||||||
print(f"File Info:")
|
|
||||||
print(f"\t header_length={len(main_header)}, bin_length={len(bin_main)}[{hex(len(bin_main))}]")
|
|
||||||
|
|
||||||
# 组装镜像
|
|
||||||
Image = [0xFF] * (len(main_header) + len(encrypt_main))
|
|
||||||
offset_image = 0
|
|
||||||
Image[offset_image: offset_image + len(main_header)] = main_header
|
|
||||||
offset_image += len(main_header)
|
|
||||||
Image[offset_image: offset_image + len(encrypt_main)] = encrypt_main
|
|
||||||
|
|
||||||
return bytearray(Image), bin_main
|
|
||||||
|
|
||||||
|
|
||||||
def GenerateImage_SLCP001_p4a0(path_boot: Path, path_main: Path, path_back: Path):
|
|
||||||
""" 叠光适配器-4A0平台版本 镜像生成 """
|
|
||||||
config = {
|
|
||||||
'prod_type': [0x45, 0x00], # 产品类型
|
|
||||||
'method_compress': False, # 文件压缩
|
|
||||||
'prog_id': list(b"SLCP001"), # 程序识别号
|
|
||||||
'prog_type': 'app', # 程序类型
|
|
||||||
'area_code': [0x00, 0x00], # 地区
|
|
||||||
}
|
|
||||||
bin_boot = IntelHex.file_IntelHex_to_Bin(path_boot.read_text(), len_max=0x010000)
|
|
||||||
bin_main = IntelHex.file_IntelHex_to_Bin(path_main.read_text(), len_max=0x0CC000)
|
|
||||||
bin_back = IntelHex.file_IntelHex_to_Bin(path_back.read_text(), len_max=0x040000)
|
|
||||||
encrypt_main = file_upgrade.file_encryption(bin_main)
|
|
||||||
encrypt_back = file_upgrade.file_encryption(bin_back)
|
|
||||||
|
|
||||||
md5_ctx = hashlib.md5()
|
|
||||||
md5_ctx.update(bin_main)
|
|
||||||
config["md5"] = list(md5_ctx.digest())
|
|
||||||
config['file_length'] = ByteConv.conv_int_to_array(len(bin_main))
|
|
||||||
config['hex_name'] = list(path_main.name.encode())[:64]
|
|
||||||
config['hex_name'] += [0] * (64 - len(config['hex_name']))
|
|
||||||
if (main_header:=file_upgrade.build_header_new(config)) is None:
|
|
||||||
raise Exception("Header tag oversize. ")
|
|
||||||
|
|
||||||
md5_ctx = hashlib.md5()
|
|
||||||
md5_ctx.update(bin_back)
|
|
||||||
config["md5"] = list(md5_ctx.digest())
|
|
||||||
config['file_length'] = ByteConv.conv_int_to_array(len(bin_back))
|
|
||||||
config['hex_name'] = list(path_back.name.encode())[:64]
|
|
||||||
config['hex_name'] += [0] * (64 - len(config['hex_name']))
|
|
||||||
if (back_header:=file_upgrade.build_header_new(config)) is None:
|
|
||||||
raise Exception("Header tag oversize. ")
|
|
||||||
|
|
||||||
print("Merge Image generated successfully.")
|
|
||||||
print(f"Main File:")
|
|
||||||
print(f"\t header_length={len(main_header)}, bin_length={len(bin_main)}[{hex(len(bin_main))}]")
|
|
||||||
print(f"Back File:")
|
|
||||||
print(f"\t header_length={len(back_header)}, bin_length={len(bin_back)}[{hex(len(bin_back))}]")
|
|
||||||
|
|
||||||
# 组装镜像
|
|
||||||
Image = [0xFF] * 0x100000
|
|
||||||
offset_image = 0
|
|
||||||
Image[offset_image: offset_image + len(bin_boot)] = bin_boot
|
|
||||||
offset_image = 0x010000
|
|
||||||
Image[offset_image: offset_image + len(bin_main)] = bin_main
|
|
||||||
offset_image = 0x0BC000
|
|
||||||
Image[offset_image: offset_image + len(bin_back)] = bin_back
|
|
||||||
offset_image = 0x0FC000
|
|
||||||
Image[offset_image: offset_image + len(main_header)] = main_header
|
|
||||||
offset_image = 0x0FE000
|
|
||||||
Image[offset_image: offset_image + len(back_header)] = back_header
|
|
||||||
|
|
||||||
return bytearray(Image), main_header, back_header
|
|
||||||
|
|
||||||
|
|
||||||
def GenerateImage_SLCP101_p460(path_boot: Path, path_main: Path, path_back: Path):
|
|
||||||
""" 叠光适配器-460平台版本 镜像生成 """
|
|
||||||
config = {
|
|
||||||
'prod_type': [0x45, 0x00], # 产品类型
|
|
||||||
'method_compress': False, # 文件压缩
|
|
||||||
'prog_id': list(b"SLCP101"), # 程序识别号
|
|
||||||
'prog_type': 'app', # 程序类型
|
|
||||||
'area_code': [0x00, 0x00], # 地区
|
|
||||||
}
|
|
||||||
bin_boot = IntelHex.file_IntelHex_to_Bin(path_boot.read_text(), len_max=0x00C000)
|
|
||||||
bin_main = IntelHex.file_IntelHex_to_Bin(path_main.read_text(), len_max=0x024000)
|
|
||||||
bin_back = IntelHex.file_IntelHex_to_Bin(path_back.read_text(), len_max=0x024000)
|
|
||||||
encrypt_main = file_upgrade.file_encryption(bin_main)
|
|
||||||
encrypt_back = file_upgrade.file_encryption(bin_back)
|
|
||||||
|
|
||||||
md5_ctx = hashlib.md5()
|
|
||||||
md5_ctx.update(bin_main)
|
|
||||||
config["md5"] = list(md5_ctx.digest())
|
|
||||||
config['file_length'] = ByteConv.conv_int_to_array(len(bin_main))
|
|
||||||
config['hex_name'] = list(path_main.name.encode())[:64]
|
|
||||||
config['hex_name'] += [0] * (64 - len(config['hex_name']))
|
|
||||||
if (main_header:=file_upgrade.build_header_new(config)) is None:
|
|
||||||
raise Exception("Header tag oversize. ")
|
|
||||||
|
|
||||||
md5_ctx = hashlib.md5()
|
|
||||||
md5_ctx.update(bin_back)
|
|
||||||
config["md5"] = list(md5_ctx.digest())
|
|
||||||
config['file_length'] = ByteConv.conv_int_to_array(len(bin_back))
|
|
||||||
config['hex_name'] = list(path_back.name.encode())[:64]
|
|
||||||
config['hex_name'] += [0] * (64 - len(config['hex_name']))
|
|
||||||
if (back_header:=file_upgrade.build_header_new(config)) is None:
|
|
||||||
raise Exception("Header tag oversize. ")
|
|
||||||
|
|
||||||
print("Merge Image generated successfully.")
|
|
||||||
print(f"Main File:")
|
|
||||||
print(f"\t header_length={len(main_header)}, bin_length={len(bin_main)}[{hex(len(bin_main))}]")
|
|
||||||
print(f"Back File:")
|
|
||||||
print(f"\t header_length={len(back_header)}, bin_length={len(bin_back)}[{hex(len(bin_back))}]")
|
|
||||||
|
|
||||||
# 组装镜像
|
|
||||||
Image = [0xFF] * 0x058000
|
|
||||||
offset_image = 0
|
|
||||||
Image[offset_image: offset_image + len(bin_boot)] = bin_boot
|
|
||||||
offset_image = 0x00C000
|
|
||||||
Image[offset_image: offset_image + len(bin_main)] = bin_main
|
|
||||||
offset_image = 0x030000
|
|
||||||
Image[offset_image: offset_image + len(bin_back)] = bin_back
|
|
||||||
offset_image = 0x054000
|
|
||||||
Image[offset_image: offset_image + len(main_header)] = main_header
|
|
||||||
offset_image = 0x056000
|
|
||||||
Image[offset_image: offset_image + len(back_header)] = back_header
|
|
||||||
|
|
||||||
return bytearray(Image), main_header, back_header
|
|
||||||
|
|
||||||
|
|
||||||
def GenerateImage_SLCP102_p460(path_boot: Path, path_main: Path, path_back: Path):
|
|
||||||
""" 叠光适配器-460平台版本 镜像生成 """
|
|
||||||
config = {
|
|
||||||
'prod_type': [0x45, 0x00], # 产品类型
|
|
||||||
'method_compress': False, # 文件压缩
|
|
||||||
'prog_id': list(b"SLCP102"), # 程序识别号
|
|
||||||
'prog_type': 'app', # 程序类型
|
|
||||||
'area_code': [0x00, 0x00], # 地区
|
|
||||||
}
|
|
||||||
bin_boot = IntelHex.file_IntelHex_to_Bin(path_boot.read_text(), len_max=0x00C000)
|
|
||||||
bin_main = IntelHex.file_IntelHex_to_Bin(path_main.read_text(), len_max=0x024000)
|
|
||||||
bin_back = IntelHex.file_IntelHex_to_Bin(path_back.read_text(), len_max=0x024000)
|
|
||||||
encrypt_main = file_upgrade.file_encryption(bin_main)
|
|
||||||
encrypt_back = file_upgrade.file_encryption(bin_back)
|
|
||||||
|
|
||||||
md5_ctx = hashlib.md5()
|
|
||||||
md5_ctx.update(bin_main)
|
|
||||||
config["md5"] = list(md5_ctx.digest())
|
|
||||||
config['file_length'] = ByteConv.conv_int_to_array(len(bin_main))
|
|
||||||
config['hex_name'] = list(path_main.name.encode())[:64]
|
|
||||||
config['hex_name'] += [0] * (64 - len(config['hex_name']))
|
|
||||||
if (main_header:=file_upgrade.build_header_new(config)) is None:
|
|
||||||
raise Exception("Header tag oversize. ")
|
|
||||||
|
|
||||||
md5_ctx = hashlib.md5()
|
|
||||||
md5_ctx.update(bin_back)
|
|
||||||
config["md5"] = list(md5_ctx.digest())
|
|
||||||
config['file_length'] = ByteConv.conv_int_to_array(len(bin_back))
|
|
||||||
config['hex_name'] = list(path_back.name.encode())[:64]
|
|
||||||
config['hex_name'] += [0] * (64 - len(config['hex_name']))
|
|
||||||
if (back_header:=file_upgrade.build_header_new(config)) is None:
|
|
||||||
raise Exception("Header tag oversize. ")
|
|
||||||
|
|
||||||
print("Merge Image generated successfully.")
|
|
||||||
print(f"Main File:")
|
|
||||||
print(f"\t header_length={len(main_header)}, bin_length={len(bin_main)}[{hex(len(bin_main))}]")
|
|
||||||
print(f"Back File:")
|
|
||||||
print(f"\t header_length={len(back_header)}, bin_length={len(bin_back)}[{hex(len(bin_back))}]")
|
|
||||||
|
|
||||||
# 组装镜像
|
|
||||||
Image = [0xFF] * 0x058000
|
|
||||||
offset_image = 0
|
|
||||||
Image[offset_image: offset_image + len(bin_boot)] = bin_boot
|
|
||||||
offset_image = 0x00C000
|
|
||||||
Image[offset_image: offset_image + len(bin_main)] = bin_main
|
|
||||||
offset_image = 0x030000
|
|
||||||
Image[offset_image: offset_image + len(bin_back)] = bin_back
|
|
||||||
offset_image = 0x054000
|
|
||||||
Image[offset_image: offset_image + len(main_header)] = main_header
|
|
||||||
offset_image = 0x056000
|
|
||||||
Image[offset_image: offset_image + len(back_header)] = back_header
|
|
||||||
|
|
||||||
return bytearray(Image), main_header, back_header
|
|
||||||
|
|
||||||
|
|
||||||
def GeneratePackage_DLSY001_p460(path_hex: Path):
|
def GeneratePackage_DLSY001_p460(path_hex: Path):
|
||||||
""" 叠光优化器-460平台版本 生成升级包 """
|
""" 叠光优化器-460平台版本 生成升级包 """
|
||||||
|
|||||||
@@ -14,9 +14,11 @@ modbus_map = {
|
|||||||
0x01: ["Hex示例", 1],
|
0x01: ["Hex示例", 1],
|
||||||
0x02: ["Int示例", 2],
|
0x02: ["Int示例", 2],
|
||||||
0x03: ["Int32示例", 3],
|
0x03: ["Int32示例", 3],
|
||||||
0x04: ["str示例", 4, 16],
|
0x05: ["str示例", 4, 16],
|
||||||
0x10: ["addr示例", 5, 6],
|
0x15: ["addr示例", 5, 6],
|
||||||
0x20: ["Float示例", 6],
|
0x1B: ["Float示例", 6],
|
||||||
|
0x1D: ["numberList示例", 3],
|
||||||
|
0x20: ["callback示例", 16],
|
||||||
}
|
}
|
||||||
|
|
||||||
frame_modbus = {
|
frame_modbus = {
|
||||||
|
|||||||
@@ -1,158 +1,8 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from device.LaminaAdapter import LaminaAdapter
|
from device.LaminaAdapter import LaminaAdapter
|
||||||
from device.LaminaAdapter import GenerateImage_SLCP001_p4a0, GeneratePackage_SLCP001_p4a0
|
|
||||||
from device.LaminaAdapter import GenerateImage_SLCP101_p460, GeneratePackage_SLCP101_p460
|
|
||||||
from device.LaminaAdapter import GenerateImage_SLCP102_p460, GeneratePackage_SLCP102_p460
|
|
||||||
from device.LaminaAdapter import GenerateImage_DLSY001_p460, GeneratePackage_DLSY001_p460
|
from device.LaminaAdapter import GenerateImage_DLSY001_p460, GeneratePackage_DLSY001_p460
|
||||||
|
|
||||||
|
|
||||||
def Process0(path_boot: Path, path_project: Path):
|
|
||||||
""" 适配器-SLCP001 镜像生成流程 """
|
|
||||||
root_boot = path_boot
|
|
||||||
root_main = path_project
|
|
||||||
result = root_main
|
|
||||||
|
|
||||||
# 正常启动镜像
|
|
||||||
hex_boot = root_boot / "bootloader.hex"
|
|
||||||
hex_main = root_main / "lamina_adapter.hex"
|
|
||||||
hex_back = root_main / "lamina_adapter_back.hex"
|
|
||||||
hex_update = hex_main
|
|
||||||
if (not hex_boot.exists()) or (not hex_main.exists()) or (not hex_back.exists()):
|
|
||||||
raise Exception("缺失必要程序文件")
|
|
||||||
|
|
||||||
file_image = result / f'{hex_main.stem}_ROM.bin'
|
|
||||||
file_main_header = result / 'SLCP001_main.header'
|
|
||||||
file_back_header = result / 'SLCP001_back.header'
|
|
||||||
file_package = result / f'{hex_update.stem}.dat'
|
|
||||||
file_bin = result / f'{hex_update.stem}.bin'
|
|
||||||
|
|
||||||
data_bins = GenerateImage_SLCP001_p4a0(hex_boot, hex_main, hex_back)
|
|
||||||
data_package, data_bin = GeneratePackage_SLCP001_p4a0(hex_update)
|
|
||||||
|
|
||||||
file_image.write_bytes(data_bins[0].copy())
|
|
||||||
file_main_header.write_bytes(data_bins[1].copy())
|
|
||||||
file_back_header.write_bytes(data_bins[2].copy())
|
|
||||||
file_package.write_bytes(data_package)
|
|
||||||
file_bin.write_bytes(data_bin)
|
|
||||||
|
|
||||||
# 异常镜像-主分区md5错误
|
|
||||||
file_image1 = result / f'{file_image.stem}_b1.bin'
|
|
||||||
data_image = data_bins[0].copy()
|
|
||||||
data_image[0x0FC018: 0x0FC01A] = [0x00, 0x01]
|
|
||||||
file_image1.write_bytes(data_image)
|
|
||||||
|
|
||||||
# 异常镜像-备份分区md5错误
|
|
||||||
file_image2 = result / f'{file_image.stem}_b2.bin'
|
|
||||||
data_image = data_bins[0].copy()
|
|
||||||
data_image[0x0FE018: 0x0FE01A] = [0x00, 0x01]
|
|
||||||
file_image2.write_bytes(data_image)
|
|
||||||
|
|
||||||
# 异常镜像-双分区md5错误
|
|
||||||
file_image3 = result / f'{file_image.stem}_b3.bin'
|
|
||||||
data_image = data_bins[0].copy()
|
|
||||||
data_image[0x0FC018: 0x0FC01A] = [0x00, 0x01]
|
|
||||||
data_image[0x0FE018: 0x0FE01A] = [0x00, 0x01]
|
|
||||||
file_image3.write_bytes(data_image)
|
|
||||||
|
|
||||||
|
|
||||||
def Process1(path_boot: Path, path_project: Path):
|
|
||||||
""" 适配器-SLCP101 镜像生成流程 """
|
|
||||||
root_boot = path_boot
|
|
||||||
root_main = path_project
|
|
||||||
result = root_main
|
|
||||||
|
|
||||||
# 正常启动镜像
|
|
||||||
hex_boot = root_boot / "bootloader.hex"
|
|
||||||
hex_main = root_main / "lamina_adapter.hex"
|
|
||||||
hex_back = root_main / "lamina_adapter_back.hex"
|
|
||||||
hex_update = hex_main
|
|
||||||
if (not hex_boot.exists()) or (not hex_main.exists()) or (not hex_back.exists()):
|
|
||||||
raise Exception("缺失必要程序文件")
|
|
||||||
|
|
||||||
file_image = result / f'{hex_main.stem}_ROM.bin'
|
|
||||||
file_main_header = result / 'SLCP101_main.header'
|
|
||||||
file_back_header = result / 'SLCP101_back.header'
|
|
||||||
file_package = result / f'{hex_update.stem}.dat'
|
|
||||||
file_bin = result / f'{hex_update.stem}.bin'
|
|
||||||
|
|
||||||
data_bins = GenerateImage_SLCP101_p460(hex_boot, hex_main, hex_back)
|
|
||||||
data_package, data_bin = GeneratePackage_SLCP101_p460(hex_update)
|
|
||||||
|
|
||||||
file_image.write_bytes(data_bins[0].copy())
|
|
||||||
file_main_header.write_bytes(data_bins[1].copy())
|
|
||||||
file_back_header.write_bytes(data_bins[2].copy())
|
|
||||||
file_package.write_bytes(data_package)
|
|
||||||
file_bin.write_bytes(data_bin)
|
|
||||||
|
|
||||||
# 异常镜像-主分区md5错误
|
|
||||||
file_image1 = result / f'{file_image.stem}_b1.bin'
|
|
||||||
data_image = data_bins[0].copy()
|
|
||||||
data_image[0x054018: 0x05401A] = [0x00, 0x01]
|
|
||||||
file_image1.write_bytes(data_image)
|
|
||||||
|
|
||||||
# 异常镜像-备份分区md5错误
|
|
||||||
file_image2 = result / f'{file_image.stem}_b2.bin'
|
|
||||||
data_image = data_bins[0].copy()
|
|
||||||
data_image[0x056018: 0x05601A] = [0x00, 0x01]
|
|
||||||
file_image2.write_bytes(data_image)
|
|
||||||
|
|
||||||
# 异常镜像-双分区md5错误
|
|
||||||
file_image3 = result / f'{file_image.stem}_b3.bin'
|
|
||||||
data_image = data_bins[0].copy()
|
|
||||||
data_image[0x054018: 0x05401A] = [0x00, 0x01]
|
|
||||||
data_image[0x056018: 0x05601A] = [0x00, 0x01]
|
|
||||||
file_image3.write_bytes(data_image)
|
|
||||||
|
|
||||||
|
|
||||||
def Process1_v2(path_boot: Path, path_project: Path):
|
|
||||||
""" 适配器-SLCP102 镜像生成流程 """
|
|
||||||
root_boot = path_boot
|
|
||||||
root_main = path_project
|
|
||||||
result = root_main
|
|
||||||
|
|
||||||
# 正常启动镜像
|
|
||||||
hex_boot = root_boot / "bootloader.hex"
|
|
||||||
hex_main = root_main / "lamina_adapter.hex"
|
|
||||||
hex_back = root_main / "lamina_adapter_back.hex"
|
|
||||||
hex_update = hex_main
|
|
||||||
if (not hex_boot.exists()) or (not hex_main.exists()) or (not hex_back.exists()):
|
|
||||||
raise Exception("缺失必要程序文件")
|
|
||||||
|
|
||||||
file_image = result / f'{hex_main.stem}_ROM.bin'
|
|
||||||
file_main_header = result / 'SLCP102_main.header'
|
|
||||||
file_back_header = result / 'SLCP102_back.header'
|
|
||||||
file_package = result / f'{hex_update.stem}.dat'
|
|
||||||
file_bin = result / f'{hex_update.stem}.bin'
|
|
||||||
|
|
||||||
data_bins = GenerateImage_SLCP102_p460(hex_boot, hex_main, hex_back)
|
|
||||||
data_package, data_bin = GeneratePackage_SLCP102_p460(hex_update)
|
|
||||||
|
|
||||||
file_image.write_bytes(data_bins[0].copy())
|
|
||||||
file_main_header.write_bytes(data_bins[1].copy())
|
|
||||||
file_back_header.write_bytes(data_bins[2].copy())
|
|
||||||
file_package.write_bytes(data_package)
|
|
||||||
file_bin.write_bytes(data_bin)
|
|
||||||
|
|
||||||
# 异常镜像-主分区md5错误
|
|
||||||
file_image1 = result / f'{file_image.stem}_b1.bin'
|
|
||||||
data_image = data_bins[0].copy()
|
|
||||||
data_image[0x054018: 0x05401A] = [0x00, 0x01]
|
|
||||||
file_image1.write_bytes(data_image)
|
|
||||||
|
|
||||||
# 异常镜像-备份分区md5错误
|
|
||||||
file_image2 = result / f'{file_image.stem}_b2.bin'
|
|
||||||
data_image = data_bins[0].copy()
|
|
||||||
data_image[0x056018: 0x05601A] = [0x00, 0x01]
|
|
||||||
file_image2.write_bytes(data_image)
|
|
||||||
|
|
||||||
# 异常镜像-双分区md5错误
|
|
||||||
file_image3 = result / f'{file_image.stem}_b3.bin'
|
|
||||||
data_image = data_bins[0].copy()
|
|
||||||
data_image[0x054018: 0x05401A] = [0x00, 0x01]
|
|
||||||
data_image[0x056018: 0x05601A] = [0x00, 0x01]
|
|
||||||
file_image3.write_bytes(data_image)
|
|
||||||
|
|
||||||
|
|
||||||
def Process2():
|
def Process2():
|
||||||
""" 优化器-DLSY001 镜像生成流程 """
|
""" 优化器-DLSY001 镜像生成流程 """
|
||||||
root = Path(r"D:\WorkingProject\LightStackOptimizer\software\lamina_optimizer\lamina_optimizer\Debug")
|
root = Path(r"D:\WorkingProject\LightStackOptimizer\software\lamina_optimizer\lamina_optimizer\Debug")
|
||||||
@@ -215,18 +65,20 @@ def Process(type_dev: str, path_boot: Path, path_project: Path, makePackages: bo
|
|||||||
hex_boot = root_boot / "bootloader.hex"
|
hex_boot = root_boot / "bootloader.hex"
|
||||||
hex_main = root_main / f"{program_name}.hex"
|
hex_main = root_main / f"{program_name}.hex"
|
||||||
hex_back = root_main / f"{program_name}_back.hex"
|
hex_back = root_main / f"{program_name}_back.hex"
|
||||||
hex_update = hex_main
|
|
||||||
|
|
||||||
file_image = result / f'{hex_main.stem}_ROM.bin'
|
file_image = result / f'{hex_main.stem}_ROM.bin'
|
||||||
file_package = result / f'{hex_update.stem}.dat'
|
file_package = result / f'{hex_main.stem}.dat'
|
||||||
|
file_package_backup = result / f'{hex_back.stem}.dat'
|
||||||
|
|
||||||
dev_lamina = LaminaAdapter(None, type_dev=type_dev)
|
dev_lamina = LaminaAdapter(None, type_dev=type_dev)
|
||||||
|
|
||||||
if makePackages:
|
if makePackages:
|
||||||
if not hex_main.exists():
|
if hex_main.exists():
|
||||||
raise Exception("缺失必要程序文件")
|
data_package = dev_lamina.make_package(hex_main)
|
||||||
data_package = dev_lamina.make_package(hex_update)
|
|
||||||
file_package.write_bytes(data_package)
|
file_package.write_bytes(data_package)
|
||||||
|
if hex_back.exists():
|
||||||
|
data_package_backup = dev_lamina.make_package(hex_back, upgrade_backup=True)
|
||||||
|
file_package_backup.write_bytes(data_package_backup)
|
||||||
if makeImage:
|
if makeImage:
|
||||||
if (not hex_boot.exists()) or (not hex_main.exists()) or (not hex_back.exists()):
|
if (not hex_boot.exists()) or (not hex_main.exists()) or (not hex_back.exists()):
|
||||||
raise Exception("缺失必要程序文件")
|
raise Exception("缺失必要程序文件")
|
||||||
@@ -286,4 +138,4 @@ if __name__ == "__main__":
|
|||||||
# Process1_v2(path_boot2, path_main) # 适配器SLCP102
|
# Process1_v2(path_boot2, path_main) # 适配器SLCP102
|
||||||
# Process2()
|
# Process2()
|
||||||
|
|
||||||
Process(*mode_config['SLCP001'])
|
Process(*mode_config['SLCP101'])
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import time
|
import time
|
||||||
from function.tools.ByteConv import display_hex
|
from device.tools.ByteConv import display_hex
|
||||||
from device.LaminaController import LaminaController
|
from device.LaminaController import LaminaController
|
||||||
from device.LaminaController import ParamMap_LaminaController
|
from device.LaminaController import ParamMap_LaminaController
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,196 @@
|
|||||||
import time
|
import time
|
||||||
|
import pytest
|
||||||
|
import logging
|
||||||
|
from typing import Tuple, Generator, List, Optional, Union
|
||||||
from device.DeviceSerial import DeviceSerial
|
from device.DeviceSerial import DeviceSerial
|
||||||
from device.LaminaAdapter import ParamMap_LaminaAdapter
|
from device.LaminaAdapter import LaminaAdapter
|
||||||
|
|
||||||
|
from device.tools.ByteConv import display_hex
|
||||||
|
|
||||||
|
TestCase_Controller = {
|
||||||
|
# 测试用例定义
|
||||||
|
# 0 - 正常写入数据序列; [(写入数据, 读取数据)]
|
||||||
|
# 1 - 范围限制测试; (最小值, 最大值)
|
||||||
|
# 2 - 相关大小限制测试; ((0-等于, 1-小于, 2-大于), 相关值地址, 死区范围)
|
||||||
|
0x60: {0: [(0, '0x0000'), (1, '0x0001'),
|
||||||
|
(2, '0x0001'), (0xFF, '0x0001'), (0xFFFF, '0x0001')]}, # 整机运行使能
|
||||||
|
0x61: {0: [(60.0, 60.0)], 1: (40, 100), 2: (1, 0x62, 0.5)}, # 最小启动允许输入电压
|
||||||
|
0x62: {0: [(440.0, 440.0)], 1: (350, 560), 2: (2, 0x61, 0.5)}, # 最大启动允许输入电压
|
||||||
|
0x63: {0: [(58, 58.0)], 1: (38, 98), 2: (1, 0x64, 0.5)}, # 最小停机输入电压
|
||||||
|
0x64: {0: [(442, 442.0)], 1: (352, 562), 2: (2, 0x63, 0.5)}, # 最大停机输入电压
|
||||||
|
0x65: {0: [(41, 41.0)], 1: (30, 60), 2: (1, 0x66, 0.5)}, # 最小启动允许输出电压
|
||||||
|
0x66: {0: [(57, 57.0)], 1: (50, 80), 2: (2, 0x65, 0.5)}, # 最大启动允许输出电压
|
||||||
|
0x67: {0: [(40, 40.0)], 1: (28, 58), 2: (1, 0x68, 0.5)}, # 最小停止允许输出电压
|
||||||
|
0x68: {0: [(58, 58.0)], 1: (52, 82), 2: (2, 0x67, 0.5)}, # 最大停止允许输出电压
|
||||||
|
0x69: {0: [(0.1, 0.1)], 1: (0, 5), 2: (1, 0x6A, 1.0)}, # 最小MPPT电流限值
|
||||||
|
0x6A: {0: [(22, 22.0)], 1: (5, 30), 2: (2, 0x69, 1.0)}, # 最大MPPT电流限值
|
||||||
|
0x6C: {0: [(6000, 6000)], 1: (3000, 7999.999),2: (0, 0x6E, 0.0)}, # 最大功率限值(由于转换误差, 无法写入8000W)
|
||||||
|
0x6E: {0: [(6000, 6000)], 1: (3000, 7999.999), }, # 最大功率限值存储值(由于转换误差, 无法写入8000W)
|
||||||
|
0x70: {0: [(500, 500)], 1: (400, 800), }, # Boost输入过压保护值
|
||||||
|
0x71: {0: [(460, 460)], 1: (300, 600), }, # Boost输出过压保护值
|
||||||
|
0x72: {0: [(60, 60)], 1: (40, 80), 2: (2, 0x73, 0.5)}, # LLC输出过压保护值
|
||||||
|
0x73: {0: [(40, 40)], 1: (20, 50), 2: (1, 0x72, 0.5)}, # LLC输出欠压保护值
|
||||||
|
0x74: {0: [(20, 20)], 1: (6, 30), }, # Boost电感过流保护值
|
||||||
|
0x75: {0: [(20, 20)], 1: (10, 30), }, # LLC输出电流均值保护值
|
||||||
|
0x76: {0: [(20, 20)], 1: (10, 30), }, # LLC输出电流峰值保护值
|
||||||
|
0x78: {0: [(6200, 6200)], 1: (4500, 9000), }, # 过载保护值
|
||||||
|
0x7A: {0: [(105, 105)], 1: (30, 150), 2: (2, 0x7B, 1.0)}, # 过温故障值
|
||||||
|
0x7B: {0: [(95, 95)], 1: (20, 150), 2: (1, 0x7A, 1.0)}, # 过温告警值
|
||||||
|
0x7C: {0: [(85, 85)], 1: (0, 120), 2: (1, 0x7A, 1.0)}, # 过温恢复值
|
||||||
|
0x7D: {0: [(10, 10)], 1: (0, 60), }, # 输出继电器故障判断差值
|
||||||
|
0x7E: {0: [(55, 55)], 1: (35, 60), }, # LLC输出电压给定值
|
||||||
|
0x7F: {0: [(420, 420)], 1: (320, 460), }, # Boost输出电压给定值
|
||||||
|
0x80: {0: [(56, 56)], 1: (10, 80), }, # 三点法中间阈值
|
||||||
|
0x81: {0: [(57, 57)], 1: (10, 80), }, # 浮充电压
|
||||||
|
0x82: {0: [(56, 56)], 1: (10, 80), }, # 恒压充电电压
|
||||||
|
0x83: {0: [(380, 380)], 1: (0, 450), }, # llc软起开始电压
|
||||||
|
0x84: {0: [(395, 395)], 1: (0, 450), 2: (1, 0x85, 0.5)}, # boost开始运行电压
|
||||||
|
0x85: {0: [(410, 410)], 1: (0, 450), 2: (2, 0x84, 0.5)}, # boost停止运行电压
|
||||||
|
0x86: {0: [(15000, 15000)], 1: (0, 30000), }, # 绝缘检测正阻抗限值
|
||||||
|
0x88: {0: [(15000, 15000)], 1: (0, 30000), }, # 绝缘检测负阻抗限值
|
||||||
|
0x8A: {0: [(123, 123), (137, 137)], 1: (50, 200), 2: (1, 0x8B, 0.2)}, # 抖动频率下限(精度误差严重, 难以正常测试)
|
||||||
|
0x8B: {0: [(137, 137), (123, 123)], 1: (50, 200), 2: (2, 0x8A, -0.2)}, # 抖动频率上限(精度误差严重, 难以正常测试)
|
||||||
|
0x170: {0: [(b'TTE0102DX20241001120001', 'TTE0102DX20241001120001\x00\x00\x00\x00\x00\x00\x00\x00\x00')]}, # 设备序列号
|
||||||
|
0x180: {0: [([0x24, 0x10, 0x01, 0x12, 0x00, 0x01], '$\x10\x01\x12\x00\x01' + 26 * '\x00')]}, # 设备MES码
|
||||||
|
0x190: {0: [(b'241001120001', '241001120001' + 20 * '\000')]}, # 出厂日期批次
|
||||||
|
}
|
||||||
|
TestCase_Adapter = {
|
||||||
|
# 测试用例定义
|
||||||
|
# 0 - 正常写入数据序列; [(写入数据, 读取数据)]
|
||||||
|
# 1 - 范围限制测试; (最小值, 最大值)
|
||||||
|
# 2 - 相关大小限制测试; ((0-等于, 1-小于, 2-大于), 相关值地址, 死区范围)
|
||||||
|
0x60: {0: [(0, '0x0000'), (1, '0x0001'),
|
||||||
|
(2, '0x0001'), (0xFF, '0x0001'), (0xFFFF, '0x0001')]}, # 整机运行使能
|
||||||
|
0x61: {0: [(60.0, 60.0)], 1: (40, 100), 2: (1, 0x62, 0.5)}, # 最小启动允许输入电压
|
||||||
|
0x62: {0: [(440.0, 440.0)], 1: (350, 560), 2: (2, 0x61, 0.5)}, # 最大启动允许输入电压
|
||||||
|
0x63: {0: [(58, 58.0)], 1: (38, 98), 2: (1, 0x64, 0.5)}, # 最小停机输入电压
|
||||||
|
0x64: {0: [(442, 442.0)], 1: (352, 562), 2: (2, 0x63, 0.5)}, # 最大停机输入电压
|
||||||
|
0x65: {0: [(41, 41.0)], 1: (30, 60), 2: (1, 0x66, 0.5)}, # 最小启动允许输出电压
|
||||||
|
0x66: {0: [(57, 57.0)], 1: (50, 80), 2: (2, 0x65, 0.5)}, # 最大启动允许输出电压
|
||||||
|
0x67: {0: [(40, 40.0)], 1: (28, 58), 2: (1, 0x68, 0.5)}, # 最小停止允许输出电压
|
||||||
|
0x68: {0: [(58, 58.0)], 1: (52, 82), 2: (2, 0x67, 0.5)}, # 最大停止允许输出电压
|
||||||
|
0x69: {0: [(0.1, 0.1)], 1: (0, 5), 2: (1, 0x6A, 1.0)}, # 最小MPPT电流限值
|
||||||
|
0x6A: {0: [(22, 22.0)], 1: (5, 30), 2: (2, 0x69, 1.0)}, # 最大MPPT电流限值
|
||||||
|
0x6C: {0: [(6000, 6000)], 1: (3000, 7999.999),2: (0, 0x6E, 0.0)}, # 最大功率限值(由于转换误差, 无法写入8000W)
|
||||||
|
0x6E: {0: [(6000, 6000)], 1: (3000, 7999.999), }, # 最大功率限值存储值(由于转换误差, 无法写入8000W)
|
||||||
|
0x70: {0: [(500, 500)], 1: (400, 800), }, # Boost输入过压保护值
|
||||||
|
0x71: {0: [(460, 460)], 1: (300, 600), }, # Boost输出过压保护值
|
||||||
|
0x72: {0: [(60, 60)], 1: (40, 80), 2: (2, 0x73, 0.5)}, # LLC输出过压保护值
|
||||||
|
0x73: {0: [(40, 40)], 1: (20, 50), 2: (1, 0x72, 0.5)}, # LLC输出欠压保护值
|
||||||
|
0x74: {0: [(20, 20)], 1: (6, 30), }, # Boost电感过流保护值
|
||||||
|
0x75: {0: [(20, 20)], 1: (10, 30), }, # LLC输出电流均值保护值
|
||||||
|
0x76: {0: [(20, 20)], 1: (10, 30), }, # LLC输出电流峰值保护值
|
||||||
|
0x78: {0: [(6200, 6200)], 1: (4500, 9000), }, # 过载保护值
|
||||||
|
0x7A: {0: [(105, 105)], 1: (30, 150), 2: (2, 0x7B, 1.0)}, # 过温故障值
|
||||||
|
0x7B: {0: [(95, 95)], 1: (20, 150), 2: (1, 0x7A, 1.0)}, # 过温告警值
|
||||||
|
0x7C: {0: [(85, 85)], 1: (0, 120), 2: (1, 0x7A, 1.0)}, # 过温恢复值
|
||||||
|
0x7D: {0: [(10, 10)], 1: (0, 60), }, # 输出继电器故障判断差值
|
||||||
|
0x7E: {0: [(55, 55)], 1: (35, 60), }, # LLC输出电压给定值
|
||||||
|
0x7F: {0: [(420, 420)], 1: (320, 460), }, # Boost输出电压给定值
|
||||||
|
0x80: {0: [(56, 56)], 1: (10, 80), }, # 三点法中间阈值
|
||||||
|
0x81: {0: [(57, 57)], 1: (10, 80), }, # 浮充电压
|
||||||
|
0x82: {0: [(56, 56)], 1: (10, 80), }, # 恒压充电电压
|
||||||
|
0x83: {0: [(380, 380)], 1: (0, 450), }, # llc软起开始电压
|
||||||
|
0x84: {0: [(395, 395)], 1: (0, 450), 2: (1, 0x85, 0.5)}, # boost开始运行电压
|
||||||
|
0x85: {0: [(410, 410)], 1: (0, 450), 2: (2, 0x84, 0.5)}, # boost停止运行电压
|
||||||
|
0x86: {0: [(15000, 15000)], 1: (0, 30000), }, # 绝缘检测正阻抗限值
|
||||||
|
0x88: {0: [(15000, 15000)], 1: (0, 30000), }, # 绝缘检测负阻抗限值
|
||||||
|
0x8A: {0: [(123, 123), (137, 137)], 1: (50, 200), 2: (1, 0x8B, 0.2)}, # 抖动频率下限(精度误差严重, 难以正常测试)
|
||||||
|
0x8B: {0: [(137, 137), (123, 123)], 1: (50, 200), 2: (2, 0x8A, -0.2)}, # 抖动频率上限(精度误差严重, 难以正常测试)
|
||||||
|
0x170: {0: [(b'TTE0102DX20241001120001', 'TTE0102DX20241001120001\x00\x00\x00\x00\x00\x00\x00\x00\x00')]}, # 设备序列号
|
||||||
|
0x180: {0: [([0x24, 0x10, 0x01, 0x12, 0x00, 0x01], '$\x10\x01\x12\x00\x01' + 26 * '\x00')]}, # 设备MES码
|
||||||
|
0x190: {0: [(b'241001120001', '241001120001' + 20 * '\000')]}, # 出厂日期批次
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def frame_write(device:DeviceSerial, address, length, value):
|
||||||
|
""" 整合参数写入接口 """
|
||||||
|
return device.frame_write(address, length, value)
|
||||||
|
|
||||||
|
def frame_read(device:DeviceSerial, address, length=None):
|
||||||
|
""" 整合参数读取接口 """
|
||||||
|
if length is None:
|
||||||
|
info = device.block['data']['data_define'][address]
|
||||||
|
length = 2 if info[1] in [3, 6] else 1
|
||||||
|
length = info[2] if info[1] in [4, 5, 7] else length
|
||||||
|
|
||||||
|
return device.output['Regs'][address][1] if device.frame_read(address, length) else None
|
||||||
|
|
||||||
|
def value_case_generator(device:DeviceSerial, address:int, itemCase:dict) -> Generator[object, object, bool]:
|
||||||
|
""" 依据地址与参数配置生成测试用例 """
|
||||||
|
addr_relate = None
|
||||||
|
list_case_normal = []
|
||||||
|
match itemCase.keys():
|
||||||
|
case 0: # 常规读写用例测试
|
||||||
|
for data_write, data_read in itemCase[0]:
|
||||||
|
logging.info(f"Param Case:\taddr={display_hex(address)}, \tvalue={data_write}")
|
||||||
|
yield data_write, data_read, True
|
||||||
|
case 2: # 存在大小约束相关项
|
||||||
|
assert device.block['data']['data_define'][address][1] in [2, 3]
|
||||||
|
type_relate, addr_relate, dead_zone = itemCase[2]
|
||||||
|
val_relate = frame_read(device, addr_relate)
|
||||||
|
yield val_relate, val_relate, False
|
||||||
|
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
case 1: # 写入范围用例测试
|
||||||
|
val_min, val_max = itemCase[1]
|
||||||
|
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
if 1 in itemCase.keys():
|
||||||
|
""" 写入范围用例测试 """
|
||||||
|
testzone = 0.7 if info_param[1] in [2, 3] and len(info_param) < 3 else 7 / info_param[2]
|
||||||
|
accuracy = 0.20001 if info_param[1] in [2, 3] and len(info_param) < 3 else 2.0001 / info_param[2]
|
||||||
|
val_min, val_max = itemCase[1]
|
||||||
|
if 2 in itemCase.keys():
|
||||||
|
""" 存在大小约束相关项 """
|
||||||
|
list_case_relate = [] # 对约束相关项的修改
|
||||||
|
list_case_late = [] # 存在约束相关项影响后的测试用例
|
||||||
|
mode_relate, addr_relate, deadzone = itemCase[2]
|
||||||
|
val_relate = frame_read(device, addr_relate, ParamCase[addr_relate])
|
||||||
|
if mode_relate == 1:
|
||||||
|
if (val_relate - deadzone) < val_max:
|
||||||
|
""" 约束项已限制写入范围 """
|
||||||
|
list_case_relate.append((val_max + 2 * abs(deadzone), val_max + 2 * abs(deadzone), True))
|
||||||
|
list_case_late.append((val_max + testzone, val_max + testzone, False))
|
||||||
|
list_case_late.append((val_max, val_max, True))
|
||||||
|
list_case_late.append((val_max - testzone, val_max - testzone, True))
|
||||||
|
val_max = val_relate - deadzone
|
||||||
|
else:
|
||||||
|
""" 约束项未限制写入范围 """
|
||||||
|
val_relate = val_max
|
||||||
|
list_case_relate.append((val_relate, val_relate, True))
|
||||||
|
list_case_late.append((val_relate - deadzone + testzone, val_relate - deadzone + testzone, False))
|
||||||
|
list_case_late.append((val_relate - deadzone, val_relate - deadzone, True))
|
||||||
|
list_case_late.append((val_relate - deadzone - testzone, val_relate - deadzone - testzone, True))
|
||||||
|
elif mode_relate == 2:
|
||||||
|
if (val_relate + deadzone) > val_min:
|
||||||
|
""" 约束项已限制写入范围 """
|
||||||
|
list_case_relate.append((val_min - 2 * abs(deadzone), val_min - 2 * abs(deadzone), True))
|
||||||
|
list_case_late.append((val_min - testzone, val_min - testzone, False))
|
||||||
|
list_case_late.append((val_min, val_min, True))
|
||||||
|
list_case_late.append((val_min + testzone, val_min + testzone, True))
|
||||||
|
val_min = val_relate + deadzone
|
||||||
|
else:
|
||||||
|
""" 约束项未限制写入范围 """
|
||||||
|
val_relate = val_min
|
||||||
|
list_case_relate.append((val_relate, val_relate, True))
|
||||||
|
list_case_late.append((val_relate + deadzone - testzone, val_relate + deadzone - testzone, False))
|
||||||
|
list_case_late.append((val_relate + deadzone, val_relate + deadzone, True))
|
||||||
|
list_case_late.append((val_relate + deadzone + testzone, val_relate + deadzone + testzone, True))
|
||||||
|
|
||||||
|
list_case_normal.append((val_min - testzone, val_min - testzone, False))
|
||||||
|
list_case_normal.append((val_min, val_min, True))
|
||||||
|
list_case_normal.append((val_min + testzone, val_min + testzone, True))
|
||||||
|
list_case_normal.append((val_max + testzone, val_max + testzone, False))
|
||||||
|
list_case_normal.append((val_max, val_max, True))
|
||||||
|
list_case_normal.append((val_max - testzone, val_max - testzone, True))
|
||||||
|
|
||||||
|
print(f"Param Case:\taddr={display_hex(addr_param)}")
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def test_communication(device: DeviceSerial, time_out=2):
|
def test_communication(device: DeviceSerial, time_out=2):
|
||||||
@@ -25,3 +215,150 @@ def test_communication(device: DeviceSerial, time_out=2):
|
|||||||
print(f"Success Rate: {device.log['read'] / device.log['send'] * 100}%")
|
print(f"Success Rate: {device.log['read'] / device.log['send'] * 100}%")
|
||||||
device.flag_print, device.retry, device.time_out = param_saved
|
device.flag_print, device.retry, device.time_out = param_saved
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def device():
|
||||||
|
mode_config = {
|
||||||
|
"Debug": {'com_name': 'COM3',
|
||||||
|
'frame_print': None,
|
||||||
|
'time_out': 0.5, 'retry': 3},
|
||||||
|
}
|
||||||
|
device = LaminaAdapter(**mode_config['Debug'])
|
||||||
|
yield device
|
||||||
|
|
||||||
|
device.close_connection()
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("address, case_value", *TestCase_Adapter.items())
|
||||||
|
def test_parameters(device:DeviceSerial, address, itemCase):
|
||||||
|
""" 参数读写测试 """
|
||||||
|
|
||||||
|
addr_relate = None
|
||||||
|
itemCase = ParamCase[addr_param]
|
||||||
|
list_case_normal = []
|
||||||
|
if 0 in itemCase.keys():
|
||||||
|
""" 常规读写用例测试 """
|
||||||
|
for data_write, data_read in itemCase[0]:
|
||||||
|
list_case_normal.append((data_write, data_read, True))
|
||||||
|
if 1 in itemCase.keys():
|
||||||
|
""" 写入范围用例测试 """
|
||||||
|
testzone = 0.7 if info_param[1] in [2, 3] and len(info_param) < 3 else 7 / info_param[2]
|
||||||
|
accuracy = 0.20001 if info_param[1] in [2, 3] and len(info_param) < 3 else 2.0001 / info_param[2]
|
||||||
|
val_min, val_max = itemCase[1]
|
||||||
|
if 2 in itemCase.keys():
|
||||||
|
""" 存在大小约束相关项 """
|
||||||
|
list_case_relate = [] # 对约束相关项的修改
|
||||||
|
list_case_late = [] # 存在约束相关项影响后的测试用例
|
||||||
|
mode_relate, addr_relate, deadzone = itemCase[2]
|
||||||
|
val_relate = frame_read(device, addr_relate, ParamCase[addr_relate])
|
||||||
|
if mode_relate == 1:
|
||||||
|
if (val_relate - deadzone) < val_max:
|
||||||
|
""" 约束项已限制写入范围 """
|
||||||
|
list_case_relate.append((val_max + 2 * abs(deadzone), val_max + 2 * abs(deadzone), True))
|
||||||
|
list_case_late.append((val_max + testzone, val_max + testzone, False))
|
||||||
|
list_case_late.append((val_max, val_max, True))
|
||||||
|
list_case_late.append((val_max - testzone, val_max - testzone, True))
|
||||||
|
val_max = val_relate - deadzone
|
||||||
|
else:
|
||||||
|
""" 约束项未限制写入范围 """
|
||||||
|
val_relate = val_max
|
||||||
|
list_case_relate.append((val_relate, val_relate, True))
|
||||||
|
list_case_late.append((val_relate - deadzone + testzone, val_relate - deadzone + testzone, False))
|
||||||
|
list_case_late.append((val_relate - deadzone, val_relate - deadzone, True))
|
||||||
|
list_case_late.append((val_relate - deadzone - testzone, val_relate - deadzone - testzone, True))
|
||||||
|
elif mode_relate == 2:
|
||||||
|
if (val_relate + deadzone) > val_min:
|
||||||
|
""" 约束项已限制写入范围 """
|
||||||
|
list_case_relate.append((val_min - 2 * abs(deadzone), val_min - 2 * abs(deadzone), True))
|
||||||
|
list_case_late.append((val_min - testzone, val_min - testzone, False))
|
||||||
|
list_case_late.append((val_min, val_min, True))
|
||||||
|
list_case_late.append((val_min + testzone, val_min + testzone, True))
|
||||||
|
val_min = val_relate + deadzone
|
||||||
|
else:
|
||||||
|
""" 约束项未限制写入范围 """
|
||||||
|
val_relate = val_min
|
||||||
|
list_case_relate.append((val_relate, val_relate, True))
|
||||||
|
list_case_late.append((val_relate + deadzone - testzone, val_relate + deadzone - testzone, False))
|
||||||
|
list_case_late.append((val_relate + deadzone, val_relate + deadzone, True))
|
||||||
|
list_case_late.append((val_relate + deadzone + testzone, val_relate + deadzone + testzone, True))
|
||||||
|
|
||||||
|
list_case_normal.append((val_min - testzone, val_min - testzone, False))
|
||||||
|
list_case_normal.append((val_min, val_min, True))
|
||||||
|
list_case_normal.append((val_min + testzone, val_min + testzone, True))
|
||||||
|
list_case_normal.append((val_max + testzone, val_max + testzone, False))
|
||||||
|
list_case_normal.append((val_max, val_max, True))
|
||||||
|
list_case_normal.append((val_max - testzone, val_max - testzone, True))
|
||||||
|
|
||||||
|
print(f"Param Case:\taddr={display_hex(addr_param)}")
|
||||||
|
|
||||||
|
last_value = frame_read(device, addr_param, info_param)
|
||||||
|
for case_test in list_case_normal:
|
||||||
|
print(f"\tnormal case={case_test}")
|
||||||
|
result = frame_write(device, addr_param, info_param, case_test[0])
|
||||||
|
assert result == case_test[2]
|
||||||
|
current_value = frame_read(device, addr_param, info_param)
|
||||||
|
if current_value is None:
|
||||||
|
raise Exception("Param Read Fail")
|
||||||
|
elif result:
|
||||||
|
if type(current_value) is float:
|
||||||
|
if abs(current_value - case_test[1]) > accuracy:
|
||||||
|
raise Exception("Param Check Fail")
|
||||||
|
else:
|
||||||
|
if current_value != case_test[1]:
|
||||||
|
raise Exception("Param Check Fail")
|
||||||
|
elif (not result) and current_value != last_value:
|
||||||
|
raise Exception("Param Check Fail")
|
||||||
|
last_value = current_value
|
||||||
|
|
||||||
|
if list_case_normal and list_case_normal[0][1] != last_value:
|
||||||
|
""" 为参数写入首个测试用例数据(一般为参数默认值), 避免影响后续参数测试 """
|
||||||
|
case_test = list_case_normal[0]
|
||||||
|
result = frame_write(device, addr_param, info_param, case_test[0])
|
||||||
|
assert result == case_test[2]
|
||||||
|
last_value = frame_read(device, addr_param, info_param)
|
||||||
|
|
||||||
|
if addr_relate:
|
||||||
|
""" 存在关联测试项 """
|
||||||
|
for case_relate in list_case_relate:
|
||||||
|
print(f"\trelate state: addr={display_hex(addr_relate)}, value={case_relate[0]}")
|
||||||
|
result = frame_write(device, addr_relate, info_param, case_relate[0])
|
||||||
|
if result == case_relate[2]:
|
||||||
|
for case_test in list_case_late:
|
||||||
|
print(f"\t\tstate case={case_test}")
|
||||||
|
result = frame_write(device, addr_param, info_param, case_test[0])
|
||||||
|
assert result == case_test[2]
|
||||||
|
current_value = frame_read(device, addr_param, info_param)
|
||||||
|
if current_value is None:
|
||||||
|
raise Exception("Param Read Fail")
|
||||||
|
elif result:
|
||||||
|
if type(current_value) is float:
|
||||||
|
if abs(current_value - case_test[1]) > accuracy:
|
||||||
|
raise Exception("Param Check Fail")
|
||||||
|
else:
|
||||||
|
if current_value != case_test[1]:
|
||||||
|
raise Exception("Param Check Fail")
|
||||||
|
elif (not result) and current_value != last_value:
|
||||||
|
raise Exception("Param Check Fail")
|
||||||
|
last_value = current_value
|
||||||
|
|
||||||
|
if list_case_normal and list_case_normal[0][1] != last_value:
|
||||||
|
""" 为参数写入首个测试用例数据(一般为参数默认值), 避免影响后续参数测试 """
|
||||||
|
case_test = list_case_normal[0]
|
||||||
|
result = frame_write(device, addr_param, info_param, case_test[0])
|
||||||
|
assert result == case_test[2]
|
||||||
|
|
||||||
|
def main():
|
||||||
|
mode_config = {
|
||||||
|
"Log": {'com_name': None,
|
||||||
|
# 'addr_645': [0x01, 0x00, 0x00, 0x00, 0x00, 0x40],
|
||||||
|
},
|
||||||
|
"Debug": {'com_name': 'COM3',
|
||||||
|
'addr_645': [0x01, 0x02, 0x03, 0x04, 0x05, 0x06],
|
||||||
|
'frame_print': True,
|
||||||
|
'time_out': 0.5, 'retry': 3},
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_lamina = LaminaAdapter(**mode_config['Debug'])
|
||||||
|
test_parameters(dev_lamina, dev_lamina.block['data']['data_define'], TestCase)
|
||||||
|
|
||||||
|
if __name__== "__main__":
|
||||||
|
pytest.main()
|
||||||
|
|||||||
Reference in New Issue
Block a user