- 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>
539 lines
13 KiB
Markdown
539 lines
13 KiB
Markdown
# Room/Light Structure Redesign Analysis
|
||
|
||
## Current Structure Analysis
|
||
|
||
### Current Organization
|
||
|
||
**Room-Centric Approach**:
|
||
- 15 rooms, each with 1 `fb_switch` instance
|
||
- Each room controls up to 6 lights
|
||
- Network variables organized by room name
|
||
- Structure: `l_masterBedroom.l_1`, `l_masterBedroom.l_2`, etc.
|
||
|
||
**Current Data Flow**:
|
||
```
|
||
Room → fb_switch → 6 lights
|
||
Network Variable: l_masterBedroom (struct_lights with l_1 to l_6)
|
||
```
|
||
|
||
### Current Issues
|
||
|
||
1. **Limited Scalability**
|
||
- Fixed 6 lights per room
|
||
- Adding a 7th light requires structure changes
|
||
- Some rooms may only need 1-2 lights (waste)
|
||
|
||
2. **Home Assistant Organization**
|
||
- HA entities: `light.master_bedroom_l1`, `light.master_bedroom_l2`
|
||
- Not intuitive - hard to find lights
|
||
- No grouping by function or zone
|
||
|
||
3. **Network Variable Efficiency**
|
||
- 15 room structures × 6 lights = 90 potential lights
|
||
- Most rooms don't use all 6 lights
|
||
- Wasted network bandwidth
|
||
|
||
4. **Maintenance Complexity**
|
||
- Changes require updating room structures
|
||
- Hard to add new rooms
|
||
- No clear naming convention
|
||
|
||
5. **MQTT Topic Structure**
|
||
- Topics like: `homeassistant/light/master_bedroom_l1`
|
||
- Not standardized
|
||
- Hard to discover and manage
|
||
|
||
## Alternative Structures
|
||
|
||
### Option 1: Flat Light-Centric Structure (Recommended)
|
||
|
||
**Concept**: All lights in a single flat structure, organized by unique IDs.
|
||
|
||
**Data Structure**:
|
||
```iec
|
||
TYPE struct_light :
|
||
STRUCT
|
||
// Control
|
||
on: BOOL; // Turn ON command
|
||
off: BOOL; // Turn OFF command
|
||
toggle: BOOL; // Toggle command (for Zigbee)
|
||
|
||
// Status
|
||
state: BOOL; // Current state
|
||
relay_status: BOOL; // Actual relay status
|
||
|
||
// Metadata (for reference, not in network var)
|
||
room: STRING; // Room name
|
||
name: STRING; // Light name
|
||
zone: STRING; // Zone (indoor/outdoor)
|
||
END_STRUCT
|
||
END_TYPE
|
||
|
||
TYPE struct_all_lights :
|
||
STRUCT
|
||
// Master Bedroom
|
||
master_bedroom_main: struct_light;
|
||
master_bedroom_bedside: struct_light;
|
||
master_bedroom_closet: struct_light;
|
||
|
||
// Kitchen
|
||
kitchen_ceiling: struct_light;
|
||
kitchen_under_cabinet: struct_light;
|
||
kitchen_island: struct_light;
|
||
|
||
// Living Room
|
||
living_room_main: struct_light;
|
||
living_room_reading: struct_light;
|
||
living_room_tv: struct_light;
|
||
|
||
// Outdoor
|
||
outdoor_front_porch: struct_light;
|
||
outdoor_back_patio: struct_light;
|
||
outdoor_side: struct_light;
|
||
|
||
// ... all other lights
|
||
END_STRUCT
|
||
END_TYPE
|
||
```
|
||
|
||
**Network Variable**:
|
||
```iec
|
||
VAR_GLOBAL
|
||
lights: struct_all_lights; // All lights in one structure
|
||
END_VAR
|
||
```
|
||
|
||
**Function Block**:
|
||
```iec
|
||
FUNCTION_BLOCK fb_lightControl
|
||
VAR_INPUT
|
||
light: struct_light;
|
||
relay_output: BOOL; // Direct relay output
|
||
END_VAR
|
||
VAR_OUTPUT
|
||
relay_control: BOOL;
|
||
light_status: struct_light;
|
||
END_VAR
|
||
// Implementation...
|
||
END_FUNCTION_BLOCK
|
||
```
|
||
|
||
**Pros**:
|
||
- ✅ Each light is independent
|
||
- ✅ Easy to add/remove lights
|
||
- ✅ Clear naming: `lights.kitchen_ceiling.on`
|
||
- ✅ Better for Home Assistant (one entity per light)
|
||
- ✅ No wasted space
|
||
- ✅ Easy to group in HA by room/zone
|
||
|
||
**Cons**:
|
||
- ⚠️ Larger structure (but more efficient overall)
|
||
- ⚠️ Need to update structure when adding lights
|
||
|
||
**Home Assistant Organization**:
|
||
```
|
||
light.kitchen_ceiling
|
||
light.kitchen_under_cabinet
|
||
light.master_bedroom_main
|
||
light.master_bedroom_bedside
|
||
```
|
||
|
||
**MQTT Topics**:
|
||
```
|
||
homeassistant/light/kitchen_ceiling/state
|
||
homeassistant/light/kitchen_ceiling/set
|
||
homeassistant/light/master_bedroom_main/state
|
||
```
|
||
|
||
---
|
||
|
||
### Option 2: Hierarchical Room → Light Structure
|
||
|
||
**Concept**: Keep room structure but make it more flexible.
|
||
|
||
**Data Structure**:
|
||
```iec
|
||
TYPE struct_room :
|
||
STRUCT
|
||
room_id: STRING; // "master_bedroom"
|
||
room_name: STRING; // "Master Bedroom"
|
||
zone: STRING; // "indoor", "outdoor"
|
||
|
||
// Flexible light array (up to 10 lights)
|
||
lights: ARRAY[1..10] OF struct_light;
|
||
light_count: INT; // Actual number of lights
|
||
END_STRUCT
|
||
END_TYPE
|
||
|
||
TYPE struct_home :
|
||
STRUCT
|
||
rooms: ARRAY[1..20] OF struct_room;
|
||
room_count: INT;
|
||
END_STRUCT
|
||
END_TYPE
|
||
```
|
||
|
||
**Pros**:
|
||
- ✅ Maintains room grouping
|
||
- ✅ Flexible number of lights per room
|
||
- ✅ Can add rooms easily
|
||
|
||
**Cons**:
|
||
- ⚠️ More complex array handling
|
||
- ⚠️ CODESYS arrays less efficient for network vars
|
||
- ⚠️ Harder to access specific lights
|
||
|
||
---
|
||
|
||
### Option 3: Zone-Based Structure
|
||
|
||
**Concept**: Organize by functional zones rather than rooms.
|
||
|
||
**Data Structure**:
|
||
```iec
|
||
TYPE struct_zone :
|
||
STRUCT
|
||
zone_id: STRING; // "indoor_main", "outdoor_security"
|
||
zone_name: STRING; // "Indoor Main", "Outdoor Security"
|
||
|
||
// Lights in this zone
|
||
lights: ARRAY[1..20] OF struct_light;
|
||
light_count: INT;
|
||
END_STRUCT
|
||
END_TYPE
|
||
|
||
TYPE struct_home_zones :
|
||
STRUCT
|
||
indoor_main: struct_zone;
|
||
indoor_bedrooms: struct_zone;
|
||
indoor_bathrooms: struct_zone;
|
||
outdoor_security: struct_zone;
|
||
outdoor_ambient: struct_zone;
|
||
END_STRUCT
|
||
END_TYPE
|
||
```
|
||
|
||
**Zones**:
|
||
- **Indoor Main**: Kitchen, Living Room, Dining Room, Hallway
|
||
- **Indoor Bedrooms**: All bedrooms
|
||
- **Indoor Bathrooms**: All bathrooms
|
||
- **Outdoor Security**: Front, Back, Side (security-focused)
|
||
- **Outdoor Ambient**: Veranda, Patio (ambient lighting)
|
||
|
||
**Pros**:
|
||
- ✅ Logical grouping for automation
|
||
- ✅ Easy to control all security lights
|
||
- ✅ Better for scheduling (indoor vs outdoor)
|
||
|
||
**Cons**:
|
||
- ⚠️ Less intuitive for room-based control
|
||
- ⚠️ Lights may belong to multiple zones conceptually
|
||
|
||
---
|
||
|
||
### Option 4: Hybrid: Room + Light ID Structure (Best Balance)
|
||
|
||
**Concept**: Combine room organization with individual light control.
|
||
|
||
**Data Structure**:
|
||
```iec
|
||
TYPE struct_light_control :
|
||
STRUCT
|
||
// Control
|
||
on: BOOL;
|
||
off: BOOL;
|
||
toggle: BOOL;
|
||
|
||
// Status
|
||
state: BOOL;
|
||
relay_status: BOOL;
|
||
|
||
// Metadata (for HA, not in network var)
|
||
light_id: STRING; // Unique ID: "mb_main", "kit_ceiling"
|
||
light_name: STRING; // Display name: "Main Light", "Ceiling Light"
|
||
room: STRING; // Room: "master_bedroom", "kitchen"
|
||
zone: STRING; // Zone: "indoor", "outdoor"
|
||
function: STRING; // Function: "main", "task", "ambient", "security"
|
||
END_STRUCT
|
||
END_TYPE
|
||
|
||
// Organized by room for CODESYS, but flat for HA
|
||
TYPE struct_rooms :
|
||
STRUCT
|
||
// Master Bedroom
|
||
master_bedroom: STRUCT
|
||
main: struct_light_control;
|
||
bedside_left: struct_light_control;
|
||
bedside_right: struct_light_control;
|
||
closet: struct_light_control;
|
||
END_STRUCT;
|
||
|
||
// Kitchen
|
||
kitchen: STRUCT
|
||
ceiling: struct_light_control;
|
||
under_cabinet: struct_light_control;
|
||
island: struct_light_control;
|
||
END_STRUCT;
|
||
|
||
// ... other rooms
|
||
END_STRUCT
|
||
END_TYPE
|
||
```
|
||
|
||
**Network Variable**:
|
||
```iec
|
||
VAR_GLOBAL
|
||
rooms: struct_rooms; // Organized by room
|
||
END_VAR
|
||
```
|
||
|
||
**Access Pattern**:
|
||
- CODESYS: `rooms.kitchen.ceiling.on`
|
||
- Node-RED: Flatten to `kitchen_ceiling` for HA
|
||
- Home Assistant: `light.kitchen_ceiling`
|
||
|
||
**Pros**:
|
||
- ✅ Best of both worlds
|
||
- ✅ Organized in CODESYS (by room)
|
||
- ✅ Flat in Home Assistant (by light)
|
||
- ✅ Easy to add lights to rooms
|
||
- ✅ Clear naming convention
|
||
|
||
**Cons**:
|
||
- ⚠️ Requires Node-RED transformation
|
||
- ⚠️ Slightly more complex
|
||
|
||
---
|
||
|
||
## Recommended Structure: Option 4 (Hybrid)
|
||
|
||
### Implementation
|
||
|
||
**1. CODESYS Structure** (Room-organized):
|
||
```iec
|
||
TYPE struct_light_control :
|
||
STRUCT
|
||
on: BOOL;
|
||
off: BOOL;
|
||
toggle: BOOL;
|
||
state: BOOL;
|
||
relay_status: BOOL;
|
||
END_STRUCT
|
||
END_TYPE
|
||
|
||
TYPE struct_room_lights :
|
||
STRUCT
|
||
main: struct_light_control;
|
||
secondary: struct_light_control;
|
||
task: struct_light_control;
|
||
ambient: struct_light_control;
|
||
accent: struct_light_control;
|
||
security: struct_light_control;
|
||
END_STRUCT
|
||
END_TYPE
|
||
|
||
VAR_GLOBAL
|
||
rooms: STRUCT
|
||
master_bedroom: struct_room_lights;
|
||
master_bathroom: struct_room_lights;
|
||
bedroom_1: struct_room_lights;
|
||
bedroom_2: struct_room_lights;
|
||
bathroom: struct_room_lights;
|
||
kitchen: struct_room_lights;
|
||
living_room: struct_room_lights;
|
||
dining_room: struct_room_lights;
|
||
hallway: struct_room_lights;
|
||
pantry: struct_room_lights;
|
||
entrance: struct_room_lights;
|
||
guest_wc: struct_room_lights;
|
||
outdoor_veranda: struct_room_lights;
|
||
outdoor_front: struct_room_lights;
|
||
outdoor_side: struct_room_lights;
|
||
outdoor_back: struct_room_lights;
|
||
END_STRUCT;
|
||
END_VAR
|
||
```
|
||
|
||
**2. Node-RED Transformation** (Flatten for HA):
|
||
```javascript
|
||
// Transform CODESYS structure to flat HA structure
|
||
function transformToHA(msg) {
|
||
const rooms = msg.payload.rooms;
|
||
const haLights = {};
|
||
|
||
// Flatten structure
|
||
for (const [roomName, roomLights] of Object.entries(rooms)) {
|
||
for (const [lightName, lightControl] of Object.entries(roomLights)) {
|
||
const lightId = `${roomName}_${lightName}`;
|
||
haLights[lightId] = {
|
||
on: lightControl.on,
|
||
off: lightControl.off,
|
||
state: lightControl.state,
|
||
status: lightControl.relay_status,
|
||
room: roomName,
|
||
light: lightName
|
||
};
|
||
}
|
||
}
|
||
|
||
return { payload: haLights };
|
||
}
|
||
```
|
||
|
||
**3. Home Assistant Configuration**:
|
||
```yaml
|
||
# Auto-discovery via MQTT
|
||
light:
|
||
- platform: mqtt
|
||
name: "Kitchen Main"
|
||
unique_id: "kitchen_main"
|
||
state_topic: "homeassistant/light/kitchen_main/state"
|
||
command_topic: "homeassistant/light/kitchen_main/set"
|
||
# ... config
|
||
```
|
||
|
||
**4. MQTT Topic Structure**:
|
||
```
|
||
homeassistant/light/{room}_{light}/state
|
||
homeassistant/light/{room}_{light}/set
|
||
|
||
Examples:
|
||
homeassistant/light/kitchen_main/state
|
||
homeassistant/light/master_bedroom_main/state
|
||
homeassistant/light/outdoor_front_security/state
|
||
```
|
||
|
||
---
|
||
|
||
## Comparison Matrix
|
||
|
||
| Aspect | Current | Option 1 (Flat) | Option 2 (Hierarchical) | Option 3 (Zone) | Option 4 (Hybrid) |
|
||
|--------|---------|-----------------|-------------------------|------------------|-------------------|
|
||
| **CODESYS Organization** | Room-based | Flat | Array-based | Zone-based | Room-based |
|
||
| **HA Organization** | Room-based | Flat | Complex | Zone-based | Flat (transformed) |
|
||
| **Scalability** | Poor | Excellent | Good | Good | Excellent |
|
||
| **Maintainability** | Medium | Excellent | Medium | Medium | Excellent |
|
||
| **Network Efficiency** | Poor | Good | Medium | Medium | Good |
|
||
| **Naming Clarity** | Medium | Excellent | Medium | Good | Excellent |
|
||
| **Implementation Complexity** | Low | Medium | High | Medium | Medium |
|
||
| **Flexibility** | Low | High | High | Medium | High |
|
||
|
||
---
|
||
|
||
## Optimization Recommendations
|
||
|
||
### 1. Network Variable Optimization
|
||
|
||
**Current**: 15 rooms × 6 lights = 90 potential lights
|
||
**Optimized**: Only include lights that exist
|
||
|
||
**Example**:
|
||
```iec
|
||
// Only define lights that exist
|
||
master_bedroom: STRUCT
|
||
main: struct_light_control;
|
||
bedside: struct_light_control;
|
||
// No closet light if it doesn't exist
|
||
END_STRUCT;
|
||
```
|
||
|
||
### 2. Function-Based Naming
|
||
|
||
Instead of `l_1`, `l_2`, use descriptive names:
|
||
- `main` - Main/primary light
|
||
- `secondary` - Secondary light
|
||
- `task` - Task lighting
|
||
- `ambient` - Ambient/atmospheric
|
||
- `accent` - Accent lighting
|
||
- `security` - Security/outdoor
|
||
|
||
### 3. Metadata for Home Assistant
|
||
|
||
Add metadata structure (not in network var, but in Node-RED):
|
||
```javascript
|
||
const lightMetadata = {
|
||
"kitchen_main": {
|
||
name: "Kitchen Main Light",
|
||
room: "Kitchen",
|
||
zone: "indoor",
|
||
function: "main",
|
||
icon: "mdi:ceiling-light"
|
||
},
|
||
// ... more lights
|
||
};
|
||
```
|
||
|
||
### 4. Grouping in Home Assistant
|
||
|
||
Use HA groups and areas:
|
||
```yaml
|
||
# Automatically group by room
|
||
light:
|
||
- platform: group
|
||
name: "Kitchen Lights"
|
||
entities:
|
||
- light.kitchen_main
|
||
- light.kitchen_under_cabinet
|
||
- light.kitchen_island
|
||
|
||
# Use areas for room organization
|
||
areas:
|
||
- name: "Kitchen"
|
||
entities:
|
||
- light.kitchen_main
|
||
- light.kitchen_under_cabinet
|
||
```
|
||
|
||
---
|
||
|
||
## Migration Strategy
|
||
|
||
### Phase 1: Structure Redesign
|
||
1. Define new data structures
|
||
2. Create mapping from old to new
|
||
3. Update function blocks
|
||
|
||
### Phase 2: Node-RED Update
|
||
1. Update network variable mapping
|
||
2. Add transformation functions
|
||
3. Update MQTT topics
|
||
|
||
### Phase 3: Home Assistant Migration
|
||
1. Create new entities with new structure
|
||
2. Migrate automations
|
||
3. Update dashboards
|
||
|
||
### Phase 4: Testing & Validation
|
||
1. Test all control paths
|
||
2. Verify status feedback
|
||
3. Test HA integration
|
||
|
||
---
|
||
|
||
## Final Recommendation
|
||
|
||
**Use Option 4 (Hybrid Structure)** because:
|
||
|
||
1. ✅ **Best Organization**: Room-based in CODESYS, flat in HA
|
||
2. ✅ **Scalability**: Easy to add lights to any room
|
||
3. ✅ **Clarity**: Descriptive names (`kitchen_main` vs `l_1`)
|
||
4. ✅ **Flexibility**: Can group by room, zone, or function
|
||
5. ✅ **Efficiency**: Only define lights that exist
|
||
6. ✅ **Maintainability**: Clear structure, easy to understand
|
||
|
||
**Key Improvements**:
|
||
- Replace `l_1`, `l_2` with `main`, `secondary`, `task`, etc.
|
||
- Use descriptive light IDs: `kitchen_main`, `master_bedroom_bedside`
|
||
- Flatten structure in Node-RED for Home Assistant
|
||
- Add metadata for better HA organization
|
||
- Optimize network variables (only existing lights)
|
||
|
||
---
|
||
|
||
**Next Steps**:
|
||
1. Review this analysis
|
||
2. Choose structure option
|
||
3. Plan migration
|
||
4. Implement new structure
|
||
5. Update Node-RED and HA
|