Work / eplanbridge

eplanbridge

Tovex Dev project - README

csharp · 2026 · Active

Stack

csharp · eplan · eplan-pro-panel · industrial-automation · mcp

Source on GitHub ↗ · Talk to me →

Readme

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 ..\..\bin

Targets 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.ps1

Success is the last three lines reading exactly:

total functions   = 273
total connections = 129
untagged (=+)     = 273

and 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.ps1

Commands

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

dialog blocks every later remote call, since EPLAN only services remote calls when idle.

NoLockingStepException (S063110).

when not open), then OpenProject.

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 →

More work

View all →

plc-checkweigher

One-command installer for the Mitsubishi PLC check-weigher system. Python · Raspberry Pi · Mitsubishi PLC · PDF Reports · npm CLI

checkweigher

High-speed industrial check-weigher on the edge. Python · Raspberry Pi 4 · XT1000 · T16 Load Cell

Tovex-CRM

Modular CRM platform with real-time dashboards. TypeScript · TypeScript · Modular Architecture · Real-time Dashboards

/ Work / {{ project.name }} {{ project.category }}

{{ project.name }}

{{ project.tagline }}

{{ m }}

Overview

{{ project.description }}

npm i {{ project.npm }}

Highlights

{{ f.n }}

{{ f.text }}

Stack

{{ t }}

Readme

{{ b.s }}

{{ b.s }}

{{ b.s }}

{{ b.s }}
{{ b.s }}
  • {{ it }}

Read the full README on GitHub →

Thoughts about this

More work

View all →

/ Work

Project not found.

That project doesn't exist. Head back to the full list.