fix(fb_room): latch ha_all_on/off on rising edge, not level #1
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user