(* === DECLARATION === *) FUNCTION_BLOCK fb_room VAR_INPUT switches: struct_room_cmds; relay_status: struct_room_outs; // Read from EtherCAT outputs (actual relay states) END_VAR VAR_OUTPUT lights: struct_room_outs; END_VAR VAR l1: fb_light; l2: fb_light; l3: fb_light; 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); lights.l_1 := l1.light_output; l2(ha_on := switches.ha_l2_on, ha_off := switches.ha_l2_off, zigbee_sw := switches.zigbee_sw2, relay_status := relay_status.l_2); lights.l_2 := l2.light_output; l3(ha_on := switches.ha_l3_on, ha_off := switches.ha_l3_off, zigbee_sw := switches.zigbee_sw3, relay_status := relay_status.l_3); lights.l_3 := l3.light_output; l4(ha_on := switches.ha_l4_on, ha_off := switches.ha_l4_off, zigbee_sw := switches.zigbee_sw4, relay_status := relay_status.l_4); lights.l_4 := l4.light_output; l5(ha_on := switches.ha_l5_on, ha_off := switches.ha_l5_off, zigbee_sw := switches.zigbee_sw5, relay_status := relay_status.l_5); 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; // 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; lights.l_4 := TRUE; lights.l_5 := TRUE; lights.l_6 := TRUE; END_IF;