Add Node-RED documentation for lights and rooms integration
- Introduced new sections in README.md for Node-RED flows related to living room lighting and room management. - Added links to specific documentation for living room flow, all lights and rooms configuration, and living room analysis. - Enhanced overall organization of the README to improve user navigation and understanding of Node-RED integration with Home Assistant. This update enriches the documentation for users implementing Node-RED in their home automation setups.
This commit is contained in:
264
docs/integration/all-lights-and-rooms.md
Normal file
264
docs/integration/all-lights-and-rooms.md
Normal file
@@ -0,0 +1,264 @@
|
||||
# Using the flow for all lights and rooms
|
||||
|
||||
This doc explains how to scale the working “test light” setup to **all your lights and rooms**: what to configure in Node-RED, what to do in Home Assistant (including creating many entities efficiently), and how it fits with the PLC.
|
||||
|
||||
---
|
||||
|
||||
## 1. How it works (recap)
|
||||
|
||||
- **HA / Zigbee** → Node-RED updates **`flow.nvlInState.rooms.<roomKey>`** (e.g. `ha_l1_on`, `zigbee_sw2`).
|
||||
- **NVL SEND** builds the payload from **all** room keys and sends to the PLC.
|
||||
- **PLC** drives relays; sends back light state in **NVL_Out**.
|
||||
- **NVL to HA Sync** reads NVL_Out and calls HA **turn_on** / **turn_off** so the UI matches the real state.
|
||||
|
||||
To support all lights you need:
|
||||
|
||||
1. A **room list** that matches the PLC (NVL_In / NVL_Out).
|
||||
2. **Node-RED:** one state key per room, and mappings: HA entity → room + light index, Zigbee device → room, PLC payload key → HA entity.
|
||||
3. **HA:** one entity per light (or per zone) that you want to show in the UI and control.
|
||||
|
||||
---
|
||||
|
||||
## 2. Room list (align with PLC)
|
||||
|
||||
Use a single list of room keys everywhere. Example (match your CODESYS NVL order):
|
||||
|
||||
| Room key (Node-RED / NVL) | PLC NVL_Out (receive) | Lights per room |
|
||||
|---------------------------|------------------------|-----------------|
|
||||
| `livingRoom` | `l_livingRoom` | 1..6 |
|
||||
| `masterBedroom` | `l_masterBedroom` | 1..6 |
|
||||
| `kitchen` | `l_kitchen` | 1..6 |
|
||||
| `bathroom` | `l_bathroom` | 1..6 |
|
||||
| … | … | 1..6 |
|
||||
|
||||
- **NVL send (to PLC):** same keys as NVL_In in CODESYS (e.g. `livingRoom`, `masterBedroom`, … or `cmd_livingroom` for the test slot). Order and names must match the PLC.
|
||||
- **NVL receive (from PLC):** keys in the nvl-receive output (e.g. `l_livingRoom`, `light_livingRoom`) — use the same key in **LIGHT_ENTITY_MAP** in the sync function.
|
||||
|
||||
Keep one list (e.g. in a comment or config file) and use it in:
|
||||
- **state-to-nvl-send-payload.js** → `roomNames`
|
||||
- **NVL to HA Sync** → `LIGHT_ENTITY_MAP[].room` (must match nvl-receive payload keys)
|
||||
- **HA to NVL** / **Zigbee to NVL** → which room key to write to
|
||||
|
||||
---
|
||||
|
||||
## 3. Node-RED configuration for all lights
|
||||
|
||||
### 3.1 NVL SEND (state-to-nvl-send-payload.js)
|
||||
|
||||
Add **every room** that the PLC expects to the **`roomNames`** array. Each room uses the same `struct_room_cmds` shape.
|
||||
|
||||
```javascript
|
||||
const roomNames = [
|
||||
'livingRoom', // or cmd_livingroom if that’s your test slot
|
||||
'masterBedroom',
|
||||
'kitchen',
|
||||
'bathroom',
|
||||
'bedroom_1',
|
||||
'bedroom_2',
|
||||
'dinningRoom',
|
||||
'entrance',
|
||||
'hallway',
|
||||
'pantry',
|
||||
'guestWc',
|
||||
'outVeranda',
|
||||
'outFront',
|
||||
'outBack',
|
||||
'outSide',
|
||||
];
|
||||
```
|
||||
|
||||
Match this list to your **CODESYS NVL_In** layout and order.
|
||||
|
||||
### 3.2 HA → PLC: which room and light?
|
||||
|
||||
You have two patterns:
|
||||
|
||||
**Option A – One trigger-state per room (current pattern)**
|
||||
- One tab (or subflow) per room.
|
||||
- **trigger-state** watches that room’s entities (e.g. `input_boolean.living_room_1`, `input_boolean.living_room_2`).
|
||||
- **HA to NVL** has `ROOM_NAME = 'livingRoom'` (or that room’s key).
|
||||
- Replicate for each room (or use a subflow and pass `ROOM_NAME` in `msg`).
|
||||
|
||||
**Option B – One trigger-state for all entities (recommended for many lights)**
|
||||
- Single **trigger-state** (or **events: state**) that watches **all** your light/input_boolean entities (e.g. by substring `input_boolean.` or a list of entity IDs).
|
||||
- **HA to NVL** gets `msg.topic` = entity_id (e.g. `input_boolean.kitchen_2`).
|
||||
- In the function, **derive room + light** from the entity_id using a small config:
|
||||
|
||||
```javascript
|
||||
// Example: entity_id "input_boolean.kitchen_2" → room "kitchen", light 2
|
||||
const ENTITY_TO_ROOM = {
|
||||
'living_room': 'livingRoom',
|
||||
'kitchen': 'kitchen',
|
||||
'master_bedroom': 'masterBedroom',
|
||||
'bathroom': 'bathroom',
|
||||
// ...
|
||||
};
|
||||
// Parse: input_boolean.living_room_1 → room livingRoom, light 1
|
||||
const parts = (msg.topic || '').split('.');
|
||||
const name = (parts[1] || '').replace(/_(\d+)$/, '_$1');
|
||||
const roomKey = ENTITY_TO_ROOM[name.split('_').slice(0, -1).join('_')] || name;
|
||||
const lightNum = parseInt((name.match(/_(\d+)$/) || [,'1'])[1], 10) || 1;
|
||||
```
|
||||
|
||||
Then set `state.rooms[roomKey]['ha_l' + lightNum + '_on']` or `_off` as you do now. So one HA to NVL function can serve all entities if you pass the right `msg.topic` and use a consistent naming (e.g. `room_light_N`).
|
||||
|
||||
### 3.3 Zigbee → PLC: which room?
|
||||
|
||||
- Each **zigbee2mqtt-in** is one physical switch.
|
||||
- **Zigbee to NVL** must know which **room** that switch belongs to.
|
||||
- Either: **one Zigbee to NVL per room** (each has `ROOM_NAME = 'kitchen'` etc.) and wire each switch to the right one, or **one Zigbee to NVL** that gets **device/entity** from `msg` and uses a **device → room** map (e.g. `friendly_name` or `device_id` → room key).
|
||||
|
||||
Example map in Zigbee to NVL:
|
||||
|
||||
```javascript
|
||||
const DEVICE_TO_ROOM = {
|
||||
'Living Room Door Switch': 'livingRoom',
|
||||
'Office Switch': 'livingRoom', // or 'office' if you add that room
|
||||
'Kitchen Switch': 'kitchen',
|
||||
// ...
|
||||
};
|
||||
const roomKey = DEVICE_TO_ROOM[msg.payload?.friendly_name || ''] || 'livingRoom';
|
||||
```
|
||||
|
||||
Then use `roomKey` instead of a fixed `ROOM_NAME` when writing to `state.rooms[roomKey]`.
|
||||
|
||||
### 3.4 PLC → HA: NVL to HA Sync (LIGHT_ENTITY_MAP)
|
||||
|
||||
Add **one entry per light** you want to sync from the PLC back to HA. The **room** key must match what **nvl-receive** puts in `msg.payload` (e.g. `l_livingRoom` or `light_livingRoom`).
|
||||
|
||||
```javascript
|
||||
const LIGHT_ENTITY_MAP = [
|
||||
{ room: 'light_livingRoom', light: 1, entityId: 'input_boolean.living_room_1' },
|
||||
{ room: 'light_livingRoom', light: 2, entityId: 'input_boolean.living_room_2' },
|
||||
{ room: 'l_kitchen', light: 1, entityId: 'input_boolean.kitchen_1' },
|
||||
{ room: 'l_kitchen', light: 2, entityId: 'input_boolean.kitchen_2' },
|
||||
{ room: 'l_masterBedroom', light: 1, entityId: 'input_boolean.master_bedroom_1' },
|
||||
// ... one line per light
|
||||
];
|
||||
```
|
||||
|
||||
Generate this list from your room list + lights per room (e.g. 16 rooms × up to 6 lights = up to 96 entries; only add those you actually use).
|
||||
|
||||
---
|
||||
|
||||
## 4. Home Assistant: creating entities for all lights
|
||||
|
||||
You need one HA entity per light (or per zone) that Node-RED and the PLC treat as one target. Two common choices:
|
||||
|
||||
- **`input_boolean`** – simple on/off, good for “virtual” switches that only drive the PLC.
|
||||
- **`light` (template or generic)** – if you want them to appear as lights in the HA UI and in dashboards.
|
||||
|
||||
You can create them **one by one** or **in bulk**.
|
||||
|
||||
### 4.1 Efficient way: YAML (many at once)
|
||||
|
||||
Define all helpers in YAML so HA creates them at startup. No need to click 50 times in the UI.
|
||||
|
||||
**Option 1 – `configuration.yaml` (or a package)**
|
||||
|
||||
```yaml
|
||||
input_boolean:
|
||||
living_room_1:
|
||||
name: Living Room Light 1
|
||||
living_room_2:
|
||||
name: Living Room Light 2
|
||||
kitchen_1:
|
||||
name: Kitchen Light 1
|
||||
kitchen_2:
|
||||
name: Kitchen Light 2
|
||||
master_bedroom_1:
|
||||
name: Master Bedroom Light 1
|
||||
# ... add one block per entity
|
||||
```
|
||||
|
||||
- Entity IDs will be **`input_boolean.living_room_1`**, **`input_boolean.kitchen_1`**, etc.
|
||||
- Match these **exactly** in Node-RED (**trigger-state** and **LIGHT_ENTITY_MAP**).
|
||||
|
||||
**Option 2 – Package file (recommended)**
|
||||
|
||||
Create a file under your config, e.g. `packages/lights_nodered.yaml`:
|
||||
|
||||
```yaml
|
||||
input_boolean:
|
||||
living_room_1: { name: Living Room 1 }
|
||||
living_room_2: { name: Living Room 2 }
|
||||
kitchen_1: { name: Kitchen 1 }
|
||||
kitchen_2: { name: Kitchen 2 }
|
||||
master_bedroom_1: { name: Master Bedroom 1 }
|
||||
bathroom_1: { name: Bathroom 1 }
|
||||
# Add every light you want to control
|
||||
```
|
||||
|
||||
In `configuration.yaml` ensure packages are loaded:
|
||||
|
||||
```yaml
|
||||
homeassistant:
|
||||
packages: !include_dir_named packages
|
||||
```
|
||||
|
||||
Restart HA. All entities are created in one go. Then in Node-RED use the same IDs in your trigger and in **LIGHT_ENTITY_MAP**.
|
||||
|
||||
**Example – copy and adapt** (save as `packages/lights_nodered.yaml` in your HA config folder):
|
||||
|
||||
```yaml
|
||||
# Input booleans for PLC lights. Entity IDs must match Node-RED LIGHT_ENTITY_MAP and trigger-state.
|
||||
input_boolean:
|
||||
living_room_1: { name: Living Room 1 }
|
||||
living_room_2: { name: Living Room 2 }
|
||||
kitchen_1: { name: Kitchen 1 }
|
||||
kitchen_2: { name: Kitchen 2 }
|
||||
master_bedroom_1: { name: Master Bedroom 1 }
|
||||
master_bedroom_2: { name: Master Bedroom 2 }
|
||||
bathroom_1: { name: Bathroom 1 }
|
||||
bedroom_1_1: { name: Bedroom 1 Light 1 }
|
||||
bedroom_2_1: { name: Bedroom 2 Light 1 }
|
||||
dinning_room_1: { name: Dining Room 1 }
|
||||
entrance_1: { name: Entrance 1 }
|
||||
hallway_1: { name: Hallway 1 }
|
||||
pantry_1: { name: Pantry 1 }
|
||||
guest_wc_1: { name: Guest WC 1 }
|
||||
out_veranda_1: { name: Veranda 1 }
|
||||
out_front_1: { name: Front 1 }
|
||||
out_back_1: { name: Back 1 }
|
||||
out_side_1: { name: Side 1 }
|
||||
```
|
||||
|
||||
Add or remove lines to match your rooms and light counts. Entity IDs become `input_boolean.living_room_1`, etc.
|
||||
|
||||
### 4.2 UI way (one by one)
|
||||
|
||||
- **Settings** → **Devices & services** → **Helpers** → **Create Helper** → **Toggle**.
|
||||
- Create a toggle, set name (e.g. “Living Room 1”). HA will assign an entity_id like **`input_boolean.living_room_1`** (or similar, depending on the name you give).
|
||||
- Repeat for each light. Slower, but no YAML.
|
||||
|
||||
### 4.3 Naming convention (recommended)
|
||||
|
||||
Use a **consistent pattern** so you can derive room + light in Node-RED and in YAML:
|
||||
|
||||
- **Entity ID:** `input_boolean.<room>_<light>`
|
||||
Examples: `living_room_1`, `kitchen_2`, `master_bedroom_1`.
|
||||
- Then in HA to NVL you can parse: room from the first part, light from the trailing number.
|
||||
|
||||
---
|
||||
|
||||
## 5. Checklist: rolling out to all lights
|
||||
|
||||
| Step | Where | Action |
|
||||
|------|--------|--------|
|
||||
| 1 | **CODESYS** | Ensure NVL_In / NVL_Out include all rooms and lights in the order you use in Node-RED. |
|
||||
| 2 | **HA** | Create all entities (YAML package or UI). Use a clear naming scheme (e.g. `room_light_N`). |
|
||||
| 3 | **Node-RED – NVL SEND** | Set **`roomNames`** in `state-to-nvl-send-payload.js` to the full list of room keys (same order as PLC). |
|
||||
| 4 | **Node-RED – HA to NVL** | Either duplicate the flow per room (Option A) or use one flow and derive **room + light** from `msg.topic` (Option B). Ensure every HA entity is mapped to a room key and light index. |
|
||||
| 5 | **Node-RED – Zigbee to NVL** | Map each Zigbee device (by name or id) to a **room key** so the correct `state.rooms[roomKey]` is updated. |
|
||||
| 6 | **Node-RED – NVL to HA Sync** | Fill **LIGHT_ENTITY_MAP** with one entry per light: `room` (payload key from nvl-receive), `light` (1..6), `entityId` (HA entity). |
|
||||
| 7 | **Action nodes** | Keep one Action node (or two for on/off) with **Block Input Overrides** off so the sync’s `payload.action` and `payload.target.entity_id` are used for all entities. |
|
||||
|
||||
---
|
||||
|
||||
## 6. Summary
|
||||
|
||||
- **One shared state:** `flow.nvlInState.rooms.<roomKey>` for all rooms; **NVL SEND** builds one payload for the PLC from that state.
|
||||
- **One sync map:** **LIGHT_ENTITY_MAP** in NVL to HA Sync defines which PLC light (room + index) updates which HA entity.
|
||||
- **HA:** Create all entities in bulk via a **YAML package** (or one-by-one in Helpers). Use a consistent **entity_id** pattern so Node-RED can map HA ↔ room + light without mistakes.
|
||||
|
||||
If you want, the next step can be a single **example `packages/lights_nodered.yaml`** and an example **LIGHT_ENTITY_MAP** and **roomNames** list tailored to your actual room names and light counts.
|
||||
Reference in New Issue
Block a user