Work / eplanbridge
eplanbridge: EPLAN Pro Panel automation through the EPLAN API in C#
Drive EPLAN Pro Panel 2022.0.3 from outside the application — and build a 6-axis robot-arm control schematic with it.
What is it made of?
csharp · eplan · eplan-pro-panel · industrial-automation · mcp
Source on GitHub ↗ · Need one like it? →
How does it work?
Drive EPLAN Pro Panel 2022.0.3 from outside the application — and build a 6-axis robot-arm control schematic with it.
A programmable control surface for EPLAN Pro Panel, shaped like the existing gxbridge MCP server, plus the project it was built to produce: RoboArm_6DOF_FX5U, a 20-page schematic for an FX5U-controlled 6-axis arm — 273 symbols and 129 connections, all placed by script.
Read these first
Each records what was measured and what is still a guess. Read the relevant one before changing anything.
Why
EPLAN has no supported way to build a schematic in bulk from outside the GUI. Drawing 273 symbols and wiring them by hand is slow and unrepeatable; doing it from a script makes the drawing a build artefact that can be rebuilt, diffed, and corrected. This project works out what that takes and records the parts that are not obvious — chiefly that placement alone connects nothing.
Why it is built this way
EPLAN's remoting channel exposes exactly one useful verb: ExecuteAction. The interesting API — DataModel, DataModel.E3D, HEServices — is in-process only. The bridge between them is EPLAN's ExecuteScript action.
But EPLAN's script compiler carries no reference to Eplan.EplApi.DataModelu.dll. Any compile-time mention of that namespace fails the whole script, and a failed compile is reported as Succeed=False with an empty message — no error text anywhere. That single fact dictates the design.
PowerShell / MCP server (out of process, net48)
| EplanRemoteClient.ExecuteAction
v
ExecuteScript /ScriptFile:EplanBridgeStub.cs
| (the ONLY reflection in the system)
v
EplanBridge.Core.dll (in process, typed C#, full API access)EplanBridgeStub.cs names no EPLAN API type, so it always compiles. It loads EplanBridge.Core.dll and calls Bridge.Invoke(command, argument). Everything below that boundary is ordinary typed C# — which means the compiler checks the API usage instead of mistakes surfacing at runtime.
The stub loads the DLL from a byte array, not Assembly.LoadFrom. That leaves the file unlocked, so EplanBridge.Core can be rebuilt without restarting EPLAN. Verified working.
Layout
Build
cd src\EplanBridge.Core
dotnet build -c Release -o ..\..\binTargets net48 because the EPLAN API is .NET Framework. The only SDK installed is .NET 10, which cannot load Framework assemblies in-process — but it builds net48 fine, since the targeting pack is present. EPLAN references use false so its DLLs are never copied; the process already has them loaded.
Use
.\tools\Invoke-EplanBridge.ps1 -Command ping
.\tools\Invoke-EplanBridge.ps1 -Command project.info `
-Argument 'C:\Users\Kishor\Tovex-Work\eplan-propanel-bridge\projects\RoboArm_6DOF_FX5U.elk'-Port defaults to 57315 (the dedicated instance). Start a dedicated instance with an explicit port rather than an ephemeral one:
Eplan.exe /Variant:"Pro Panel" EplanServer /EPLANSERVERPORT:<port>Verify
With a dedicated EPLAN instance running on port 57315:
.\tools\Get-ProjectAudit.ps1Success is the last three lines reading exactly:
total functions = 273
total connections = 129
untagged (=+) = 273and every page =RA1+CAB/2 through /17 reporting a non-zero function count. The audit reopens the project from disk, so a passing run is also the persistence proof — there is no Save in this API, only Project.Close().
untagged = 273 is the expected value, not a failure to investigate: device numbering does not work yet (FINDINGS §3). It will drop to 0 when it does.
Parts allocation
.\tools\Invoke-EplanBridge.ps1 -Command project.parts `
-Argument 'C:\Users\Kishor\Tovex-Work\eplan-propanel-bridge\projects\RoboArm_6DOF_FX5U.elk'Success is withoutPart reading 0:
{"totalFunctions":169,"withPart":144,"withoutPart":0,
"cannotCarryArticle":25,"distinctParts":9}totalFunctions is 169 here and 273 in the audit above, and both are correct. The audit sums 16 page-filtered queries; this is one project-wide query, and GetFunctions(null) does not return the 104 PLC connection points. Do not "fix" either number to match the other.
Rebuild from scratch and re-verify
.\tools\Build-RoboArmSchematic.ps1
.\tools\Invoke-EplanAction.ps1 -Actions 'generate /TYPE:CONNECTIONS /PROJECTNAME:"C:\Users\Kishor\Tovex-Work\eplan-propanel-bridge\projects\RoboArm_6DOF_FX5U.elk" /REBUILDALLCONNECTIONS:1'
.\tools\Invoke-EplanBridge.ps1 -Command project.close -Argument 'C:\Users\Kishor\Tovex-Work\eplan-propanel-bridge\projects\RoboArm_6DOF_FX5U.elk'
.\tools\Get-ProjectAudit.ps1Commands
Page types accepted by page.create: Circuit, TitlePage, TableOfContents, PLCDiagram, PLCCardOverview, TerminalDiagram, PanelLayout, Overview, and the rest of DocumentTypeManager.DocumentType.
Rules for adding a command
- One command, one verb, one effect. Never "create or update".
- Return JSON always. Never throw across the boundary; never show a dialog — a modal
dialog blocks every later remote call, since EPLAN only services remote calls when idle.
- Data-model writes must be wrapped in a LockingStep, or EPLAN throws
NoLockingStepException (S063110).
- A project already open cannot be re-opened. Use GetProject first (returns null
when not open), then OpenProject.
- State in the command's docs what it cannot do.
API gotchas found the hard way
There is no Save. The only persistence trigger is Project.Close(). Verified: after creating 19 pages, Page.eod was still 1,134 bytes at its original timestamp; after project.close it became 22,680 bytes, and reopening from disk (wasAlreadyOpen:false) returned all 20 pages. Never report a write as done before closing — an in-memory read-back proves nothing.
Placing symbols does not connect them. EPLAN auto-connects connection points that share an X coordinate and face each other, but only when generate /TYPE:CONNECTIONS /REBUILDALLCONNECTIONS:1 is run. Place → generate → close. Skip the middle step and you get a drawing that looks right and is electrically empty.
Place symbols with SymbolVariant.Create(page), never Function.Create. Function.Create only builds generic Functions. For a symbol backed by a specialised class (terminals, cables, PLC boxes) it creates the object and then throws NotImplementedException — leaving a half-initialised object on the page while reporting failure. Observed exactly: four terminals reported FAIL yet all appeared in page.contents. SymbolVariant.Create returns the correct subclass; set SymbolReference.Location afterwards.
Device tags cannot be set as a property. FUNC_DEVICETAG_FULL throws NotImplementedException; NameParts has no FUNC_DEVICETAG_MAINNAME; there are no IDENTLETTER/COUNTER name-part properties on FunctionBasePropertyList. EPLAN assigns device tags with its own renumber action — place first, number after.
The page description property is PAGE_NOMINATIOMN — EPLAN's own misspelling, documented as "Page description # 11011". There is no PAGE_DESCRIPTION. PAGE_SUPPLEMENTARYFIELD is a different, indexed property (11901) and is the wrong choice.
Read the full README on GitHub →
What do people ask about it?
Can EPLAN Pro Panel be automated from outside the application?
Yes, with one catch: EPLAN's remoting channel exposes a single useful verb, ExecuteAction, and the real API — DataModel, DataModel.E3D, HEServices — is in-process only. eplanbridge crosses that gap through EPLAN scripting, the ExecuteScript action: an out-of-process PowerShell or MCP server on .NET Framework 4.8 sends the action, a stub script runs inside EPLAN, and the stub loads EplanBridge.Core.dll, typed C# with full access to the API.
Which EPLAN version does it target?
EPLAN Pro Panel 2022.0.3. The API behaviour that cost time to find — a failed script compile reported as Succeed=False with an empty message, the missing reference to Eplan.EplApi.DataModelu.dll — is recorded in FINDINGS.md, and the dead ends in ATTEMPTS.md, so neither is repeated.
What did it actually build?
RoboArm_6DOF_FX5U: a 20-page control schematic for a 6-axis robot arm on a Mitsubishi FX5U — 273 symbols and 129 connections, all placed by script, so the drawing is a build artefact that can be rebuilt from scratch, diffed and re-verified.
Why does placing symbols by script connect nothing?
Because placement alone connects nothing in EPLAN: a placed symbol has no connections until the generate step runs, so the sequence is place, generate, close, and the pin geometry has to be right first. That is the main finding the project records.
Is it an MCP server like GXBridge?
It is shaped like the GXBridge MCP server — a programmable control surface for an engineering tool — with a PowerShell front as well, so an AI agent or a plain script can drive EPLAN the same way.
What else did I build?
GXBridge-MCP
Control Mitsubishi GX Works3 and your PLC with AI — an MCP server for any agent GX Works3 · Industrial Automation
tovex-cli-showcase
tovex-cli: command-line control of Siemens TIA Portal and live S7 PLCs, built for AI agents. Public overview; source is private.
picw-overview
Replacing a Mitsubishi PLC with a Raspberry Pi 4B as master of a dynamic checkweigher (Thames Side T16 / XT1-SO)