I’d like to ask: is it possible to turn the PC into an adapter? What I’m trying to do is make my PC act as an adapter so that the PLC can continuously read the values I want to respond with. I’ve already imported the corresponding EDS file, but it still doesn’t work. I’m stuck at the part where I need to set up the server. Below is my code. mycode is from copliot.
import threading
import time
import logging
# 匯入 cpppo 的 EIP Server 和數據模型
from cpppo.server.enip import server
from cpppo.server.enip.poll import poll
from cpppo.server.enip.get_attribute import attribute_name
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
# --- 參數設定 ---
PC_IP_ADDRESS = '172.16.0.201' # 替換為您的 PC 實際 IP 地址
# PLC (Scanner) 期望讀寫的數據模型 (Assembly Object)
# 使用 DINT 是因為 INT (16位) 在許多 EIP 實現中容易被忽略,DINT (32位) 更通用。
TAG_NAME = "My_EIP_Data"
DATA_TYPE = "DINT"
ARRAY_LENGTH = 10
DINT_SIZE = 4 # 每個 DINT 佔 4 bytes
# 總 I/O 數據長度: 10 * 4 = 40 bytes
# --- 核心邏輯 ---
def run_eip_adapter():
# 1. 定義 Server 的數據字典 (這是 PLC 會讀寫的 I/O 記憶體)
parameters = {
TAG_NAME: [0] * ARRAY_LENGTH # 初始值
}
logging.info(f"🟢 EIP Adapter 啟動中...")
logging.info(f" - PC IP 地址: {PC_IP_ADDRESS}")
logging.info(f" - 數據模型: {TAG_NAME}={DATA_TYPE}[{ARRAY_LENGTH}] ({ARRAY_LENGTH * DINT_SIZE} bytes)")
logging.info(f" - 監聽 TCP/44818 (等待 PLC 的 Forward_Open 請求)...")
# 2. 啟動 EIP Server
try:
# 創建 EIP Server 實例
srv = server.server(
bindings=[PC_IP_ADDRESS], # 綁定到特定 IP,確保監聽正確
parameters=parameters,
timeout=0.1, # 短暫超時,讓主迴圈可以更新數據
workers=1 # 使用單一工作執行緒
)
logging.info("✨ EIP Adapter 成功運行!請切換到 PLC 配置。")
counter = 0
while True:
# 讓 Server 運行一小段時間 (處理連線請求和數據交換)
srv.loop_iter()
# --- 模擬數據更新 (用於測試 PLC 是否成功讀到變化) ---
# 讓第一個值不斷變化
parameters[TAG_NAME][0] = counter
# 檢查是否有來自 PLC 的寫入 (如果 PLC 配置為寫入,值會變動)
plc_write_value = parameters[TAG_NAME][1]
counter += 1
if counter > 65535:
counter = 0
# 顯示當前狀態和 PLC 寫入的值
print(f"\r[Server 狀態]: Counter={parameters[TAG_NAME][0]} | PLC寫入值: {plc_write_value} | 等待連線...", end='', flush=True)
time.sleep(0.5)
except KeyboardInterrupt:
logging.info("\n程式被使用者中斷,正在停止 EIP Adapter...")
except Exception as e:
logging.error(f"❌ 發生致命錯誤: {e}")
finally:
if 'srv' in locals() and srv:
srv.stop()
logging.info("Adapter 已停止。")
if __name__ == "__main__":
run_eip_adapter()
Here is the content of my EDS file.
$ EZ-EDS Version 3.36.1.20241010 Generated Electronic Data Sheet
[File]
DescText = "EDS file for Simple IO Device";
CreateDate = 09-24-2025;
CreateTime = 12:00:00;
ModDate = 09-24-2025;
ModTime = 12:00:00;
Revision = 1.00;
HomeURL = "https://github.com/";
[Device]
VendCode = 1234;
VendName = "test";
ProdType = 43;
ProdTypeStr = "Generic Device";
ProdCode = 1;
MajRev = 1;
MinRev = 1;
ProdName = "Simple IO Device";
Catalog = "SimpleIO";
[Device Classification]
Class1 = EtherNetIP;
[Params]
Param1 =
0, $ reserved, shall equal 0
,, $ Link Path Size, Link Path
0x0000, $ Descriptor
0xC6, $ Data Type (USINT)
1, $ Data Size in bytes
"Write Byte", $ name
"", $ units
"Write a single byte to the device.", $ help string
0,255,0, $ min, max, default data values
,,,, $ mult, div, base, offset scaling
,,,, $ mult, div, base, offset links
; $ decimal places
Param2 =
0, $ reserved, shall equal 0
,, $ Link Path Size, Link Path
0x0030, $ Descriptor
0xC6, $ Data Type (USINT)
1, $ Data Size in bytes
"Read Byte", $ name
"", $ units
"Read a single byte from the device.", $ help string
0,255,0, $ min, max, default data values
,,,, $ mult, div, base, offset scaling
,,,, $ mult, div, base, offset links
; $ decimal places
Param10 =
0, $ reserved, shall equal 0
,, $ Link Path Size, Link Path
0x0000, $ Descriptor
0xC8, $ Data Type
4, $ Data Size in bytes
"RPI", $ name
"us", $ units
"Sets the RPI.", $ help string
1000,3200000,10000, $ min, max, default data values
,,,, $ mult, div, base, offset scaling
,,,, $ mult, div, base, offset links
; $ decimal places
[Assembly]
Revision = 2;
Object_Name = "Assembly Object";
Object_Class_Code = 0x04;
MaxInst = 2;
Number_Of_Static_Instances = 2;
Max_Number_Of_Dynamic_Instances = 0;
Assem1 =
"Output (O->T)",
"20 04 24 01 30 03",
,
0x0001,
,,
8,Param1;
Assem2 =
"Input (T->O)",
"20 04 24 01 30 03",
,
0x0000,
,,
8,Param2;
[Connection Manager]
Object_Name = "Connection Manager Object";
Object_Class_Code = 0x06;
Connection1 =
0x04010002, $ Connection type flags
0x44640455, $ Connection flags
Param10,,Assem1, $ O->T RPI, size, format
Param10,,Assem2, $ T->O RPI, size, format
,, $ proxy config size, format
,, $ target config size, format
"Exclusive Owner", $ Connection Name
"", $ help string
"20 04 2C 01 2C 02"; $ Path
Connection2 =
0x01010002, $ Connection type flags
0x44640355, $ Connection flags
Param10,0,, $ O->T RPI, size, format
Param10,,Assem2, $ T->O RPI, size, format
,, $ proxy config size, format
,, $ target config size, format
"Listen Only", $ Connection Name
"", $ help string
"20 04 2C C6 2C 02"; $ Path
Connection3 =
0x02010002, $ Connection type flags
0x44640355, $ Connection flags
Param10,0,, $ O->T RPI, size, format
Param10,,Assem2, $ T->O RPI, size, format
,, $ proxy config size, format
,, $ target config size, format
"Input Only", $ Connection Name
"", $ help string
"20 04 2C C5 2C 02"; $ Path
[Capacity]
MaxIOConnections = 2;
MaxMsgConnections = 6;
MaxConsumersPerMcast = 2;
TSpec1 = TxRx, 8, 2000;
[DLR Class]
Revision = 3;
Object_Name = "Device Level Ring Object";
Object_Class_Code = 0x47;
MaxInst = 1;
Number_Of_Static_Instances = 1;
Max_Number_Of_Dynamic_Instances = 0;
Ring_Supervisor_Capable = No;
[TCP/IP Interface Class]
Revision = 4;
Object_Name = "TCP/IP Interface Object";
Object_Class_Code = 0xF5;
MaxInst = 1;
Number_Of_Static_Instances = 1;
Max_Number_Of_Dynamic_Instances = 0;
[Ethernet Link Class]
Revision = 3;
Object_Name = "Ethernet Link Object";
Object_Class_Code = 0xF6;
MaxInst = 1;
Number_Of_Static_Instances = 1;
Max_Number_Of_Dynamic_Instances = 0;
InterfaceLabel1 = "Ethernet Port 1";
InterfaceType1 = 2;
[Identity Class]
Revision = 2;
Object_Name = "Identity Object";
Object_Class_Code = 0x01;
MaxInst = 1;
Number_Of_Static_Instances = 1;
Max_Number_Of_Dynamic_Instances = 0;
[QoS Class]
Revision = 1;
Object_Name = "QoS Object";
Object_Class_Code = 0x48;
MaxInst = 1;
Number_Of_Static_Instances = 1;
Max_Number_Of_Dynamic_Instances = 0;
I’d like to ask: is it possible to turn the PC into an adapter? What I’m trying to do is make my PC act as an adapter so that the PLC can continuously read the values I want to respond with. I’ve already imported the corresponding EDS file, but it still doesn’t work. I’m stuck at the part where I need to set up the server. Below is my code. mycode is from copliot.
Right now, I’m stuck at the line
from cpppo.server.enip import server. It says “cannot import name 'server' from 'cpppo.server.enip'.” How should I resolve this?Here is the content of my EDS file.