Files
kkelomatic_home/docs/redesign/fb_switch-redesign-recommendation.md
nearxos bf7bd56fe7 Initial commit: Home automation docs and CODESYS project
- Reorganized project: codesys/, docs/codesys|redesign|integration|reference/, scripts/
- CODESYS project and exports in codesys/
- Documentation index in docs/README.md
- Redesign and light naming configuration
- Water boiler control and safety design

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-07 21:52:46 +02:00

452 lines
11 KiB
Markdown

# 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