node-red-automation
Node-RED Automation
Expert guidance for Node-RED flow-based programming and automation.
When to Use This Skill
- Building smart home automations
- Creating API integrations
- Processing MQTT messages
- Building dashboards
- Connecting services and devices
- Data transformation and routing
Installation
# docker-compose.yml
version: '3.8'
services:
nodered:
image: nodered/node-red:latest
ports:
- "1880:1880"
volumes:
- ./node-red-data:/data
environment:
- TZ=America/New_York
restart: unless-stopped
# Native installation
npm install -g node-red
# Start
node-red
# Access at http://localhost:1880
Settings Configuration
// settings.js
module.exports = {
flowFile: 'flows.json',
// Admin auth
adminAuth: {
type: "credentials",
users: [{
username: "admin",
password: "$2b$08$...", // bcrypt hash
permissions: "*"
}]
},
// HTTP node auth
httpNodeAuth: {
user: "user",
pass: "$2b$08$..."
},
// HTTPS
https: {
key: require("fs").readFileSync('privkey.pem'),
cert: require("fs").readFileSync('cert.pem')
},
// Context storage
contextStorage: {
default: {
module: "localfilesystem"
}
},
// Function global context
functionGlobalContext: {
moment: require('moment')
}
}
Core Nodes
Inject Node
// Triggered flow
{
"payload": "Hello",
"topic": "greeting",
"repeat": "60", // Every 60 seconds
"crontab": "0 9 * * 1-5" // 9 AM weekdays
}
Function Node
// Basic transformation
msg.payload = msg.payload.toUpperCase();
return msg;
// Multiple outputs
var msg1 = { payload: msg.payload.value1 };
var msg2 = { payload: msg.payload.value2 };
return [msg1, msg2];
// Conditional routing
if (msg.payload > 100) {
return [msg, null]; // Output 1
} else {
return [null, msg]; // Output 2
}
// Access context
var count = context.get('count') || 0;
count++;
context.set('count', count);
msg.payload = count;
return msg;
// Flow context (shared across flow)
var data = flow.get('sharedData');
// Global context (shared across all flows)
var config = global.get('config');
// Async operation
node.send(msg);
return null; // Don't send twice
// Status
node.status({fill:"green", shape:"dot", text:"OK"});
node.status({fill:"red", shape:"ring", text:"Error"});
Switch Node
// Route based on property
{
"property": "payload.type",
"rules": [
{"t": "eq", "v": "temperature"},
{"t": "eq", "v": "humidity"},
{"t": "regex", "v": "^error"},
{"t": "else"}
]
}
Change Node
// Set, change, delete, move properties
{
"rules": [
{"t": "set", "p": "payload.processed", "to": true},
{"t": "change", "p": "payload", "from": "foo", "to": "bar"},
{"t": "delete", "p": "payload.temp"},
{"t": "move", "p": "payload.old", "to": "payload.new"}
]
}
Template Node
Temperature: {{payload.temperature}}°C
Humidity: {{payload.humidity}}%
Time: {{timestamp}}
{{#payload.items}}
- {{name}}: {{value}}
{{/payload.items}}
MQTT Integration
MQTT Nodes
// MQTT In
{
"topic": "sensors/+/temperature",
"qos": 1,
"broker": "mqtt-broker-config"
}
// MQTT Out
{
"topic": "commands/device1",
"qos": 1,
"retain": true
}
Flow: MQTT Processing
// Function: Parse MQTT message
var topic = msg.topic;
var parts = topic.split('/');
var deviceId = parts[1];
var measurement = parts[2];
msg.payload = {
device: deviceId,
type: measurement,
value: parseFloat(msg.payload),
timestamp: new Date().toISOString()
};
return msg;
Home Assistant Integration
Home Assistant Palette
# Install node-red-contrib-home-assistant-websocket
cd ~/.node-red
npm install node-red-contrib-home-assistant-websocket
HA Nodes
// Events: state
{
"entity_id": "sensor.temperature",
"state_type": "str",
"halt_if": "",
"halt_if_compare": "is"
}
// Call service
{
"domain": "light",
"service": "turn_on",
"data": {
"entity_id": "light.living_room",
"brightness_pct": 80
}
}
// Get current state
{
"entity_id": "sensor.temperature",
"state_type": "num"
}
Flow: Motion Light Automation
// When motion detected, turn on light for 5 minutes
// Events: state node -> Function -> Call service
// Function node
if (msg.payload === 'on') {
msg.payload = {
domain: 'light',
service: 'turn_on',
data: {
entity_id: 'light.hallway',
brightness_pct: 100
}
};
// Schedule turn off
var turnOff = {
payload: {
domain: 'light',
service: 'turn_off',
data: { entity_id: 'light.hallway' }
}
};
setTimeout(() => node.send([null, turnOff]), 300000);
return msg;
}
return null;
HTTP Integration
HTTP Nodes
// HTTP In - Create endpoint
// Method: GET, POST, etc.
// URL: /api/data
// HTTP Request - Call external API
{
"method": "GET",
"url": "https://api.example.com/data",
"headers": {
"Authorization": "Bearer {{flow.token}}"
}
}
// HTTP Response
msg.statusCode = 200;
msg.headers = { "Content-Type": "application/json" };
msg.payload = { status: "ok" };
return msg;
Flow: REST API Endpoint
// HTTP In -> Function -> HTTP Response
// Function: Handle API request
var response = {
success: true,
data: [],
timestamp: new Date().toISOString()
};
switch (msg.req.method) {
case 'GET':
response.data = flow.get('items') || [];
break;
case 'POST':
var items = flow.get('items') || [];
items.push(msg.payload);
flow.set('items', items);
response.data = msg.payload;
break;
}
msg.payload = response;
return msg;
Dashboard (node-red-dashboard)
npm install node-red-dashboard
// Button
{
"group": "Home",
"name": "Toggle Light",
"topic": "light/toggle",
"payload": "toggle"
}
// Gauge
{
"group": "Sensors",
"name": "Temperature",
"min": 0,
"max": 50,
"units": "°C"
}
// Chart
{
"group": "Sensors",
"name": "Temperature History",
"xaxis": "time",
"yaxis": "value"
}
// Text Input
{
"group": "Settings",
"name": "Set Threshold",
"mode": "number"
}
Common Patterns
Debounce
// Prevent rapid-fire messages
var timeout = context.get('timeout');
if (timeout) {
clearTimeout(timeout);
}
context.set('timeout', setTimeout(() => {
node.send(msg);
}, 1000));
return null;
Rate Limiting
// Limit to 1 message per 5 seconds
var lastTime = context.get('lastTime') || 0;
var now = Date.now();
if (now - lastTime > 5000) {
context.set('lastTime', now);
return msg;
}
return null;
State Machine
var state = flow.get('state') || 'idle';
var event = msg.payload;
switch(state) {
case 'idle':
if (event === 'start') {
flow.set('state', 'running');
msg.payload = 'Started';
return msg;
}
break;
case 'running':
if (event === 'stop') {
flow.set('state', 'idle');
msg.payload = 'Stopped';
return msg;
}
break;
}
return null;
Aggregation
// Collect messages and send batch
var buffer = context.get('buffer') || [];
buffer.push(msg.payload);
if (buffer.length >= 10) {
msg.payload = buffer;
context.set('buffer', []);
return msg;
}
context.set('buffer', buffer);
return null;
Error Handling
// Try-catch in function
try {
var data = JSON.parse(msg.payload);
msg.payload = data;
return [msg, null]; // Success output
} catch (e) {
msg.payload = { error: e.message };
return [null, msg]; // Error output
}
// Catch node - catches errors from nodes
// Complete node - triggers on node completion
Subflows
// Create reusable flow components
// Right-click -> Subflow -> Create subflow
// Add inputs/outputs
// Set environment variables
// Access subflow env in function:
var threshold = env.get('THRESHOLD') || 100;
Best Practices
- Name all nodes for readability
- Use link nodes to connect distant flows
- Add comments with Comment nodes
- Use subflows for reusable logic
- Handle errors with Catch nodes
- Use context storage for persistence
- Organize flows in tabs
- Version control flows.json
- Add status to function nodes
- Test with inject nodes
More from housegarofalo/claude-code-base
mqtt-iot
Configure MQTT brokers (Mosquitto, EMQX) for IoT messaging, device communication, and smart home integration. Manage topics, QoS levels, authentication, and bridging. Use when setting up IoT messaging, smart home communication, or device-to-cloud connectivity. (project)
22devops-engineer-agent
Infrastructure and DevOps specialist. Manages Docker, Kubernetes, CI/CD pipelines, and cloud deployments. Expert in GitHub Actions, Azure DevOps, Terraform, and container orchestration. Use for deployment automation, infrastructure setup, or CI/CD optimization.
6react-typescript
Build modern React applications with TypeScript. Covers React 18+ patterns, hooks, component architecture, state management (Zustand, Redux Toolkit), server components, and best practices. Use for React development, TypeScript integration, component design, and frontend architecture.
5svelte-kit
Expert guidance for SvelteKit 2 with Svelte 5 runes, server-side rendering, and modern patterns. Covers $state, $derived, $effect, form actions, load functions, and API routes. Use for SvelteKit applications, Svelte 5 runes, and full-stack Svelte development.
5matter-thread
>
5vitest
Fast Vite-native unit testing framework for JavaScript/TypeScript. ESM-first, Jest-compatible API, with instant HMR. Use for modern frontend testing, Vue/React/Svelte testing, or fast test execution. Triggers on vitest, vite test, vue test, svelte test.
5