Files
framework-ignition-docker/ignition/CLAUDE.md
2026-03-17 13:23:56 -05:00

201 lines
5.9 KiB
Markdown

# Ignition Project Structure — CLAUDE.md
Parent: [../CLAUDE.md](../CLAUDE.md)
## Overview
Ignition 8.3 with Git-native project storage. The project directory is
mounted into the Ignition Docker container and is the single source of truth.
All resources are JSON files on disk.
## Git-Native Project Storage
Ignition 8.3 stores projects as files and directories:
```
ignition/project/
├── project.json ← project metadata
├── com.inductiveautomation.perspective/
│ ├── views/
│ │ └── <view-name>/
│ │ ├── view.json ← view definition
│ │ └── resource.json ← resource metadata
│ └── page-config/
├── com.inductiveautomation.webdev/
│ └── <endpoint-name>/
│ ├── code.py ← Jython 2.7 handler
│ └── resource.json
└── ignition/
├── named-query/
│ └── <query-name>/
│ ├── query.sql
│ └── resource.json
├── script-python/
│ └── <package>/
│ ├── code.py ← project library scripts
│ └── resource.json
└── global-props/
└── props.json
```
## JSON File Rules
All JSON files in the project directory:
1. **Must be valid JSON** — validate before writing (use `json.loads()` then write).
2. **Must use sorted keys**`json.dumps(data, sort_keys=True, indent=2)`
3. **Must be backed up** before overwriting — `cp file.json file.json.bak`
4. **Must use 2-space indentation** — matches Ignition's native format.
### resource.json Template
Every resource directory contains a `resource.json`:
```json
{
"props": {
"resource.name": "<resource-name>"
},
"scope": "G",
"version": 1
}
```
- `scope`: `"G"` = gateway, `"C"` = client, `"A"` = all
- `version`: increment on changes for cache-busting
## UDT / Linking Pattern
### Structure
```
[Device Type UDT]
├── Config/
│ ├── DeviceType (String)
│ ├── DeviceId (String)
│ └── Description (String)
├── Status/
│ ├── Running (Boolean)
│ ├── Faulted (Boolean)
│ └── ...
├── Command/
│ ├── Start (Boolean)
│ ├── Stop (Boolean)
│ └── ...
└── Linking/
└── Link/
├── LinkPath (String) ← path to PLC tag
└── LinkData (Dataset/Document) ← signal mapping
```
### How LinkPath Works
`LinkPath` contains the OPC tag path prefix for the PLC signals.
Example: `[ControlLogix]Program:MainProgram.P_101`
`LinkData` maps UDT members to PLC tag suffixes:
- `Status/Running``LinkPath + ".Sts_Running"`
- `Command/Start``LinkPath + ".Cmd_Start"`
This decouples the test/simulation layer from specific PLC I/O structures.
Changing the PLC program only requires updating `LinkPath` and `LinkData`.
### Rules
- Never modify `LinkPath` or `LinkData` at runtime from external tools.
- Set linking configuration through Ignition Designer or startup scripts.
- Test scenarios reference device UDT paths, not raw PLC tag paths.
## Scripting
### Jython 2.7 Constraints
All scripts in `ignition/project/` run Jython 2.7. Violating these causes runtime errors:
- NO f-strings → use `"text {}".format(val)` or `"text %s" % val`
- NO walrus operator `:=`
- NO `pathlib` → use `os.path`
- NO type hints → no `def foo(x: int) -> str:`
- NO `dataclasses`, `enum.auto()`, `asyncio`
- NO dictionary unpacking `{**d1, **d2}` → use `d1.update(d2)`
- NO `yield from` → use explicit loops
- Imports: `system.*` for Ignition API, standard Java/Jython libs only
### Project Library Scripts (`script-python/`)
Jython 2.7 — see root CLAUDE.md for language constraints.
Naming convention:
```
script-python/
├── testing/
│ ├── code.py ← testing.runScenario(), testing.validateResults()
│ └── resource.json
├── devices/
│ ├── code.py ← devices.getStatus(), devices.sendCommand()
│ └── resource.json
└── util/
├── code.py ← util.formatTag(), util.validateJson()
└── resource.json
```
Access in Ignition: `project.testing.runScenario()`
### Gateway Event Scripts
Located in project config, not in `script-python/`.
Used for startup initialization, tag change events, scheduled tasks.
### Common Ignition API Calls
```python
# Tag operations
system.tag.readBlocking(["path/to/tag"])
system.tag.writeBlocking(["path/to/tag"], [value])
system.tag.browseConfiguration("path", {})
# Named queries
system.db.runNamedQuery("queryName", {"param": value})
# WebDev (inside endpoint handlers)
# request object has: data, params, headers, remoteAddr
# return dict or string — Ignition serializes to JSON
# Logging
logger = system.util.getLogger("testing")
logger.info("message")
```
## Tag Provider Structure
```
[default]
├── _types_/ ← UDT definitions
│ ├── Devices/
│ │ ├── Motor/
│ │ ├── Valve/
│ │ └── Pump/
│ └── Linking/
│ └── Link/
├── Devices/ ← UDT instances
│ ├── Pumps/
│ │ ├── P-101/
│ │ └── P-102/
│ ├── Valves/
│ │ └── XV-1001/
│ └── Motors/
│ └── M-201/
└── System/ ← system/status tags
├── Health/
└── Config/
```
## Perspective Views
Views are JSON definitions in `com.inductiveautomation.perspective/views/`.
Each view folder contains `view.json` (component tree) and `resource.json`.
Rules:
- Do not hand-edit `view.json` unless you understand the component schema.
- Prefer creating views through Ignition Designer when possible.
- If editing programmatically, validate the full JSON structure before writing.