nodered

SKILL.md

Node-RED

Node-RED is a flow-based programming tool for event-driven applications, enabling visual wiring of nodes to create automation workflows.

Core Concepts

Message Object

Messages flow between nodes via msg object:

{
  payload: "data",      // Primary data
  topic: "category",    // Message type/category
  _msgid: "abc123"      // Auto-generated ID
}

Node Types

  • Input: Inject, HTTP In, MQTT In - initiate flows
  • Processing: Function, Change, Switch - transform data
  • Output: Debug, HTTP Response, MQTT Out - send results
  • Utility: Delay, Trigger, Split/Join - control flow

Flow JSON Structure

Flows stored in flows.json:

[
  {
    "id": "node-uuid",
    "type": "inject",
    "name": "Timer",
    "repeat": "5",
    "payload": "hello",
    "payloadType": "str",
    "x": 100,
    "y": 100,
    "wires": [["next-node-id"]]
  },
  {
    "id": "next-node-id",
    "type": "debug",
    "name": "Output",
    "active": true,
    "complete": "payload",
    "x": 300,
    "y": 100,
    "wires": []
  }
]

Key properties:

  • id: Unique UUID
  • type: Node type name
  • x, y: Editor position
  • wires: Array of arrays mapping outputs to next node inputs

Function Node

Execute JavaScript with full context access:

// Access message
const data = msg.payload;

// Modify message
msg.payload = data.toUpperCase();
msg.timestamp = Date.now();

// Send to output
return msg;

// Multiple outputs
return [msg1, msg2];

// Send nothing
return null;

Context Storage

// Node context (this node only)
context.set("key", value);
const val = context.get("key");

// Flow context (all nodes in flow)
flow.set("counter", 0);
const count = flow.get("counter");

// Global context (all flows)
global.set("config", {});
const cfg = global.get("config");

Async Operations

// Using async/await
const result = await someAsyncFunction();
msg.payload = result;
return msg;

// Using node.send() for async
someAsyncFunction().then(result => {
  msg.payload = result;
  node.send(msg);
});
return null;  // Don't return msg here

Common Nodes

Change Node

Modify message properties without code:

  • Set: msg.payload to value
  • Change: Replace text in property
  • Move: Rename property
  • Delete: Remove property

Switch Node

Route messages based on conditions:

  • ==, !=, <, >, <=, >=
  • contains, matches regex
  • is null, is not null
  • is of type (string, number, etc.)

Template Node

Mustache templating:

Hello {{payload.name}}!
Temperature: {{payload.temp}}°C

Integrations

MQTT

Subscribe (MQTT In):

Topic: home/sensors/#
QoS: 0/1/2
Output: parsed JSON or string

Publish (MQTT Out):

Topic: home/commands/light
Retain: true/false
QoS: 0/1/2

HTTP

Create endpoint (HTTP In → HTTP Response):

Method: GET/POST/PUT/DELETE
URL: /api/data

Make request (HTTP Request):

Method: GET
URL: https://api.example.com/data
Return: parsed JSON

WebSocket

Real-time bidirectional communication:

  • WebSocket In: Listen for messages
  • WebSocket Out: Send to clients

Debugging

Debug Node

  • Output to sidebar panel
  • Show complete msg or specific property
  • Add to status bar

Console Logging

// In function node
node.warn("Warning message");   // Yellow, shows in debug
node.error("Error message");    // Red, triggers catch
console.log(msg);               // Terminal only

Status Indicators

node.status({
  fill: "green",    // green, yellow, red, grey
  shape: "dot",     // dot, ring
  text: "connected"
});
node.status({});    // Clear status

Error Handling

Catch Node

Catches errors from nodes in same flow:

[Any Node] → error → [Catch Node] → [Handle Error]

Try/Catch in Function

try {
  const result = JSON.parse(msg.payload);
  msg.payload = result;
  return msg;
} catch (e) {
  node.error("Parse failed: " + e.message, msg);
  return null;
}

Configuration (settings.js)

Location: ~/.node-red/settings.js

module.exports = {
  // Server
  uiPort: 1880,
  httpAdminRoot: '/admin',
  httpNodeRoot: '/api',

  // Flows
  flowFile: 'flows.json',
  credentialSecret: "your-secret-key",

  // Security
  adminAuth: {
    type: "credentials",
    users: [{
      username: "admin",
      password: "$2b$08$hash...",  // bcrypt hash
      permissions: "*"
    }]
  },

  // Logging
  logging: {
    console: { level: "info" }
  },

  // Context storage
  contextStorage: {
    default: { module: "memory" },
    persistent: { module: "localfilesystem" }
  },

  // Function node globals
  functionGlobalContext: {
    moment: require('moment'),
    _: require('lodash')
  }
};

Home Assistant Integration

Use node-red-contrib-home-assistant-websocket:

Call Service Node

Domain: light
Service: turn_on
Entity: light.living_room
Data: {"brightness": 255}

Entity Node

Monitor state changes:

Entity: sensor.temperature
Output on: state change

Get Entities Node

Query current state:

Search: entity_id contains "light"
Output: array of entities

Reference

Weekly Installs
8
Repository
szkocot/skills
First Seen
Jan 28, 2026
Installed on
opencode6
gemini-cli6
codex6
github-copilot5
cursor5
antigravity4