$npx -y skills add tonylofgren/aurora-smart-home --skill node-redNode-RED visual automation flows for Home Assistant. Covers visual automation, flow JSON, trigger-state, api-call-service, function nodes, context storage, timer patterns, error handling, and node-red-contrib-home-assistant-websocket nodes. Use when user mentions "Node-RED", "flo
| 1 | # Node-RED for Home Assistant |
| 2 | |
| 3 | Build Node-RED flows using node-red-contrib-home-assistant-websocket nodes (v0.80+). |
| 4 | |
| 5 | **Requirements:** Node-RED 4.x (Node.js 18+), Home Assistant 2024.3.0+. |
| 6 | |
| 7 | ## The Iron Law |
| 8 | |
| 9 | ``` |
| 10 | USE CURRENT NODE NAMES - NEVER OUTDATED ONES |
| 11 | ``` |
| 12 | |
| 13 | The node-red-contrib-home-assistant-websocket package has renamed several nodes. Using old names produces broken flows that silently fail. |
| 14 | |
| 15 | ## Delivery Contract (read first, applies to every output) |
| 16 | |
| 17 | **Every flow ships as files in a project folder on disk. Chat output is not delivery.** A flow JSON pasted in chat is not a delivered flow. Create `<project-slug>/` (or write into the existing project folder in a multi-agent build), write the flow JSON under `node-red-flows/`, and write a `README.md` per Iron Law 3 in `../aurora/souls/river.md`. README sections follow `../aurora/references/deliverables/manual-format.md`: What this does, Installation, Troubleshooting, Recovery. No chat-only output option. |
| 18 | |
| 19 | ## The Process |
| 20 | |
| 21 | ``` |
| 22 | User request |
| 23 | │ |
| 24 | ▼ |
| 25 | HA server config node exists in Node-RED? |
| 26 | │ no ─────────────────────────┐ |
| 27 | │ yes ▼ |
| 28 | │ Set up `server` config first |
| 29 | │ (URL, access token, allow self-signed if needed) |
| 30 | │ │ |
| 31 | ▼ ◀────────────────────────────┘ |
| 32 | Pick trigger node (current names only — see table below) |
| 33 | │ |
| 34 | │ time-based? ──▶ inject (time) or trigger-state with cron |
| 35 | │ state-change? ──▶ trigger-state OR events:state |
| 36 | │ event? ──▶ events:all (filtered by event_type) |
| 37 | │ external? ──▶ http in (webhook) / mqtt in |
| 38 | │ |
| 39 | ▼ |
| 40 | Add filter/condition (current-state, switch, template) |
| 41 | │ |
| 42 | ▼ |
| 43 | Pick action node (current names only) |
| 44 | │ |
| 45 | │ call HA service? ──▶ call-service (`action`, not `service`) |
| 46 | │ set entity state? ──▶ call-service light.turn_on / etc. |
| 47 | │ send HTTP? ──▶ http request |
| 48 | │ notify? ──▶ call-service notify.* |
| 49 | │ |
| 50 | ▼ |
| 51 | Battery-drain risk? ──yes──▶ Add throttle/delay (rate-limit msgs/sec) |
| 52 | │ no |
| 53 | ▼ |
| 54 | Add status indicators (debug node OR catch node for error path) |
| 55 | │ |
| 56 | ▼ |
| 57 | Test in editor with debug node, fix wiring |
| 58 | │ |
| 59 | ▼ |
| 60 | Deploy and verify in HA |
| 61 | │ |
| 62 | ▼ |
| 63 | Document the flow (description on key nodes) |
| 64 | ``` |
| 65 | |
| 66 | ## Critical: Node Names Have Changed |
| 67 | |
| 68 | **STOP.** If you're about to use any of these node types, you're using outdated names: |
| 69 | |
| 70 | | WRONG (Old) | CORRECT (Current) | |
| 71 | |-------------|-------------------| |
| 72 | | `server-state-changed` | `trigger-state` or `events:state` | |
| 73 | | `poll-state` | `poll-state` (unchanged but check config) | |
| 74 | | `call-service` | `api-call-service` | |
| 75 | |
| 76 | ## Trigger Node Configuration (Current API) |
| 77 | |
| 78 | ```json |
| 79 | { |
| 80 | "type": "trigger-state", |
| 81 | "entityId": "binary_sensor.motion", |
| 82 | "entityIdType": "exact", |
| 83 | "constraints": [ |
| 84 | { |
| 85 | "targetType": "this_entity", |
| 86 | "propertyType": "current_state", |
| 87 | "comparatorType": "is", |
| 88 | "comparatorValue": "on" |
| 89 | } |
| 90 | ], |
| 91 | "outputs": 2 |
| 92 | } |
| 93 | ``` |
| 94 | |
| 95 | **entityIdType options:** `exact`, `substring`, `regex` |
| 96 | |
| 97 | **There is NO `list` type.** To monitor multiple entities, use `regex`: |
| 98 | ```json |
| 99 | "entityId": "binary_sensor\\.motion_(1|2|3)", |
| 100 | "entityIdType": "regex" |
| 101 | ``` |
| 102 | |
| 103 | ## Service Call Configuration (Current API) |
| 104 | |
| 105 | ```json |
| 106 | { |
| 107 | "type": "api-call-service", |
| 108 | "domain": "light", |
| 109 | "service": "turn_on", |
| 110 | "entityId": ["light.living_room"], |
| 111 | "data": "", |
| 112 | "dataType": "json" |
| 113 | } |
| 114 | ``` |
| 115 | |
| 116 | Or dynamic via msg: |
| 117 | ```json |
| 118 | { |
| 119 | "type": "api-call-service", |
| 120 | "domain": "", |
| 121 | "service": "", |
| 122 | "data": "", |
| 123 | "dataType": "msg" |
| 124 | } |
| 125 | ``` |
| 126 | |
| 127 | With function node before: |
| 128 | ```javascript |
| 129 | msg.payload = { |
| 130 | action: "light.turn_on", |
| 131 | target: { entity_id: ["light.living_room"] }, |
| 132 | data: { brightness_pct: 80 } |
| 133 | }; |
| 134 | return msg; |
| 135 | ``` |
| 136 | |
| 137 | ## Current State Node - Single Entity Only |
| 138 | |
| 139 | `api-current-state` queries **ONE entity**, not patterns. |
| 140 | |
| 141 | ```json |
| 142 | { |
| 143 | "type": "api-current-state", |
| 144 | "entity_id": "person.john" |
| 145 | } |
| 146 | ``` |
| 147 | |
| 148 | To check multiple entities, use function node: |
| 149 | ```javascript |
| 150 | const ha = global.get("homeassistant").homeAssistant.states; |
| 151 | const people = Object.keys(ha) |
| 152 | .filter(id => id.startsWith("person.")) |
| 153 | .filter(id => ha[id].state !== "home"); |
| 154 | msg.awayPeople = people; |
| 155 | return msg; |
| 156 | ``` |
| 157 | |
| 158 | ## Entity Nodes Require Extra Integration |
| 159 | |
| 160 | The following nodes require `hass-node-red` integration (separate from the websocket nodes): |
| 161 | - `ha-entity` (sensor, binary_sensor, switch, etc.) |
| 162 | - Entity config nodes |
| 163 | |
| 164 | **Always mention this prerequisite when using entity nodes.** |
| 165 | |
| 166 | ## Stable Entity Nodes (v0.71.0+) |
| 167 | |
| 168 | These nodes were promoted from beta to s |