- Rewrite generateDeviceManifest() to read DESC_IP sheet from
PLC Data Generator/{PROJECT}/{MCM}_DESC_IP_MERGED.xlsx
- Rewrite generateProjectManifest() to discover projects from same files
- Key devices-manifest by {PROJECT}_{MCM} to avoid cross-project collisions
- Add fill.paint binding for standalone photoeye path elements
- Add fill.paint binding for button circle sub-elements
- Add s_str_ prefix to path/rect element names for consistency
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SCADA Device Layout Tool
Visual layout editor for designing conveyor system SCADA views. Generates Ignition Perspective views with full tag bindings, deployable directly to an Ignition gateway.
Built with SvelteKit + Svelte 5 + TypeScript + HTML5 Canvas.
What It Does
- Drag-and-drop placement of conveyor system devices (VFDs, photoeyes, EPCs, sensors, controls, etc.) onto a canvas
- Trace PDF blueprints as background reference while placing devices
- Assign device IDs from Excel manifests to placed symbols
- Export production-ready Ignition Perspective
view.jsonwith tag bindings (color/state/priority), pan/zoom controls, tooltips, and alarm filters - Deploy directly to the Ignition gateway filesystem with automatic project rescan
Data Sources
Excel Device Manifests
svelte-app/static/projectes/{PROJECT}/excel/*.xlsx
Each file represents one MCM (Module Control Module) with device IO data. Parsed at build time (Vite plugin) into devices-manifest.json — device IDs mapped to symbol types, organized by MCM.
PDF Blueprints
svelte-app/static/projectes/{PROJECT}/pdf/*.pdf
Conveyor layout drawings rendered as canvas background for accurate device tracing.
SVG Symbols
svelte-app/static/symbols/*.svg
Vector graphics for each device type. Rendered programmatically on canvas for consistent stroke width at any size.
Ignition Tag Tree
Tag paths follow the Ignition tag provider hierarchy:
System/{MCM}/
VFD/APF/ - Variable Frequency Drives
Station/Emergency_Pull_Cord/ - EPCs
Station/Start/ - Start Buttons (S)
Station/Start_Stop/ - Start/Stop Buttons (SS)
Station/Jam_Reset/ - Jam Reset Buttons (JR)
Station/Jam_Reset_Chute_Bank/ - Chute Enable Buttons
Sensor/Tracking/ - Tracking Photoeyes (TPE)
Sensor/Laser/ - Laser Photoeyes (LPE)
Sensor/Jam/ - Jam Photoeyes (JPE)
Sensor/Full/ - Full Photoeyes (FPE)
Sensor/Pressure/ - Pressure Sensors (PS)
Network_Node/FIO/ - Field I/O Modules (FIOM)
Network_Node/HUB/ - Hub Modules (FIOH)
Network_Node/SIO/ - Serial I/O Modules
Network_Node/DPM/ - Distribution Power Modules
Beacon/ - Beacon Lights (BCN)
Solenoid/ - Solenoid Valves (SOL)
Diverter/ - Diverter Limit Switches
PDP/ - Power Distribution Panels
Chute/Conveyance/ - Chute Conveyors
Tipper/ - Tipper Conveyors
Extendo/ - Extendo Conveyors
How It Works
1. Project Setup
Select a project and MCM from the toolbar. Device manifest and PDF blueprint load automatically.
2. Layout Design
- Drag symbols from the palette onto the canvas
- Resize conveyors, spurs, and curves by dragging handles
- Rotate (R), mirror (M), snap to grid
- Shift+drag constrains to horizontal/vertical
- Mouse wheel to zoom, middle-click to pan
3. Device Assignment
- Drag device IDs from the right dock onto placed symbols
- IDs match by conveyance family (conveyor IDs work on spurs, curves, inductions, extendos)
- Labels render inside conveyance shapes as bold text (parsed:
UL17_22_VFD->UL / 17-22)
4. Export Options
| Button | Output | Description |
|---|---|---|
| SVG | {MCM}_Detailed_View.svg |
Standard SVG with shapes, labels, embedded layout data |
| JSON | {MCM}_layout.json |
Layout data for backup/restore |
| SCADA | {MCM}_Detailed_View.json |
Ignition ia.shapes.svg component JSON |
| Deploy | Writes to Ignition | view.json + resource.json to gateway project directory |
5. Ignition View Structure
Generated view.json includes:
- Pan/zoom container — mouse wheel zoom, pointer-move panning, double-click reset
- SVG component — all device shapes with per-element tag bindings:
color— indirect tag binding to[{fc}_SCADA_TAG_PROVIDER]{tagpath}/Colorwith 21-color state mapstate— indirect tag binding to[{fc}_SCADA_TAG_PROVIDER]{tagpath}/Statewith 35-state mappriority— indirect tag binding to[{fc}_SCADA_TAG_PROVIDER]{tagpath}/Priority(5 levels)fill.paint/stroke.paint— dynamic coloring based on device typestyle.display— alarm-based visibility filters (show_fio,show_pes,show_beacons, etc.)
- Markdown tooltip — hover tooltips with device state/priority, glow effects on active elements
- Zoom controls — reset, zoom in/out, percentage dropdown
- Message handler —
focusDevicefor external navigation
Device-Specific Bindings
| Device Type | Fill Binding | Notes |
|---|---|---|
| Conveyor/Chute/Spur/Induction | elements[0].fill.paint + text contrast |
Background + text color |
| DPM | elements[0].fill.paint only |
First triangle path |
| MCM | elements[1].fill.paint only |
Second triangle path |
| EPC | elements[0].stroke.paint + elements[1].elements[1].fill.paint |
Polyline stroke + icon inner |
| Buttons (JR/S/SS) | Text fill.paint only |
Background keeps static color |
| Photoeye/FIO/Beacon/etc. | elements[0].fill.paint |
Standard fill |
Setup & Run
cd svelte-app
npm install
npm run dev # Dev server at http://localhost:5173
Gateway Integration
Deploy Target
Files are written to:
C:/Program Files/Inductive Automation/Ignition/data/projects/{PROJECT}/
com.inductiveautomation.perspective/views/DetailedView/{MCM}/
view.json # Full Perspective view with bindings
resource.json # Resource metadata with SHA-256 signature
Automatic Project Rescan
A gateway timer script (5s interval) watches for .deploy-pending trigger files and calls IgnitionGateway.get().getProjectManager().requestScan() so the Designer picks up new views without a gateway restart.
Gateway Timer Script setup:
import os
basePath = "C:/Program Files/Inductive Automation/Ignition/data/projects"
projects = ["CDW5_SCADA"]
for proj in projects:
viewsDir = os.path.join(basePath, proj, "com.inductiveautomation.perspective", "views")
if not os.path.exists(viewsDir):
continue
for root, dirs, files in os.walk(viewsDir):
if ".deploy-pending" in files:
trigger = os.path.join(root, ".deploy-pending")
os.remove(trigger)
from com.inductiveautomation.ignition.gateway import IgnitionGateway
IgnitionGateway.get().getProjectManager().requestScan()
system.util.getLogger("SCADADeploy").info("Deployed view: " + root)
Project Structure
scada_device_layout/
svelte-app/
src/
lib/
canvas/
renderer.ts # Canvas draw loop, symbol rendering
interactions.ts # Mouse/keyboard handlers, drag-and-drop
hit-testing.ts # Shape-aware click detection
collision.ts # Spacing violation detection
render-theme.ts # Visual constants (colors, sizes)
grid-snap.ts # Grid snapping
distance.ts # Geometry helpers
geometry.ts # Oriented box math
stores/
layout.svelte.ts # Central state (symbols, selection, settings)
export.ts # SVG/JSON/SCADA export, Ignition deploy
ignition-view.ts # Full view.json generator with all bindings
symbols.ts # Symbol definitions, type checks, image cache
symbol-config.ts # Geometry constants (EPC, induction, photoeye, etc.)
label-utils.ts # Label parsing (UL17_22_VFD -> UL / 17-22)
serialization.ts # Save/load with size migration
pdf.ts # PDF background rendering
projects.ts # Project/MCM discovery
types.ts # TypeScript interfaces
components/
Canvas.svelte # Main canvas + PDF + context menu
Toolbar.svelte # Left sidebar (project, settings, palette, Ignition deploy)
Palette.svelte # Symbol picker with groups
DeviceDock.svelte # Right sidebar (device ID assignment)
static/
symbols/ # SVG files for each device type
projectes/ # Project data (Excel, PDF, manifests)
vite.config.ts # Vite plugins: manifest gen, Excel parser, deploy endpoint
Device Classification (from Excel)
| Suffix | Symbol | Tag Path |
|---|---|---|
| VFD | Conveyor | VFD/APF |
| EPC | EPC | Station/Emergency_Pull_Cord |
| TPE | Photoeye | Sensor/Tracking |
| LPE | Photoeye | Sensor/Laser |
| JPE | Photoeye | Sensor/Jam |
| FPE | Photoeye | Sensor/Full |
| PS | Pressure Sensor | Sensor/Pressure |
| BDS, TS | Photoeye | Sensor/Tracking |
| JR_PB | Jam Reset | Station/Jam_Reset |
| S_PB | Start | Station/Start |
| SS_SPB/STPB | Start Stop | Station/Start_Stop |
| EN_PB | Chute Enable | Station/Jam_Reset_Chute_Bank |
| BCN | Beacon | Beacon |
| SOL | Solenoid | Solenoid |
| DIV_LS | Diverter | Diverter |
| FIOM | FIO/SIO/FIOH | Network_Node/FIO |
| FIOH | FIO/SIO/FIOH | Network_Node/HUB |
| SIO | FIO/SIO/FIOH | Network_Node/SIO |
| DPM | DPM | Network_Node/DPM |
| PDP | PDP | PDP |
Note: _PB/_SPB/_STPB suffixes are stripped from tag paths to match PLC naming.
Skipped: ENSH/ENW (encoders), VFD_DISC (disconnect), _LT (lights), EPC 2nd channel, ESTOP, SCALE, STO, PRX, LRPE.