- 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>
13 KiB
Room/Light Structure Redesign Analysis
Current Structure Analysis
Current Organization
Room-Centric Approach:
- 15 rooms, each with 1
fb_switchinstance - 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
-
Limited Scalability
- Fixed 6 lights per room
- Adding a 7th light requires structure changes
- Some rooms may only need 1-2 lights (waste)
-
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
- HA entities:
-
Network Variable Efficiency
- 15 room structures × 6 lights = 90 potential lights
- Most rooms don't use all 6 lights
- Wasted network bandwidth
-
Maintenance Complexity
- Changes require updating room structures
- Hard to add new rooms
- No clear naming convention
-
MQTT Topic Structure
- Topics like:
homeassistant/light/master_bedroom_l1 - Not standardized
- Hard to discover and manage
- Topics like:
Alternative Structures
Option 1: Flat Light-Centric Structure (Recommended)
Concept: All lights in a single flat structure, organized by unique IDs.
Data Structure:
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:
VAR_GLOBAL
lights: struct_all_lights; // All lights in one structure
END_VAR
Function Block:
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:
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:
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:
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:
VAR_GLOBAL
rooms: struct_rooms; // Organized by room
END_VAR
Access Pattern:
- CODESYS:
rooms.kitchen.ceiling.on - Node-RED: Flatten to
kitchen_ceilingfor 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):
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):
// 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:
# 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:
// 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 lightsecondary- Secondary lighttask- Task lightingambient- Ambient/atmosphericaccent- Accent lightingsecurity- Security/outdoor
3. Metadata for Home Assistant
Add metadata structure (not in network var, but in Node-RED):
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:
# 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
- Define new data structures
- Create mapping from old to new
- Update function blocks
Phase 2: Node-RED Update
- Update network variable mapping
- Add transformation functions
- Update MQTT topics
Phase 3: Home Assistant Migration
- Create new entities with new structure
- Migrate automations
- Update dashboards
Phase 4: Testing & Validation
- Test all control paths
- Verify status feedback
- Test HA integration
Final Recommendation
Use Option 4 (Hybrid Structure) because:
- ✅ Best Organization: Room-based in CODESYS, flat in HA
- ✅ Scalability: Easy to add lights to any room
- ✅ Clarity: Descriptive names (
kitchen_mainvsl_1) - ✅ Flexibility: Can group by room, zone, or function
- ✅ Efficiency: Only define lights that exist
- ✅ Maintainability: Clear structure, easy to understand
Key Improvements:
- Replace
l_1,l_2withmain,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:
- Review this analysis
- Choose structure option
- Plan migration
- Implement new structure
- Update Node-RED and HA