home / skills / tonylofgren / aurora-smart-home / node-red
This skill helps you build Node-RED flows for Home Assistant using up-to-date node types and flow configuration.
npx playbooks add skill tonylofgren/aurora-smart-home --skill node-redReview the files below or copy the command above to add this skill to your agents.
---
name: node-red
description: >
Use when user mentions "node-red" anywhere in their request (including
compound words like "node-redflöde", "node-red-flow"). The term "Node-RED"
is a product name that appears unchanged in all languages.
NOT for: YAML automations (use home-assistant skill), device firmware (use esphome skill).
---
# Node-RED for Home Assistant
Build Node-RED flows using node-red-contrib-home-assistant-websocket nodes.
## First Step: Clarify Platform
**If the user's request does NOT explicitly mention "Node-RED" or "flow", ASK:**
> "Do you want this as:
> 1. **Node-RED flow** (visual, drag-drop, importable JSON)
> 2. **Home Assistant YAML** (automations.yaml, scripts.yaml)
> 3. **ESPHome config** (device firmware for ESP32/ESP8266)"
**NEVER assume Node-RED.** A request like "make a motion light" could be any of these.
Only proceed with this skill if user confirms Node-RED.
## Critical: Node Names Have Changed
**STOP.** If you're about to use any of these node types, you're using outdated names:
| WRONG (Old) | CORRECT (Current) |
|-------------|-------------------|
| `server-state-changed` | `trigger-state` or `events:state` |
| `poll-state` | `poll-state` (unchanged but check config) |
| `call-service` | `api-call-service` |
## Trigger Node Configuration (Current API)
```json
{
"type": "trigger-state",
"entityId": "binary_sensor.motion",
"entityIdType": "exact",
"constraints": [
{
"targetType": "this_entity",
"propertyType": "current_state",
"comparatorType": "is",
"comparatorValue": "on"
}
],
"outputs": 2
}
```
**entityIdType options:** `exact`, `substring`, `regex`
**There is NO `list` type.** To monitor multiple entities, use `regex`:
```json
"entityId": "binary_sensor\\.motion_(1|2|3)",
"entityIdType": "regex"
```
## Service Call Configuration (Current API)
```json
{
"type": "api-call-service",
"domain": "light",
"service": "turn_on",
"entityId": ["light.living_room"],
"data": "",
"dataType": "json"
}
```
Or dynamic via msg:
```json
{
"type": "api-call-service",
"domain": "",
"service": "",
"data": "",
"dataType": "msg"
}
```
With function node before:
```javascript
msg.payload = {
action: "light.turn_on",
target: { entity_id: ["light.living_room"] },
data: { brightness_pct: 80 }
};
return msg;
```
## Current State Node - Single Entity Only
`api-current-state` queries **ONE entity**, not patterns.
```json
{
"type": "api-current-state",
"entity_id": "person.john"
}
```
To check multiple entities, use function node:
```javascript
const ha = global.get("homeassistant").homeAssistant.states;
const people = Object.keys(ha)
.filter(id => id.startsWith("person."))
.filter(id => ha[id].state !== "home");
msg.awayPeople = people;
return msg;
```
## Entity Nodes Require Extra Integration
The following nodes require `hass-node-red` integration (separate from the websocket nodes):
- `ha-entity` (sensor, binary_sensor, switch, etc.)
- Entity config nodes
**Always mention this prerequisite when using entity nodes.**
## Timer Pattern (Motion Light)
Use single trigger node with `extend: true`:
```json
{
"type": "trigger",
"op1type": "nul",
"op2": "timeout",
"op2type": "str",
"duration": "5",
"extend": true,
"units": "min"
}
```
**Do NOT create separate reset/start timer nodes.** The `extend` property handles this.
## Flow JSON Guidelines
1. **Never include server config node** - User configures separately
2. **Leave `server` field empty** - User selects their server
3. **Use placeholder entity IDs** - Document what to change
4. **Add comment node** - Explain required configuration
## Function Node: External Libraries
**WRONG:** Using `global.get('axios')` or similar for HTTP requests.
This requires manual configuration in `settings.js`:
```javascript
// settings.js - requires Node-RED restart
functionGlobalContext: {
axios: require('axios')
}
```
**CORRECT:** Use the built-in `http request` node instead:
```json
{
"type": "http request",
"method": "GET",
"url": "https://api.example.com/data",
"ret": "obj"
}
```
**When you MUST use function node for HTTP:**
- Complex request logic that can't be handled by http request node
- Requires settings.js configuration (warn user!)
- Use `node.send()` and `node.done()` for async:
```javascript
// Async pattern in function node
const axios = global.get('axios'); // Requires settings.js config!
async function fetchData() {
try {
const response = await axios.get(msg.url);
msg.payload = response.data;
node.send(msg);
} catch (error) {
node.error(error.message, msg);
}
node.done();
}
fetchData();
return null; // Prevent sync output
```
## Context Storage
Three scopes available:
| Scope | Syntax | Shared With |
|-------|--------|-------------|
| Node | `context.get/set()` | Only this node |
| Flow | `flow.get/set()` | All nodes in tab |
| Global | `global.get/set()` | All flows |
```javascript
// Store state
flow.set('machineState', 'washing');
flow.set('history', historyArray);
// Retrieve
const state = flow.get('machineState') || 'idle';
```
**For persistence across restarts**, configure in settings.js:
```javascript
contextStorage: {
default: { module: "localfilesystem" }
}
```
## Error Handling Pattern
Use `catch` node scoped to specific nodes:
```json
{
"type": "catch",
"scope": ["call_service_node_id"],
"uncaught": false
}
```
Error info available in `msg.error`:
- `msg.error.message` - Error text
- `msg.error.source.id` - Node that threw error
- `msg.error.source.type` - Node type
**Retry pattern:** Use `delay` node with `delayv` type to read delay from `msg.delay`.
## Common Mistakes Table
| Mistake | Reality |
|---------|---------|
| Using `server-state-changed` | Node renamed to `trigger-state` |
| `entityIdType: "list"` | No such type. Use `regex` for multiple entities |
| `api-current-state` with pattern | Only accepts single entity_id |
| Using `ha-entity` without warning | Requires separate hass-node-red integration |
| Complex timer reset logic | Use `extend: true` on trigger node |
| `dataType: "jsonata"` for service data | Use `msg` when passing dynamic payload |
| `global.get('axios')` for HTTP | Use http request node, or warn about settings.js |
| `return msg` in async function | Use `node.send(msg)` + `node.done()` + `return null` |
## Pre-Output Checklist
Before outputting flow JSON:
- [ ] Using current node type names?
- [ ] Entity filtering uses valid type (exact/substring/regex)?
- [ ] Service call has domain/service OR uses msg payload correctly?
- [ ] Single entity nodes don't assume pattern matching?
- [ ] Entity nodes mention hass-node-red requirement?
- [ ] Server field left empty for user configuration?
This skill helps create and validate Node-RED flows for Home Assistant using node-red-contrib-home-assistant-websocket nodes. It focuses on current node names, correct configuration patterns, and safe defaults so flows import cleanly and work as expected. It also guides decisions when automation could instead be YAML or ESPHome.
I inspect requested automation goals and confirm whether you explicitly want a Node-RED flow or one of the alternatives (Home Assistant YAML or ESPHome). I produce importable flow JSON with placeholder entity IDs, leave the server field empty, and include comment nodes explaining required edits. I also flag deprecated node names, required integrations (like hass-node-red for entity nodes), and async/function-node pitfalls.
Do you assume Node-RED if I just say 'motion light'?
No. I will ask whether you want a Node-RED flow, Home Assistant YAML, or an ESPHome device config before producing a flow.
Can api-current-state check patterns or multiple entities?
No. api-current-state only accepts a single entity_id; use regex in trigger-state or iterate with a function node for multiple entities.