Initial commit: CODESYS tree, integration docs, Node-RED scripts.

PLC application sources (NVL, rooms, boiler), HA/Node-RED integration guide, and NVL patch utilities.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-26 21:21:56 +03:00
commit d98c44bfa3
27 changed files with 3844 additions and 0 deletions

164
codesys-tree/_io.md Normal file
View File

@@ -0,0 +1,164 @@
# Device I/O Inventory
Snapshot of all hardware I/O channels and their CODESYS variable mappings.
Source: `read_device_io` against `C:\codesys-projects\Codesys_Home_Automation\Home_Automation.project`
(channels_only=true). Raw data: `_io.json`.
## Device tree (hardware)
| Device | Path | In | Out | Mapped out | Addr range |
|--------|------|---:|---:|---:|------------|
| GPIOs_A_B | `Device/GPIOs_A_B` | 1 (DWORD) | 1 (DWORD) | 0 | `%ID1` / `%QD2` |
| K1 | `Device/EtherCAT_Master/EK1100/K1` | 16 BOOL | 0 | — | `%IX0.0..%IX1.7` |
| K2 | `Device/EtherCAT_Master/EK1100/K2` | 0 | 16 BOOL | 14 / 16 | `%QX0.0..%QX1.7` |
| K3 | `Device/EtherCAT_Master/EK1100/K3` | 0 | 16 BOOL | 15 / 16 | `%QX2.0..%QX3.7` |
| K4 | `Device/EtherCAT_Master/EK1100/K4` | 0 | 16 BOOL | 12 / 16 | `%QX4.0..%QX5.7` |
`Onewire`, `Camera device`, `SPI`, `I?C`, `EtherCAT_Master` and `EK1100`
return no host parameters / channels of their own (they're parents/couplers).
**Totals:** 16 digital inputs (none mapped), 48 digital outputs (41 mapped, 7 free).
## Findings worth flagging
### Duplicate output mapping (likely a bug)
`Application.NVL_Sender.light_livingRoom.l_1` is written by **two** physical output channels:
| Where | IEC addr |
|-------|----------|
| K2 ch 10 | `%QX1.1` |
| K4 ch 16 | `%QX5.7` |
Both physical relays will switch together whenever the variable is written.
One of these should be remapped — usually `K4 %QX5.7` would be the one to free up
(based on K4's role as the spillover terminal).
### Unmapped output channels
| Device | IEC addr | Channel |
|--------|----------|---------|
| GPIOs_A_B | `%QD2` | (DWORD) |
| K2 | `%QX0.5` | Ch 6 |
| K2 | `%QX0.7` | Ch 8 |
| K3 | `%QX2.3` | Ch 4 |
| K4 | `%QX5.2` | Ch 11 |
| K4 | `%QX5.3` | Ch 12 |
| K4 | `%QX5.5` | Ch 14 |
| K4 | `%QX5.6` | Ch 15 |
### No inputs mapped
K1 (16-channel digital input terminal, `%IX0.0..%IX1.7`) is wired up at hardware
level but has zero variable mappings. If you have physical switches on K1, the
PLC currently can't see them.
### Variable target
All mapped outputs write into `Application.NVL_Sender.*` — i.e. the global
variable list that is *broadcast over UDP* to the receiver. This is the "Option C"
relay-feedback pattern referenced in the `GVL` comment: the program writes the
desired relay state into the NVL_Sender variable, the EtherCAT terminal switches
the actual relay, and the value read back is exactly the value just written.
No outputs are mapped against the application's room/light function block outputs
(`fb_room.lights.*` / `fb_light.light_output`). The new `fb_room` / `fb_light`
logic is therefore not yet driving the physical relays — that wiring would need
to be done in `PLC_PRG` (or `Lights_new`) by assigning each FB output into the
corresponding `NVL_Sender.light_*.l_N` slot before the IO write phase.
## Per-channel detail
### K1 (`Device/EtherCAT_Master/EK1100/K1`)
| Ch | IEC addr | Dir | Variable |
|---:|----------|-----|----------|
| 1 | `%IX0.0` | INP | _(unmapped)_ |
| 2 | `%IX0.1` | INP | _(unmapped)_ |
| 3 | `%IX0.2` | INP | _(unmapped)_ |
| 4 | `%IX0.3` | INP | _(unmapped)_ |
| 5 | `%IX0.4` | INP | _(unmapped)_ |
| 6 | `%IX0.5` | INP | _(unmapped)_ |
| 7 | `%IX0.6` | INP | _(unmapped)_ |
| 8 | `%IX0.7` | INP | _(unmapped)_ |
| 9 | `%IX1.0` | INP | _(unmapped)_ |
| 10 | `%IX1.1` | INP | _(unmapped)_ |
| 11 | `%IX1.2` | INP | _(unmapped)_ |
| 12 | `%IX1.3` | INP | _(unmapped)_ |
| 13 | `%IX1.4` | INP | _(unmapped)_ |
| 14 | `%IX1.5` | INP | _(unmapped)_ |
| 15 | `%IX1.6` | INP | _(unmapped)_ |
| 16 | `%IX1.7` | INP | _(unmapped)_ |
### K2 (`Device/EtherCAT_Master/EK1100/K2`)
| Ch | IEC addr | Dir | Variable |
|---:|----------|-----|----------|
| 1 | `%QX0.0` | OUT | `Application.NVL_Sender.light_dinningRoom.l_1` |
| 2 | `%QX0.1` | OUT | `Application.NVL_Sender.l_entrance.l_1` |
| 3 | `%QX0.2` | OUT | `Application.NVL_Sender.light_dinningRoom.l_2` |
| 4 | `%QX0.3` | OUT | `Application.NVL_Sender.light_dinningRoom.l_3` |
| 5 | `%QX0.4` | OUT | `Application.NVL_Sender.light_guestWc.l_1` |
| 6 | `%QX0.5` | OUT | _(unmapped)_ |
| 7 | `%QX0.6` | OUT | `Application.NVL_Sender.light_dinningRoom.l_4` |
| 8 | `%QX0.7` | OUT | _(unmapped)_ |
| 9 | `%QX1.0` | OUT | `Application.NVL_Sender.l_entrance.l_2` |
| 10 | `%QX1.1` | OUT | `Application.NVL_Sender.light_livingRoom.l_1` ⚠ duplicated on K4 ch 16 |
| 11 | `%QX1.2` | OUT | `Application.NVL_Sender.light_livingRoom.l_2` |
| 12 | `%QX1.3` | OUT | `Application.NVL_Sender.light_livingRoom.l_3` |
| 13 | `%QX1.4` | OUT | `Application.NVL_Sender.light_livingRoom.l_4` |
| 14 | `%QX1.5` | OUT | `Application.NVL_Sender.light_kitchenArea.l_1` |
| 15 | `%QX1.6` | OUT | `Application.NVL_Sender.light_kitchenArea.l_2` |
| 16 | `%QX1.7` | OUT | `Application.NVL_Sender.light_kitchenArea.l_3` |
### K3 (`Device/EtherCAT_Master/EK1100/K3`)
| Ch | IEC addr | Dir | Variable |
|---:|----------|-----|----------|
| 1 | `%QX2.0` | OUT | `Application.NVL_Sender.light_kitchenArea.l_4` |
| 2 | `%QX2.1` | OUT | `Application.NVL_Sender.light_hallway.l_1` |
| 3 | `%QX2.2` | OUT | `Application.NVL_Sender.light_office.l_1` |
| 4 | `%QX2.3` | OUT | _(unmapped)_ |
| 5 | `%QX2.4` | OUT | `Application.NVL_Sender.light_shower.l_1` |
| 6 | `%QX2.5` | OUT | `Application.NVL_Sender.light_shower.l_2` |
| 7 | `%QX2.6` | OUT | `Application.NVL_Sender.light_hallway.l_2` |
| 8 | `%QX2.7` | OUT | `Application.NVL_Sender.light_bedroom.l_1` |
| 9 | `%QX3.0` | OUT | `Application.NVL_Sender.light_bedroom.l_2` |
| 10 | `%QX3.1` | OUT | `Application.NVL_Sender.light_masterBedroom.l_1` |
| 11 | `%QX3.2` | OUT | `Application.NVL_Sender.light_masterBedroom.l_2` |
| 12 | `%QX3.3` | OUT | `Application.NVL_Sender.light_masterBedroom.l_3` |
| 13 | `%QX3.4` | OUT | `Application.NVL_Sender.light_masterBedroom.l_4` |
| 14 | `%QX3.5` | OUT | `Application.NVL_Sender.light_masterBath.l_1` |
| 15 | `%QX3.6` | OUT | `Application.NVL_Sender.light_masterBath.l_2` |
| 16 | `%QX3.7` | OUT | `Application.NVL_Sender.light_masterBath.l_3` |
### K4 (`Device/EtherCAT_Master/EK1100/K4`)
| Ch | IEC addr | Dir | Variable |
|---:|----------|-----|----------|
| 1 | `%QX4.0` | OUT | `Application.NVL_Sender.light_livingRoom.l_5` |
| 2 | `%QX4.1` | OUT | `Application.NVL_Sender.light_outBack.l_1` |
| 3 | `%QX4.2` | OUT | `Application.NVL_Sender.light_outBack.l_2` |
| 4 | `%QX4.3` | OUT | `Application.NVL_Sender.light_outFront.l_2` |
| 5 | `%QX4.4` | OUT | `Application.NVL_Sender.light_coveredVeranda.l_2` |
| 6 | `%QX4.5` | OUT | `Application.NVL_Sender.light_coveredVeranda.l_3` |
| 7 | `%QX4.6` | OUT | `Application.NVL_Sender.light_coveredVeranda.l_4` |
| 8 | `%QX4.7` | OUT | `Application.NVL_Sender.l_outSide.l_1` |
| 9 | `%QX5.0` | OUT | `Application.NVL_Sender.l_outFront.l_1` |
| 10 | `%QX5.1` | OUT | `Application.NVL_Sender.l_outVeranda.l_4` |
| 11 | `%QX5.2` | OUT | _(unmapped)_ |
| 12 | `%QX5.3` | OUT | _(unmapped)_ |
| 13 | `%QX5.4` | OUT | `Application.NVL_Sender.boiler_status.relay_output` |
| 14 | `%QX5.5` | OUT | _(unmapped)_ |
| 15 | `%QX5.6` | OUT | _(unmapped)_ |
| 16 | `%QX5.7` | OUT | `Application.NVL_Sender.light_livingRoom.l_1` ⚠ duplicates K2 ch 10 |
### GPIOs_A_B (`Device/GPIOs_A_B`)
| Ch | IEC addr | Dir | Variable |
|---:|----------|-----|----------|
| GPIOs in | `%ID1` | INP (DWORD) | _(unmapped)_ |
| GPIOs out | `%QD2` | OUT (DWORD) | _(unmapped)_ |
The Raspberry Pi onboard GPIO bank exists in the project but is not wired to any
variables.