diff --git a/codesys-tree/Device/Plc Logic/Application/3.Function Blocks/fb_room.st b/codesys-tree/Device/Plc Logic/Application/3.Function Blocks/fb_room.st index 9c3ecbe..58518f8 100644 --- a/codesys-tree/Device/Plc Logic/Application/3.Function Blocks/fb_room.st +++ b/codesys-tree/Device/Plc Logic/Application/3.Function Blocks/fb_room.st @@ -14,12 +14,20 @@ VAR l4: fb_light; l5: fb_light; l6: fb_light; + r_trig_all_on: R_TRIG; + r_trig_all_off: R_TRIG; + all_on_latch: BOOL := FALSE; // Latched room-wide ON until ha_all_off rising edge END_VAR (* === IMPLEMENTATION === *) // ===================================================== // fb_room - Implementation (per redesign) // ===================================================== +// Per-light: ha_lN_on/off and zigbee_swN use R_TRIG in fb_light (NVL pulses). +// Room-wide: ha_all_on / ha_all_off are also rising-edge pulses from Node-RED; +// latch all_on_latch so outputs stay on after the pulse ends (do not use level +// on switches.ha_all_on — a FALSE NVL bit would drop back to per-light state). +// ===================================================== // Light 1..6 (relay_status = previous cycle output for Option C) l1(ha_on := switches.ha_l1_on, ha_off := switches.ha_l1_off, zigbee_sw := switches.zigbee_sw1, relay_status := relay_status.l_1); @@ -40,15 +48,17 @@ lights.l_5 := l5.light_output; l6(ha_on := switches.ha_l6_on, ha_off := switches.ha_l6_off, zigbee_sw := switches.zigbee_sw6, relay_status := relay_status.l_6); lights.l_6 := l6.light_output; -// Global Commands (overwrite outputs per redesign) -IF switches.ha_all_off THEN - lights.l_1 := FALSE; - lights.l_2 := FALSE; - lights.l_3 := FALSE; - lights.l_4 := FALSE; - lights.l_5 := FALSE; - lights.l_6 := FALSE; -ELSIF switches.ha_all_on THEN +// Room-wide commands (rising edge + latch) +r_trig_all_on(CLK := switches.ha_all_on); +r_trig_all_off(CLK := switches.ha_all_off); + +IF r_trig_all_on.Q THEN + all_on_latch := TRUE; +ELSIF r_trig_all_off.Q THEN + all_on_latch := FALSE; +END_IF; + +IF all_on_latch THEN lights.l_1 := TRUE; lights.l_2 := TRUE; lights.l_3 := TRUE; diff --git a/docs/integration-home-assistant-nodered.md b/docs/integration-home-assistant-nodered.md index 4feb157..5a18ac1 100644 --- a/docs/integration-home-assistant-nodered.md +++ b/docs/integration-home-assistant-nodered.md @@ -88,7 +88,7 @@ flowchart LR |-------------|---------|---------| | HA pulses | `ha_l1_on` … `ha_l6_on`, `ha_l1_off` … `ha_l6_off` | `fb_light` via `R_TRIG` (rising edge only) | | Zigbee pulses | `zigbee_sw1` … `zigbee_sw6` | `fb_light` toggle on edge | -| Room-wide | `ha_all_on`, `ha_all_off` | Room-level FBs | +| Room-wide | `ha_all_on`, `ha_all_off` | `fb_room`: `R_TRIG` + `all_on_latch` (rising edge only; see below) | **`struct_room_outs`** (in `NVL_Sender` as `light_*` rooms)—per-room outputs: @@ -112,6 +112,20 @@ Physical mapping: see `codesys-tree/_io.md` (EtherCAT `%QX*` → `Application.NV Outputs feed `NVL_Sender`; EtherCAT maps those BOOLs to contactors. +### Room-wide ALL ON / ALL OFF (`fb_room`) + +Node-RED sends **`ha_all_on` / `ha_all_off` as short rising-edge pulses** (PLC Troubleshoot dashboard, same as `zigbee_swN`). They must **not** be treated as level-sensitive BOOLs. + +**Previous behaviour (bug):** `IF switches.ha_all_on THEN …` forced all outputs on only while the NVL bit stayed `TRUE`. When Node-RED cleared the pulse (~120 ms–1 s), outputs fell back to per-light `fb_light` state (usually off) → “flash then all off”. + +**Current behaviour (`fb_room.st`):** + +1. `R_TRIG` on `ha_all_on` / `ha_all_off`. +2. Rising edge on `ha_all_on` sets internal `all_on_latch := TRUE` (all six outputs forced on each scan until released). +3. Rising edge on `ha_all_off` clears `all_on_latch`; per-light `fb_light` outputs apply again. + +**Node-RED alignment:** `room-config-lib.js` uses sparse `buildNvlSendPayload` (only `TRUE` bits merged into `nvl-send`) and does not send a follow-up `ha_all_on := FALSE` frame for ALL ON. After deploying this PLC change, download the application to the controller. + --- ## Node-RED side @@ -141,7 +155,7 @@ Outputs feed `NVL_Sender`; EtherCAT maps those BOOLs to contactors. 5. **Return path:** **`udp in`** `:1202` → **`nvl-receive`** (parses **`NVL_Sender`**) → **NVL to HA Sync** → Home Assistant `api-call-service` (`turn_on` / `turn_off` on mapped helpers). -6. **Edge clearing** — after ~80 ms, **Clear NVL edges** / **Clear zigbee edge** reset pulse bits so the PLC sees rising edges on the next command (matches `R_TRIG` in ST). +6. **Edge clearing** — after ~120 ms, **Clear NVL edges** reset `zigbee_sw*` / `ha_lN_*` pulse bits via `buildNvlClearPayload` (explicit `FALSE` merge only for cleared keys). **`ha_all_on` / `ha_all_off`** are not cleared over UDP (one rising-edge frame only); the PLC latch in `fb_room` holds the room on until `ha_all_off`. ### Configuration files (single source of truth)