PLC Conversion Runner

HTTP service that converts Allen-Bradley ACD files to L5X format (and other PLC formats to analyzable outputs). Wraps the proven l5xgit conversion engine with a REST API, job queue, and scheduled fleet scanning.


Conversion-only as of 2026-06-23 (ADR-001)

The runner is now conversion-only (ACD→L5X + L5X git history). The analysis pipeline (parse/scorecard/summary) and all archive writes were removed — PLC analysis is owned solely by the PLC Fleet Archive, which is the single fleet analyzer. Sections below describing an analysis pipeline / /api/pipeline endpoints are historical.

Overview

The PLC Conversion Runner is a .NET 8 Windows Service deployed on PS-PLCRunner (10.150.141.3). It provides on-demand and scheduled ACD-to-L5X conversion for the PSI fleet, with a Python fallback for projects where the Rockwell SDK cannot be used. The L5X it writes to K: is what the PLC Fleet Archive nightly job analyzes.

PropertyValue
URLhttp://ps-plcrunner:3200
SourceProgressiveSurface/psi-plc-runner
Dev LocationC:\git\psi-plc-runner\
Runtime.NET 8 (framework-dependent)
DeployC:\Services\PSI.PlcRunner\ on PS-PLCRunner
Port3200 (TCP)
Service ManagerNSSM 2.24
Auto-deployPush to master triggers GitHub Actions on [self-hosted, ps-plcrunner]

Architecture

┌──────────────────────────────────────────────────────────────────────┐
│                          MCP Server (PS-PROXY:3100)                  │
│   get_plc_analysis tool                                              │
│     1. Check fleet archive JSON                                      │
│     2. Check existing L5X on K: drive                                │
│     3. Call PS-PLCRunner:3200/api/convert  ◄── NEW                   │
│     4. Fall back to acd_analyzer.py                                  │
└────────────────────┬─────────────────────────────────────────────────┘
                     │ HTTP
                     ▼
┌──────────────────────────────────────────────────────────────────────┐
│  PSI.PlcRunner  (PS-PLCRunner:3200)                                  │
│                                                                      │
│  REST API:                                                           │
│    POST /api/convert   - Queue a conversion (by job# or file path)   │
│    GET  /api/convert/id - Check job status                           │
│    GET  /api/jobs       - List recent jobs                           │
│    POST /api/scan       - Trigger fleet scan                         │
│    GET  /api/scan/status - Last scan report                          │
│    GET  /api/health     - Health + converter availability            │
│                                                                      │
│  Background Services:                                                │
│    ConversionWorker  - Dequeues + runs conversions (serial)          │
│    FleetScanner      - Nightly scan (2 AM) + on-demand               │
│                                                                      │
│  Converters (priority order):                                        │
│    1. l5xgit.exe acd2l5x  (Rockwell SDK - high fidelity L5X)        │
│    2. acd_analyzer.py      (Python fallback - JSON analysis)         │
└────────┬───────────────────────────┬─────────────────────────────────┘
         │                           │
         ▼                           ▼
  C:\Tools\l5xgit\l5xgit.exe   Python 3.11 + acd-tools
  (ra-logix-designer-vcs-        (direct ACD binary extraction)
   custom-tools, Rockwell SDK)
         │
         ▼
  K:\PROJECT\{job}\sw\PLC\l5x\{filename}.L5X
  (consumed by l5x_parser.js, MCP Server, Fleet Archive)

Conversion Pipeline

The runner does NOT embed the Rockwell Logix Designer SDK directly. Instead, it shells out to l5xgit.exe from the ra-logix-designer-vcs-custom-tools project. This is the same proven conversion engine used by the PowerShell batch scripts.

POST /api/convert { "jobNumber": "2399" }
  1. FileDiscovery scans K:\PROJECT\2399\sw\{PLC, CompactLogix, ...}
  2. Selects primary ACD file (filters backups, prefers Proj{job}.ACD)
  3. Checks if L5X already exists and is newer → returns Skipped
  4. Queues conversion job (Channel<T>, FIFO)
  5. ConversionWorker picks up job:
     a. Try: l5xgit.exe acd2l5x --acd <input> --l5x <output>
     b. Fallback: python acd_analyzer.py <input> <job>
  6. L5X written to K:\PROJECT\2399\sw\PLC\l5x\
  7. Returns 202 Accepted with job ID for polling

Why l5xgit instead of direct SDK?

  • Proven: Already tested converting v34 ACD files across the fleet
  • Self-contained: Carries its own FtspAdapter.exe, gRPC bindings, and Rockwell DLLs
  • Maintained: Upstream Rockwell open-source project with PSI customizations
  • Separation of concerns: psi-plc-runner focuses on HTTP service / queue / scanning

API Reference

POST /api/convert

Queue a conversion job.

{ "jobNumber": "2399" }
// or
{ "filePath": "K:\\PROJECT\\2399\\sw\\PLC\\Proj2399.ACD" }
// or force re-conversion
{ "jobNumber": "2399", "force": true }

Returns 202 Accepted:

{ "id": "abc123", "status": "Queued", "jobNumber": "2399", "inputPath": "..." }

GET /api/convert/{id}

Poll job status. Status values: Queued, Running, Completed, Failed, Skipped.

GET /api/jobs?count=100&status=completed

List recent conversion jobs with optional status filter.

POST /api/scan

Trigger fleet scan immediately (normally runs at 2 AM daily).

GET /api/scan/status

Last scan report: total projects, converted, pending, failed.

GET /api/health

{
  "status": "healthy",
  "service": "PSI.PlcRunner",
  "version": "1.1.0",
  "converters": {
    "l5xgit": { "available": true, "path": "C:\\Tools\\l5xgit\\l5xgit.exe" },
    "pythonFallback": { "available": true }
  }
}

Configuration

appsettings.json:

{
  "PlcRunner": {
    "ProjectRoot": "\\\\ad.ptihome.com\\DFS\\LDS\\PROJECT",
    "L5xSubfolder": "sw/PLC/l5x",
    "L5xGitPath": "C:\\Tools\\l5xgit\\l5xgit.exe",
    "PlcSubfolders": ["sw/PLC", "sw", "sw/CompactLogix", "sw/MainPlc", ...],
    "ConversionTimeoutSeconds": 300,
    "MaxQueueSize": 500,
    "ScanSchedule": "0 2 * * *",
    "Python": {
      "Executable": "C:\\Python311\\python.exe",
      "AcdAnalyzer": "C:\\Services\\PSI.PlcRunner\\acd_analyzer.py"
    }
  }
}

Prerequisites on PS-PLCRunner

ComponentPathPurpose
.NET 8 SDKC:\Program Files\dotnet\Build + run the service
Studio 5000v28/v30/v31/v34 installedRequired by l5xgit at runtime
Logix Designer SDKC:\Users\Public\Documents\Studio 5000\Logix Designer SDK\Required to build l5xgit
l5xgit.exeC:\Tools\l5xgit\ACD-to-L5X conversion engine
ra-logix-designer-vcs-custom-toolsC:\git\ra-logix-designer-vcs-custom-tools\l5xgit source (built during deploy)
GHA runner[self-hosted, ps-plcrunner]Auto-deploy from GHE
Python 3.11C:\Python311\Fallback ACD analyzer (optional)

Version Compatibility

The Rockwell SDK requires the matching Studio 5000 version to open each ACD. See version distribution for details.

Studio 5000 VersionCoverage
v34 only (current)90 projects (18%)
+ v20268 projects (55%)
+ all versions487 projects (100%)

Next step: Install Studio 5000 v20 on PS-PLCRunner to unlock 178 more projects.