Corrected in README.md, CLAUDE.md, 02-environment/README.md and 03-plc/VERSIONS.md. The @VERSION 1.03.00 header inside the .qli files is the quickload FILE FORMAT version, not the CI Server release. Left alone. This also sharpens a caveat that was previously stated wrongly. The EQP-E-DUP_ITEM rejection - an item import fails if two items share an IO_ADDRESS - was observed on 2026-08-14 on the DEVELOPMENT machine, which ran R1.03. Production runs R1.05, where it has never been tested. The design still works around it by publishing level and speed in % only, and that workaround costs nothing; but anyone wanting a second unit for a measurement should try it on R1.05 before assuming they need a second PLC register to carry it.
79 lines
3.8 KiB
Markdown
79 lines
3.8 KiB
Markdown
# Software and versions
|
||
|
||
Everything below was **read from the running system on 2026-09-02**, not taken
|
||
from documentation. Where a version matters — where a different one behaves
|
||
differently — that is said explicitly.
|
||
|
||
## The PLC
|
||
|
||
| Component | Version | Where it runs | How to check |
|
||
|---|---|---|---|
|
||
| **OpenPLC Runtime** | **v4.1.10** | `openplc-runtime` container on `yau-sls-poc-lin001` | `docker exec openplc-runtime cat /workdir/VERSION` |
|
||
| Docker image | `openplc-runtime-migrated:v4.1.10` | local to the host, **not in any registry** | `docker images` |
|
||
| Base OS in container | Debian 12 (bookworm) | | `docker exec openplc-runtime cat /etc/os-release` |
|
||
| Python (runtime + plugins) | 3.11.2 | | `docker exec openplc-runtime python3 --version` |
|
||
| g++ | 12.2.0 | used to build the PLC program | `docker exec openplc-runtime g++ --version` |
|
||
| GNU Make | 4.3 | drives `scripts/Makefile.strucpp` | |
|
||
| pymodbus (in the slave plugin) | 3.11.2 | | `docker exec openplc-runtime ./venvs/modbus_slave/bin/pip list` |
|
||
|
||
### Runtime plugins
|
||
|
||
`/workdir/plugins.conf` — the third field is enabled (1) / disabled (0):
|
||
|
||
| Plugin | Enabled | Note |
|
||
|---|---|---|
|
||
| `modbus_slave` | **1** | This is the one that matters. It is what makes the PLC a Modbus **server** on 502. |
|
||
| `modbus_master` | 0 | Correct — the PLC must not poll anyone. |
|
||
| `opcua` | 0 | |
|
||
| `s7comm` | 0 | |
|
||
| `ethercat` | **1** | ⚠️ Enabled for no reason. It came from an `ethercat.json` the Editor project emits by default (the file is 0 bytes). Harmless so far, but it is a plugin running with nothing to do. |
|
||
|
||
## The toolchain
|
||
|
||
| Component | Version | Notes |
|
||
|---|---|---|
|
||
| **OpenPLC Editor** | **v4.2.11** (AppImage) | Needs `--no-sandbox` (Electron) and `libfuse2t64`. ⚠️ **Not currently installed anywhere** — see `DEPLOY.md` §0. |
|
||
| **STruC++** | **v0.6.2** | The ST → C++ compiler. **Ships only inside the Editor AppImage**; there is no standalone binary. This is the single reason the Editor is unavoidable. |
|
||
|
||
## The SCADA
|
||
|
||
| Component | Version | Where |
|
||
|---|---|---|
|
||
| **Yokogawa CI Server** | R1.05 | `yau-poc-cicore1` (`10.0.0.21`) |
|
||
|
||
## Versions that actually matter
|
||
|
||
**OpenPLC Runtime v3 → v4 is a breaking change, and most guidance you'll find
|
||
online is for v3.**
|
||
|
||
| | v3 | **v4 (what we run)** |
|
||
|---|---|---|
|
||
| ST compiler | MatIEC | **STruC++** |
|
||
| Accepts a flat `.st` upload | yes | **no** — `scripts/compile.sh` explicitly rejects MatIEC files (`Config0.c`, `glueVars.c`) |
|
||
| Web UI on the runtime | yes | **no** — REST API only, port 8443, JWT |
|
||
| Editor project format | one file | **a folder** — `project.json` + one file per POU |
|
||
| `%MW` Modbus mapping | starts at HR 0 | **starts at HR 1024** (`%QW` occupies 0–1023) |
|
||
|
||
That last row is the one that silently produces wrong data rather than an error.
|
||
See `register-map.csv`, which carries resolved addresses.
|
||
|
||
**The Modbus buffer layout is configuration, not a constant.** From
|
||
`core/generated/conf/modbus_slave.json` in the running container:
|
||
|
||
```json
|
||
"holding_registers": { "qw_count": 1024, "mw_count": 1024, ... }
|
||
```
|
||
|
||
`qw_count: 1024` is *why* `%MW0` is holding register 1024. Change that file and
|
||
every SCADA address moves.
|
||
|
||
**One CI Server behaviour is load-bearing, and it was observed on a different
|
||
release.** An item import is rejected if two items share an `IO_ADDRESS`
|
||
(`EQP-E-DUP_ITEM`). The SCADA design works around it by publishing one unit per
|
||
register — level and speed in % only, not in both % and engineering units.
|
||
|
||
That rejection was seen on **2026-08-14 on the development machine, which ran
|
||
R1.03**. Production `yau-poc-cicore1` runs **R1.05**, where the constraint has
|
||
never been tested. The workaround is harmless either way, but if you need a second
|
||
unit for a measurement, try it on R1.05 before assuming you need a second PLC
|
||
register for it.
|