Claude Code Plugins

Community-maintained marketplace

Feedback

>

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

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)

{
  "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:

"entityId": "binary_sensor\\.motion_(1|2|3)",
"entityIdType": "regex"

Service Call Configuration (Current API)

{
  "type": "api-call-service",
  "domain": "light",
  "service": "turn_on",
  "entityId": ["light.living_room"],
  "data": "",
  "dataType": "json"
}

Or dynamic via msg:

{
  "type": "api-call-service",
  "domain": "",
  "service": "",
  "data": "",
  "dataType": "msg"
}

With function node before:

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.

{
  "type": "api-current-state",
  "entity_id": "person.john"
}

To check multiple entities, use function node:

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:

{
  "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:

// settings.js - requires Node-RED restart
functionGlobalContext: {
    axios: require('axios')
}

CORRECT: Use the built-in http request node instead:

{
  "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:
// 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
// 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:

contextStorage: {
    default: { module: "localfilesystem" }
}

Error Handling Pattern

Use catch node scoped to specific nodes:

{
  "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?