# fb_switch Redesign Recommendation

## Current Implementation Issues

### Problem 1: Toggle-Based Control
**Issue**: The current `fb_toogleButton` implementation uses toggle logic, which causes state desynchronization with Home Assistant.

**Why this is a problem**:
- Home Assistant sends explicit ON/OFF commands
- CODESYS treats every input as a toggle trigger
- If HA thinks light is ON and sends ON again, CODESYS toggles it OFF
- State becomes out of sync between HA and actual relay state

**Example Scenario**:
1. HA sends `sw_1 = TRUE` (turn ON)
2. CODESYS toggles: OFF → ON ✓
3. HA sends `sw_1 = TRUE` again (thinking it's already ON)
4. CODESYS toggles: ON → OFF ✗ (wrong!)

### Problem 2: No Direct Set/Reset Commands
**Issue**: Current structure only has toggle triggers, no explicit ON/OFF commands.

**Current Structure**:
```iec
struct_switches:
    sw_1: BOOL;  // Treated as toggle trigger
    all_on: BOOL;  // Toggle trigger
    all_off: BOOL;  // Toggle trigger
```

**What's needed**:
- Separate ON and OFF commands
- Edge detection for Zigbee switches (toggle behavior)
- Direct set/reset for Home Assistant

### Problem 3: Status Feedback Limitations
**Issue**: Current `lights.l_X` outputs represent toggle button state, not actual relay status.

**Problems**:
- No direct feedback from physical relay outputs
- Status may not match actual relay state if relay fails
- No way to detect relay hardware failures

## Recommended Redesign

### New Data Structure

```iec
TYPE struct_switches :
STRUCT
    // Home Assistant Commands (set/reset)
    ha_l1_on: BOOL;      // HA command: Light 1 ON
    ha_l1_off: BOOL;     // HA command: Light 1 OFF
    ha_l2_on: BOOL;
    ha_l2_off: BOOL;
    ha_l3_on: BOOL;
    ha_l3_off: BOOL;
    ha_l4_on: BOOL;
    ha_l4_off: BOOL;
    ha_l5_on: BOOL;
    ha_l5_off: BOOL;
    ha_l6_on: BOOL;
    ha_l6_off: BOOL;
    
    // Zigbee Switch Inputs (edge detection for toggle)
    zigbee_sw1: BOOL;    // Zigbee switch 1 (edge detected)
    zigbee_sw2: BOOL;
    zigbee_sw3: BOOL;
    zigbee_sw4: BOOL;
    zigbee_sw5: BOOL;
    zigbee_sw6: BOOL;
    
    // Global Commands
    ha_all_on: BOOL;     // HA: All lights ON
    ha_all_off: BOOL;    // HA: All lights OFF
END_STRUCT
END_TYPE

TYPE struct_lights:
STRUCT
    l_1: BOOL;  // Light 1 control output
    l_2: BOOL;  // Light 2 control output
    l_3: BOOL;  // Light 3 control output
    l_4: BOOL;  // Light 4 control output
    l_5: BOOL;  // Light 5 control output
    l_6: BOOL;  // Light 6 control output
    
    // Status feedback (read from actual relay outputs)
    l_1_status: BOOL;  // Actual relay 1 state
    l_2_status: BOOL;  // Actual relay 2 state
    l_3_status: BOOL;  // Actual relay 3 state
    l_4_status: BOOL;  // Actual relay 4 state
    l_5_status: BOOL;  // Actual relay 5 state
    l_6_status: BOOL;  // Actual relay 6 state
END_STRUCT
END_TYPE
```

### New Function Block: fb_lightControl

```iec
FUNCTION_BLOCK fb_lightControl
VAR_INPUT
    // Home Assistant Commands
    ha_on: BOOL;      // HA command: Turn ON
    ha_off: BOOL;     // HA command: Turn OFF
    
    // Zigbee Switch Input
    zigbee_sw: BOOL;  // Zigbee switch (edge detected)
    
    // Status Feedback
    relay_status: BOOL;  // Actual relay state (read from EtherCAT)
END_VAR
VAR_OUTPUT
    light_output: BOOL;      // Control output to relay
    light_status: BOOL;      // Status to send back (actual relay state)
END_VAR
VAR
    // Edge detection for Zigbee
    zigbee_prev: BOOL;
    zigbee_edge: BOOL;
    
    // Command processing
    ha_on_prev: BOOL;
    ha_off_prev: BOOL;
    ha_on_edge: BOOL;
    ha_off_edge: BOOL;
    
    // Internal state
    light_state: BOOL;
    
    // Edge triggers
    r_trig_ha_on: R_TRIG;
    r_trig_ha_off: R_TRIG;
    r_trig_zigbee: R_TRIG;
END_VAR
```

### Implementation Logic

**Priority Order** (highest to lowest):
1. **HA OFF command** - Always turns light OFF
2. **HA ON command** - Always turns light ON
3. **Zigbee toggle** - Toggles current state
4. **Maintain current state** - If no commands

**Logic Flow**:

```iec
// Edge detection for commands
r_trig_ha_on(CLK := ha_on);
ha_on_edge := r_trig_ha_on.Q;

r_trig_ha_off(CLK := ha_off);
ha_off_edge := r_trig_ha_off.Q;

r_trig_zigbee(CLK := zigbee_sw);
zigbee_edge := r_trig_zigbee.Q;

// State machine
IF ha_off_edge THEN
    light_state := FALSE;
ELSIF ha_on_edge THEN
    light_state := TRUE;
ELSIF zigbee_edge THEN
    light_state := NOT light_state;
END_IF

// Output assignment
light_output := light_state;

// Status feedback (read from actual relay)
light_status := relay_status;
```

### New fb_switch Implementation

```iec
FUNCTION_BLOCK fb_switch
VAR_INPUT
    switches: struct_switches;
    relay_status: struct_lights;  // Read from EtherCAT outputs
END_VAR
VAR_OUTPUT
    lights: struct_lights;
END_VAR
VAR
    l1: fb_lightControl;
    l2: fb_lightControl;
    l3: fb_lightControl;
    l4: fb_lightControl;
    l5: fb_lightControl;
    l6: fb_lightControl;
END_VAR

// Light 1 Control
l1(
    ha_on := switches.ha_l1_on,
    ha_off := switches.ha_l1_off,
    zigbee_sw := switches.zigbee_sw1,
    relay_status := relay_status.l_1_status
);
lights.l_1 := l1.light_output;
lights.l_1_status := l1.light_status;

// Light 2 Control
l2(
    ha_on := switches.ha_l2_on,
    ha_off := switches.ha_l2_off,
    zigbee_sw := switches.zigbee_sw2,
    relay_status := relay_status.l_2_status
);
lights.l_2 := l2.light_output;
lights.l_2_status := l2.light_status;

// ... (repeat for l3-l6)

// Global Commands
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
    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;
```

## Node-RED Integration Changes

### Current Flow (Toggle-Based)
```
Zigbee Switch → MQTT → Node-RED → CODESYS (sw_1 = TRUE) → Toggle
Home Assistant → MQTT → Node-RED → CODESYS (sw_1 = TRUE) → Toggle (WRONG!)
```

### New Flow (Command-Based)
```
Zigbee Switch → MQTT → Node-RED → CODESYS (zigbee_sw1 = edge) → Toggle
Home Assistant → MQTT → Node-RED → CODESYS (ha_l1_on = TRUE) → Set ON
Home Assistant → MQTT → Node-RED → CODESYS (ha_l1_off = TRUE) → Set OFF
```

### Node-RED Flow Example

**For Zigbee Switches**:
```javascript
// Detect button press (edge detection)
if (msg.payload.action === "single") {
    // Send edge trigger to CODESYS
    msg.payload = {
        zigbee_sw1: true  // Edge detected
    };
    return msg;
}
```

**For Home Assistant**:
```javascript
// Direct ON/OFF commands
if (msg.payload === "ON") {
    msg.payload = {
        ha_l1_on: true,
        ha_l1_off: false
    };
} else if (msg.payload === "OFF") {
    msg.payload = {
        ha_l1_on: false,
        ha_l1_off: true
    };
}
return msg;
```

**Status Feedback to Home Assistant**:
```javascript
// Read status from CODESYS
const status = msg.payload.l_1_status;
// Publish to HA
msg.topic = "homeassistant/light/room1_light1/state";
msg.payload = status ? "ON" : "OFF";
return msg;
```

## Home Assistant Configuration

### MQTT Light Entity

```yaml
light:
  - platform: mqtt
    name: "Room 1 Light 1"
    state_topic: "homeassistant/light/room1_light1/state"
    command_topic: "homeassistant/light/room1_light1/set"
    state_value_template: "{{ value_json.state }}"
    command_on_template: '{"state":"ON"}'
    command_off_template: '{"state":"OFF"}'
    qos: 1
    retain: true
```

### Node-RED Flow for HA Integration

```
[HA Command] → [Parse] → [Convert to CODESYS format] → [Network Variable]
[CODESYS Status] → [Network Variable] → [Convert to HA format] → [HA State]
```

## Benefits of Redesign

### 1. State Synchronization
- ✅ HA always knows actual relay state
- ✅ No state desynchronization
- ✅ Reliable ON/OFF commands

### 2. Multiple Control Sources
- ✅ HA uses set/reset commands
- ✅ Zigbee switches use toggle (edge detection)
- ✅ Both work simultaneously without conflicts

### 3. Status Feedback
- ✅ Actual relay state read from EtherCAT
- ✅ Hardware failure detection possible
- ✅ Accurate status in Home Assistant

### 4. Better Debugging
- ✅ Clear separation of commands
- ✅ Can trace which source triggered action
- ✅ Easier troubleshooting

### 5. Extensibility
- ✅ Easy to add more control sources
- ✅ Can add priority levels
- ✅ Can add scheduling/automation

## Migration Path

### Step 1: Update Data Structures
1. Modify `struct_switches` to include HA commands and Zigbee inputs
2. Modify `struct_lights` to include status feedback
3. Keep old structure temporarily for backward compatibility

### Step 2: Create New Function Blocks
1. Implement `fb_lightControl` with new logic
2. Update `fb_switch` to use new function blocks
3. Test in simulation first

### Step 3: Update Node-RED Flows
1. Modify flows to send HA commands (ON/OFF)
2. Keep Zigbee flows with edge detection
3. Add status feedback flows

### Step 4: Update Home Assistant
1. Configure MQTT light entities
2. Test control from HA
3. Verify status updates

### Step 5: Testing
1. Test HA control (ON/OFF)
2. Test Zigbee switch control (toggle)
3. Test status feedback
4. Test both simultaneously

## Alternative: Simpler Approach (If Full Redesign Too Complex)

If the full redesign is too complex, here's a simpler improvement:

### Simplified Improvement

**Keep toggle logic but add state tracking**:

```iec
FUNCTION_BLOCK fb_lightControl_Simple
VAR_INPUT
    toggle: BOOL;  // Toggle command (edge detected)
    set_on: BOOL;  // Set ON command (edge detected)
    set_off: BOOL; // Set OFF command (edge detected)
    relay_status: BOOL;  // Actual relay state
END_VAR
VAR_OUTPUT
    output: BOOL;
    status: BOOL;
END_VAR
VAR
    state: BOOL;
    r_trig_toggle: R_TRIG;
    r_trig_on: R_TRIG;
    r_trig_off: R_TRIG;
END_VAR

// Edge detection
r_trig_toggle(CLK := toggle);
r_trig_on(CLK := set_on);
r_trig_off(CLK := set_off);

// State machine
IF r_trig_off.Q THEN
    state := FALSE;
ELSIF r_trig_on.Q THEN
    state := TRUE;
ELSIF r_trig_toggle.Q THEN
    state := NOT state;
END_IF;

output := state;
status := relay_status;  // Read from actual relay
```

**Data Structure**:
```iec
struct_switches:
    sw1_toggle: BOOL;  // Zigbee toggle
    sw1_on: BOOL;      // HA ON command
    sw1_off: BOOL;     // HA OFF command
    // ... repeat for sw2-sw6
```

This simpler approach:
- ✅ Keeps existing structure mostly intact
- ✅ Adds explicit ON/OFF commands for HA
- ✅ Maintains toggle for Zigbee
- ✅ Adds status feedback
- ⚠️ Still requires data structure changes
- ⚠️ Less clean than full redesign

## Recommendation

**I recommend the full redesign** because:
1. Better long-term maintainability
2. Clear separation of concerns
3. Easier to extend and debug
4. Proper state management
5. Industry-standard approach

However, if time is limited, the **simplified approach** is a good compromise that addresses the main issues.

---

**Next Steps**:
1. Review this recommendation
2. Decide on full redesign vs. simplified approach
3. Plan migration strategy
4. Update Node-RED flows accordingly
5. Test thoroughly before deploying
