Files
kkelomatic_home/docs/integration/nodered-livingroom-flow.md
nearxos f0d883b8c2 Remove obsolete INFORMATION_NEEDED.md and streamline README.md for clarity
- Deleted the INFORMATION_NEEDED.md file as it was no longer necessary for documentation.
- Revised README.md to enhance the overview of the home automation system, focusing on how services and CODESYS connectivity work.
- Updated project structure in README.md for better organization and clarity, including links to relevant documentation.

This update simplifies the documentation and improves the overall user experience for developers and users of the home automation system.
2026-02-08 17:09:30 +02:00

168 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Node-RED: Living Room flow
This document describes the **Living Room** tab in Node-RED: how HA and Zigbee drive NVL commands and how the 328-byte buffer is built and sent to the PLC.
---
## Flow diagram
```
[Inject] ──► [trigger-state] ◄── HA entity: input_boolean.living_room_new
├──► [HA to NVL] ──┬──► [Build NVL_In] ──┬──► [link out 26] ──► (Flow 1: to UDP → PLC)
│ │ └──► debug 39
└──► debug 36 │
[Zigbee2MQTT] ──► [Zigbee to NVL] ──┼──► [Build NVL_In]
Living Room Door Switch │ ▲
(TS0044) ├──► [80ms delay] ──► [Clear zigbee edge] ──► [Build NVL_In]
│ │
└──► debug 40 └──► debug 41
```
- **HA path:** `trigger-state` watches `input_boolean.living_room_new`**HA to NVL** updates `flow.nvlInState.rooms.cmd_livingroom` (ha_lN_on / ha_lN_off) → **Build NVL_In** → link out → Flow 1 → UDP to PLC.
- **Zigbee path:** **zigbee2mqtt-in** (Living Room Door Switch TS0044) → **Zigbee to NVL** sets zigbee_swN in state → **Build NVL_In** (send) → then **80ms delay****Clear zigbee edge** (clear zigbee_swN) → **Build NVL_In** again (second packet so PLC sees one pulse).
---
## Nodes (Living Room tab)
| Node | Type | Role |
|------|------|------|
| **trigger-state** | node-red-contrib-home-assistant-websocket | Listens to `input_boolean.living_room_new`; output 1 → HA to NVL, output 2 → blocked. |
| **Inject** | inject | Manual/startup trigger into trigger-state (optional). |
| **HA to NVL** | function | Maps HA entity state to `cmd_livingroom` in `flow.nvlInState`; sets ha_l1_on/ha_l1_off … ha_l6_on/ha_l6_off from entity ID and payload; then `buildAndSend: true`. |
| **Zigbee to NVL** | function | Maps Zigbee action (single/double/hold/release/triple/quad) to zigbee_sw1…6; updates `flow.nvlInState.rooms.livingRoom`; sets `msg.zigbeeClear` for later clear; then `buildAndSend: true`. |
| **80ms** | delay | 80 ms then passes message to Clear zigbee edge. |
| **Clear zigbee edge** | function | Clears the zigbee_swN flag in `nvlInState` and sets `buildAndSend: true` again. |
| **Build NVL_In** | function | Reads `flow.nvlInState`, builds 328-byte buffer (16 rooms × 20 bytes + boiler 8 bytes), sets `msg.payload = buf`; outputs to link out 26 and debug. |
| **link out 26** | link out | Sends built buffer to Flow 1s **to UDP** link in → **udp out** (10.20.30.5:1202). |
| **debug 3641** | debug | Optional debug (37 active). |
---
## Shared state: `flow.nvlInState`
All rooms and boiler share one object:
- **Shape:** `{ rooms: { cmd_livingroom: { ha_l1_on, ha_l1_off, … }, … }, boiler: { … } }`
- **Living Room (HA test)** writes to `state.rooms.cmd_livingroom`. **Build NVL_In** reads the full object and serializes all 16 slots + boiler into the 328-byte NVL_In layout.
Room names order in Build NVL_In (must match PLC NVL):
`masterBedroom`, `masterBathroom`, `bedroom_1`, `bedroom_2`, `bathroom`, `guestWc`, `kitchen`, `pantry`, **`cmd_livingroom`**, `dinningRoom`, `entrance`, `hallway`, `outVeranda`, `outFront`, `outBack`, `outSide`.
---
## Test variable: `cmd_livingroom`
The flow uses **`cmd_livingroom`** (the NVL variable you added for testing), not `livingRoom`. HA to NVL writes to `flow.nvlInState.rooms.cmd_livingroom`, and Build NVL_In reads that key for the living-room slot in the 328-byte buffer (same 20-byte layout as struct_room_cmds).
---
## What the trigger-state must output to turn the light ON (PLC)
The **HA to NVL** node decides ON vs OFF from the message it receives. For the PLC to turn the light **on**:
| Field | Value |
|----------|--------|
| **payload** | `'on'` (string) **or** `true` (boolean) |
| **topic** | Entity ID (e.g. `input_boolean.living_room_new`). Optional for which light 16: if the last part after `_` is a number (e.g. `living_room_2` → 2), that light is used; otherwise light **1** is used. |
So the **trigger-state** should output to the first (allowed) output:
- **Turn ON:** `msg.payload === 'on'` or `msg.payload === true` → PLC gets `ha_lN_on = true` in **cmd_livingroom**.
- **Turn OFF:** any other payload (e.g. `'off'`, `false`) → PLC gets `ha_lN_off = true` in **cmd_livingroom**.
With the current entity `input_boolean.living_room_new` there is no `_1``_6`, so it always controls **light 1** in the living room.
---
## HA to NVL (function code)
- **Room (state key):** `cmd_livingroom` (NVL variable for testing).
- **Entity ID:** from `msg.topic` (e.g. `input_boolean.living_room_new`). Light index 16 is parsed from the last `_N` in the entity ID; default 1.
- **ON/OFF:** `msg.payload === 'on'` or `true` → set `ha_lN_on = true`, else `ha_lN_off = true` (the other cleared).
- Then sets `msg.payload = { buildAndSend: true }` and returns.
### Debug logs (in Node-RED Debug sidebar)
The function uses `node.warn()` so messages appear in the **Debug** tab (with the warning icon) without needing a separate debug node:
1. **On input:** `[HA to NVL] topic=... payload=... (type ...) → lightNum=... isOn=...`
Use this to confirm what the trigger-state sent: `topic`, `payload`, its type, and the parsed `lightNum` (16) and `isOn` (true/false).
2. **After state update:** `[HA to NVL] set cmd_livingroom ha_lN_on=true, buildAndSend` (or `ha_lN_off`).
Confirms which command was written and that `buildAndSend` is being passed on.
If `isOn` is false when you expect ON, check that the trigger-state output is exactly `'on'` (string) or `true` (boolean). If `topic` is wrong or missing, the light number may default to 1.
**HA to NVL function with debug:** full code in [ha-to-nvl-function.js](ha-to-nvl-function.js) (uses **cmd_livingroom**). Copy that files contents into the Node-RED function node.
---
## Zigbee to NVL (function code)
- **Room:** `livingRoom`.
- **Action map:** `single→1, double→2, hold→3, release→4, triple→5, quad→6` → sets `zigbee_swN`.
- **Edge behaviour:** Passes `msg.zigbeeClear = { room: 'livingRoom', key: 'zigbee_swN' }` so **Clear zigbee edge** (after 80 ms) clears that flag and calls **Build NVL_In** again; PLC sees one pulse.
---
## Build NVL_In (function code)
- **Buffer:** 328 bytes (Buffer.alloc(328)).
- **Rooms:** 16 rooms × 20 bytes each: bytes 011 = ha_l1_on, ha_l1_off, … ha_l6_off; bytes 1217 = zigbee_sw1…6; bytes 1819 = ha_all_on, ha_all_off.
- **Boiler:** offset 320: ha_on, ha_off, schedule_on, schedule_off, emergency_stop, (reserved), max_on_time_minutes (INT16 LE).
- **Output:** `msg.payload = buf`; wired to **link out 26** (and debug).
---
## Zigbee device
- **Friendly name:** Living Room Door Switch (TS0044)
- **Device ID:** 0xa4c1383d7921827a
- **Server:** zigbee2mqtt-server config (id 4e20fc347c658518)
---
## Do you need Build NVL_In?
**No, if you use the nvl-send node.** The nvl-send node (node-red-contrib-nvl) does the binary packing from a payload object. So you can:
1. **Remove** the **Build NVL_In** node and the **link out 26** (and the link in “to UDP” path that receives it).
2. **Add** a single function that builds the payload object from `flow.nvlInState` and feed that into **nvl-send****udp out**.
Code for that function (copy into a function node): **[state-to-nvl-send-payload.js](state-to-nvl-send-payload.js)**. It builds the object with the 15 `struct_switches` rooms (default false) and **cmd_livingroom** from `state.rooms.cmd_livingroom`. Wire: **HA to NVL / Zigbee to NVL****state-to-nvl-send-payload****nvl-send****udp out**.
---
## Syncing PLC state back to Home Assistant (Zigbee / any source → HA UI)
When you change a light with the **Zigbee switch** (or any source that doesnt go through HA), the PLC updates but HA doesnt, so entities can stay out of sync. To keep HA in sync for **all** mapped lights:
1. **After the nvl-receive node** (Flow 1), add a **function** node and paste the code from **[nvl-to-ha-sync-livingroom.js](nvl-to-ha-sync-livingroom.js)**.
2. In that function, **`LIGHT_ENTITY_MAP`** defines which PLC room/light → HA entity to sync. Each entry is `{ room: 'payloadKey', light: 1..6, entityId: 'domain.entity_id' }`. Add one row per light (any room/zone). Example:
- `{ room: 'light_livingRoom', light: 1, entityId: 'input_boolean.living_room_new' }`
- `{ room: 'l_kitchen', light: 1, entityId: 'light.kitchen_ceiling' }`
3. Give the function **2 outputs**. Then either:
**Option A Action node:** In the palette look under **Home Assistant** for **Action** ([docs](https://zachowj.github.io/node-red-contrib-home-assistant-websocket/node/action.html)). The sync already sends `payload.action` (e.g. `input_boolean.turn_on`) and `payload.target.entity_id` (array). Output 1 → **Action** (turn_on), Output 2 → **Action** (turn_off). You can leave Action config empty and use “Block Input Overrides” off so `msg.payload` sets the action and target.
**Option B HTTP:** Use **[nvl-to-ha-http-call.js](nvl-to-ha-http-call.js)** + **http request** node; set `flow.set('ha_base_url', 'http://HA_IP:8123')` and `flow.set('ha_token', 'YOUR_TOKEN')`.
The function only sends a message when a mapped lights state **changed**, so multiple entities can be updated in one NVL cycle. When you use the Zigbee switch (or the PLC changes state any other way), the matching HA entities are updated.
---
## Connection to Flow 1 (CODESYS)
- **Option A (with Build NVL_In):** Living Room builds the buffer in a function and sends it via **link out 26** → Flow 1 **link in "to UDP"****udp out**.
- **Option B (with nvl-send only):** HA to NVL / Zigbee to NVL → **state-to-nvl-send-payload****nvl-send****udp out**. No Build NVL_In, no link nodes needed for this path.
- The PLC (CODESYS) receives NVL_In on port 1202 and drives lights/boiler from the packed struct.
---
## File reference
- **Flows export:** [nodered-flows.json](nodered-flows.json) — Living Room tab id: `7de41d810b04d992`
- **Payload layout (PLC/Node-RED):** [codesys/src/NVL/nodered-payload.md](../../codesys/src/NVL/nodered-payload.md)