跳到主要内容

ESI 文件管理

主站运行时 ESI 走 DLL EcEsi_LoadFile / EcEsi_LoadDirectory,通过 master.set_esi_file() / master.set_esi_files() 调用。Windows 路径按 mbcs(系统 ANSI 代码页)传入 native。

EsiManager 静态类提供 Python 侧 ESI 文件缓存与查询。ESI 文件包含从站的完整配置信息。

三个相关类型
  • EsiManager (darra_ethercat.utils.esi) — ESI 文件加载 / 缓存的静态类
  • EsiLoader (darra_ethercat.slave.esi) — 解析单个 ESI 文件,提取设备信息与启动参数
  • EsiDeviceInfo / EsiStartupParam (darra_ethercat.slave.esi) — EsiLoader 解析出的设备信息 / 启动参数数据类

加载和管理​

load_path()​

@classmethod
def load_path(cls, path: str,
progress_callback: Optional[Callable[[int, int, str], None]] = None) -> None

加载指定路径下的所有 ESI 文件。内部自动跳过已加载文件(等效增量加载)。

参数:

  • path (str) — ESI 文件目录路径
  • progress_callback (Callable, 可选) — 进度回调 (current, total, file_name)

示例:

from darra_ethercat.utils.esi import EsiManager

# 加载默认路径
EsiManager.load_default()

# 加载指定路径,显示进度
EsiManager.load_path(r"C:\EtherCAT\ESI", lambda cur, total, name:
print(f"加载ESI文件: {cur}/{total} - {name}"))

preload()​

@classmethod
def preload(cls, progress_callback: Optional[Callable[[int, int, str], None]] = None) -> None

预加载默认路径的 ESI 文件。

示例:

# 启动时预加载
EsiManager.preload(lambda cur, total, name:
print(f"\r加载ESI: {cur * 100 // total}% - {name}", end=""))
print("\nESI文件加载完成")

load_default()​

@classmethod
def load_default(cls,
progress_callback: Optional[Callable[[int, int, str], None]] = None) -> None

从默认路径加载 ESI 文件(与 preload() 等价,显式语义版本)。

示例:

EsiManager.load_default()

clear()​

@classmethod
def clear(cls) -> None

清除所有已加载的 ESI 文件。

示例:

# 清除并重新加载
EsiManager.clear()
EsiManager.load_path(r"C:\NewESI")

remove_from_cache()​

@classmethod
def remove_from_cache(cls, file_name: str) -> None

从缓存中移除指定 ESI 文件。

示例:

EsiManager.remove_from_cache("MyVendor_EL7211.xml")

查询和检索​

解析单个 ESI 设备节点

要拿到结构化的设备信息(厂商 / 产品 / 版本 / 设备名等),用 EsiLoader 加载某个 ESI 文件后读 loader.device_info(EsiDeviceInfo,见下文 ESI 绑定到从站)。EsiManager 静态类只负责文件级加载 / 缓存与 ConfigData 字节查询(get_config_data_bytes),不解析结构化设备信息。

get_config_data_bytes()​

@classmethod
def get_config_data_bytes(cls, vendor_id: int, product_code: int,
revision: int = 0) -> Optional[bytes]

获取 ESI 配置数据的原始字节。在已加载的 ESI 文件中查找匹配的设备,返回其 EEPROM 配置数据。

参数:

  • vendor_id (int) — 厂商 ID
  • product_code (int) — 产品代码
  • revision (int, 可选) — 修订号,0 表示不限

返回值:

  • Optional[bytes] — 配置数据字节,未找到返回 None

示例:

config = EsiManager.get_config_data_bytes(0x00000002, 0x03F03052)
if config is not None:
print(f"配置数据: {config.hex()}")

find_esi_file()​

def find_esi_file(filename: str, search_paths: Optional[List[str]] = None) -> Optional[str]

根据文件名查找 ESI 文件完整路径。

参数:

  • filename (str) — ESI 文件名
  • search_paths (List[str], 可选) — 搜索路径列表,None 使用默认路径

返回值:

  • Optional[str] — 完整路径,未找到返回 None

示例:

from darra_ethercat.utils.esi import find_esi_file

path = find_esi_file("Beckhoff EL1008.xml")
if path is not None:
print(f"找到文件: {path}")

状态查询​

loaded_file_count()​

@classmethod
def loaded_file_count(cls) -> int

获取已加载的 ESI 文件数量。

示例:

count = EsiManager.loaded_file_count()
print(f"已加载 {count} 个ESI文件")

is_file_loaded()​

@classmethod
def is_file_loaded(cls, file_name: str) -> bool

检查指定 ESI 文件是否已加载。

示例:

if EsiManager.is_file_loaded("MyDevice.xml"):
print("自定义设备ESI已加载")

is_preloaded()​

@classmethod
def is_preloaded(cls) -> bool

检查是否已预加载(即是否有任何已加载文件)。

示例:

if not EsiManager.is_preloaded():
EsiManager.preload()

默认路径​

default_path()​

@classmethod
def default_path(cls) -> str

获取默认 ESI 文件搜索路径。

默认目录不随 wheel 发布

default_path() 返回 <site-packages>/darra_ethercat/esi,该目录不随 SDK wheel 发布,pip 全新安装后通常不存在。ESI 由 Windows 安装器投放到 C:\DARRA\EtherCAT_Master\ESI,加载用 EsiManager.load_path(r"C:\DARRA\EtherCAT_Master\ESI")。默认目录缺失时 load_default() / preload() 记 WARNING,不加载任何文件。

返回值:

  • str — 默认 ESI 目录路径

示例:

path = EsiManager.default_path()
print(f"默认ESI路径: {path}")

ESI 绑定到从站​

运行时参与拓扑 / PDO / DC / 邮箱协议解析的 ESI 绑定在 DLL 侧完成:set_esi_file() / set_esi_files() 载入后,build() 扫站时经 EcEsi_AutoMatchAll 自动匹配到从站。Python 侧 EsiLoader 类负责解析单个 ESI 文件:提取设备信息(device_info)与启动参数(startup_params),挂到从站的 slave.esi 后,CoE 对象字典目录会优先读取该 ESI 树(免 SDO 往返)。

EsiLoader.load()​

class EsiLoader:
def load(self, file_path: str) -> bool

解析指定 ESI XML 文件,提取设备信息与启动参数。常用于需要为某站读取特定厂商版本 ESI 的场景。

参数:

  • file_path (str) — ESI XML 文件完整路径

返回值:

  • bool — 解析成功返回 True; 文件无效 / 解析失败返回 False

示例:

from darra_ethercat.slave.esi import EsiLoader

# 独立解析;也可用 master[2].esi 挂到从站,CoE 对象字典目录会用到
loader = EsiLoader(slave=master[2])
ok = loader.load(r"D:\esi\Vendor_Drive_v3.xml")
if not ok:
print("加载失败, 检查文件路径和 XML 内容")

EsiLoader.is_loaded / file_path / device_info​

解析后查询 ESI 加载状态、文件路径与解析出的设备信息。

类别属性类型读写说明
加载状态is_loadedbool只读ESI 文件是否已加载
加载状态file_pathOptional[str]只读已加载的 ESI 文件路径
设备信息device_infoEsiDeviceInfo只读解析出的设备信息(厂商 / 产品 / 版本 / 设备名)
启动参数startup_paramsList[EsiStartupParam]只读解析出的启动参数(SDO 初始化项)列表

示例:

loader = EsiLoader(slave=master[2])
loader.load(r"D:\esi\Vendor.xml")
if loader.is_loaded:
print(f"ESI 文件: {loader.file_path}")
print(f"设备名: {loader.device_info.device_name}")
print(f"启动参数数量: {len(loader.startup_params)}")
与扫描流程的关系

EsiLoader.load() 只解析文件,不依赖总线状态;CoE 对象字典目录读取时优先用 slave.esi 已加载的 ESI 树。PDO 配置 / DC 启用 / 邮箱协议建立所用的 ESI 绑定由 DLL 自动完成(ESI 经 set_esi_file / set_esi_files 载入,build() 扫站后 EcEsi_AutoMatchAll 匹配)。

ESI 版本匹配​

match_revision()​

from darra_ethercat.utils.esi import match_revision, ESIRevisionCheckStrategy

def match_revision(actual: int, expected: int,
strategy: ESIRevisionCheckStrategy) -> bool

根据指定策略判断从站实际版本号与 ESI 期望版本号是否匹配(模块级函数)。

ESIRevisionCheckStrategy 枚举:

class ESIRevisionCheckStrategy(IntEnum):
NONE = 0 # 不检查版本号
EQ = 1 # 完全匹配
EQ_OR_G = 2 # 等于或大于
LW_EQ = 3 # 低16位匹配
HW_EQ = 4 # 高16位匹配
LW_EQ_OR_G = 5 # 低16位等于或大于
HW_EQ_OR_G = 6 # 高16位等于或大于

EEPROM CRC 工具​

calculate_eeprom_crc()​

def calculate_eeprom_crc(data: bytes, length: int) -> int

计算 EEPROM 数据的 CRC-8 校验值。使用 ETG.1000.6 / ETG.2010 定义的 CRC-8 算法(多项式 0x07,初始值 0xFF)。

参数:

  • data (bytes) — EEPROM 数据
  • length (int) — 参与计算的数据长度

返回值:

  • int — CRC-8 校验值

示例:

from darra_ethercat.utils.esi import calculate_eeprom_crc

eeprom_data = slave.read_eeprom(0, 16)
crc = calculate_eeprom_crc(eeprom_data, 14) # 前 14 字节参与 CRC
print(f"CRC: 0x{crc:02X}")

validate_eeprom_crc()​

def validate_eeprom_crc(eeprom_data: bytes) -> bool

校验 EEPROM 数据的 CRC 是否正确。自动读取数据中的 CRC 字段并与计算值比较。

参数:

  • eeprom_data (bytes) — 完整 EEPROM 数据(至少 15 字节)

返回值:

  • bool — CRC 校验通过返回 True

示例:

from darra_ethercat.utils.esi import validate_eeprom_crc

eeprom = slave.read_eeprom(0, 128)
if validate_eeprom_crc(eeprom):
print("EEPROM CRC 校验通过")
else:
print("EEPROM CRC 校验失败,数据可能已损坏")

完整示例​

应用启动时预加载 ESI​

from darra_ethercat.utils.esi import EsiManager

print("正在加载ESI文件...")

EsiManager.preload(lambda cur, total, name:
print(f"\r进度: {cur * 100 // total}% ({cur}/{total}) - {name}", end=""))

print(f"\n成功加载 {EsiManager.loaded_file_count()} 个ESI文件")

从站识别 (基础属性)​

from darra_ethercat import EtherCATMaster, EcState
from darra_ethercat.utils.esi import EsiManager

# 预加载 ESI
EsiManager.preload()

with EtherCATMaster() as master:
master.set_eni(r"C:\config.deni")
master.set_network(r"\Device\NPF_{GUID}")
master.set_state(EcState.OP)

# 遍历从站,读取从站基础标识属性
for slave in master.slaves:
print(f"[{slave.slave_num}] {slave.name} "
f"VID=0x{slave.vendor_id:08X} PID=0x{slave.product_id:08X} "
f"Rev=0x{slave.rev_id:08X}")

缓存管理​

from darra_ethercat.utils.esi import EsiManager

# 检查特定文件是否已加载
if EsiManager.is_file_loaded("MyVendor_EL7211.xml"):
print("自定义设备 ESI 已加载")

# 从缓存中移除特定文件(例如更新 ESI 后重新加载)
EsiManager.remove_from_cache("MyVendor_EL7211.xml")
EsiManager.load_path(r"C:\ESI\Updated")

# 完全清除并重新加载
EsiManager.clear()
EsiManager.load_path(r"C:\ESI")
print(f"重新加载完成: {EsiManager.loaded_file_count()} 个文件")

自定义设备支持​

import os
from darra_ethercat.utils.esi import EsiManager

def load_custom_devices(custom_esi_path: str):
# 加载标准 ESI
EsiManager.preload()

# 增量加载自定义设备 ESI
if os.path.isdir(custom_esi_path):
EsiManager.load_path(custom_esi_path)
print("自定义设备ESI已加载")

ESI 诊断工具​

from darra_ethercat.utils.esi import EsiManager

def generate_esi_report():
print("=== ESI诊断报告 ===")
print()

# 基本统计
file_count = EsiManager.loaded_file_count()
print(f"已加载文件数: {file_count}")
print(f"默认路径: {EsiManager.default_path()}")
print()

# 检查预加载状态
if EsiManager.is_preloaded():
print("ESI 已预加载")
else:
print("ESI 未预加载")

ESI 管理器封装​

from darra_ethercat.utils.esi import EsiManager
import os

class ESIManagerWrapper:
_initialized = False

@classmethod
def initialize(cls, custom_path: str = None):
if cls._initialized:
return

print("初始化ESI管理器...")

# 加载默认 ESI 文件
print("加载标准ESI文件...")
EsiManager.preload(lambda cur, total, name:
print(f"\r 进度: {cur * 100 // total}% ({cur}/{total}) - {name}", end=""))

# 加载自定义 ESI 文件
if custom_path and os.path.isdir(custom_path):
print(f"\n加载自定义ESI文件: {custom_path}")
EsiManager.load_path(custom_path)

cls._initialized = True
print(f"\nESI初始化完成,共加载 {EsiManager.loaded_file_count()} 个文件")

@classmethod
def reload(cls):
print("重新加载ESI文件...")
EsiManager.clear()
cls._initialized = False
cls.initialize()

总线配置加载​

用户加载 ENI / DENI / JSON 只走 master.set_eni() 或 master.load_config_json()。两者都把内容交给 DLL LoadConfigJson(XML 或 JSON)。

包 __all__ 不再导出 MasterXMLConfiguration / load_xml_configuration。save_xml / apply_xml / SaveXML 不是产品 API(XML 读写仅 GUI / PLC 内部路径)。保存配置 / 启动快照在主站自愈窗口内采用有限等待(秒级上限,短轮询),超时返回错误,不会长时间挂起。

导出 DENI

导出运行时配置为 DENI 文件由 Darra 主界面和 PLC 中间层提供,不通过 SDK 对外开放。

注意事项​

性能优化

ESI 文件加载可能需要几秒钟。建议在应用启动时使用 preload() 预加载,避免运行时延迟。

文件路径

运行时 ESI 走 master.set_esi_file / set_esi_files → DLL EcEsi_LoadFile / EcEsi_LoadDirectory。Windows 路径按 mbcs(系统 ANSI 代码页)传入 native,不能 UTF-8。EsiManager 缓存加载跳过无效文件,不影响其他文件。

增量加载

EsiManager.load_path() 自动跳过已加载文件,等同于增量加载,可以避免重复加载相同文件,提高效率。

相关功能

ESI 设备信息在主站构造(set_esi_file / set_esi_files)和从站管理中使用。总线配置加载见本页 总线配置加载。