201 lines
5.9 KiB
Markdown
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. |