Skip to content

Node-RED Trigger Flow

Node-RED Trigger Flow

This section covers the Node-RED flow that receives and processes button press messages from the IoT button. By the end of this section, you will be able to:

  • Create an MQTT In node to receive button messages
  • Implement a toggle switch logic for on/off actions
  • Integrate with Shelly relays or other smart devices
  • Deploy and test the complete button-to-action flow

Before starting this section, please ensure:

  • Node-RED is installed and running (see Chapter 09)
  • MQTT broker is configured (Mosquitto)
  • Completed 04-08. MQTT Message Transmission
  • Basic familiarity with Node-RED flows

The button trigger flow follows a simple chain:

[MQTT In] → [Function: Parse] → [Toggle Node] → [MQTT Out: Shelly]
│ │
└─────────────┴──→ [Debug] (monitoring)
NodeTypePurpose
MQTT Inmqtt inSubscribe to button topic
Parse JSONfunctionExtract button data from JSON payload
Togglenode-red-contrib-toggleSwitch on/off state
MQTT Outmqtt outSend command to Shelly/device
DebugdebugMonitor incoming messages
Terminal window
# In Node-RED container or installation directory
cd ~/.node-red
npm install node-red-contrib-toggle
npm install node-red-contrib-shelly # Optional, for Shelly integration

Then restart Node-RED.

Configuration:

  • Node: MQTT In
  • Topic: factory/button/#
  • Output: a parsed JSON object
  • Name: Button Press
  • Server: Your Mosquitto broker (select or add MQTT broker config)
╔══════════════════════════════════════════════════╗
║ [MQTT In] ║
║ ║
║ Server: Mosquitto (localhost:1883) ║
║ Topic: factory/button/# ║
║ QoS: 1 ║
║ Output: Auto-detect (JSON string) ║
║ ║
║ Name: Button Press ║
╚══════════════════════════════════════════════════╝

The # wildcard subscribes to all button topics, allowing multiple buttons to use the same flow.

// Parse incoming button message
// Input: msg.payload = JSON string
// Output: msg.payload = parsed object
// The button sends: {"button_id":"BTN-001","action":"toggle","battery_voltage":3.85}
try {
// Parse JSON payload (if not already an object)
let data = typeof msg.payload === 'string'
? JSON.parse(msg.payload)
: msg.payload;
// Extract button information
msg.buttonId = data.button_id;
msg.batteryVoltage = data.battery_voltage;
msg.batteryPercent = data.battery_percent;
// Log battery status
if (data.battery_percent < 20) {
node.warn(`Low battery: ${data.button_id} at ${data.battery_percent}%`);
}
// Set payload to trigger toggle
msg.payload = {
action: data.action || "toggle",
source: data.button_id
};
return msg;
} catch (error) {
node.error("Parse error: " + error.message, msg);
return null;
}

Node Configuration:

  • Node: Function
  • Name: Parse Button Data
  • Outputs: 1

The node-red-contrib-toggle maintains a state and toggles it each time it receives a message.

Configuration:

  • Node: Toggle
  • Topic: toggle (or leave blank)
  • Output values:
    • On value: {"state": "ON", "source": "button"}
    • Off value: {"state": "OFF", "source": "button"}
  • Initial state: off
  • Random: false
  • Name: Toggle Relay
╔══════════════════════════════════════════════════╗
║ [Toggle] ║
║ ║
║ Start State: off ║
║ Payload On: {"state":"ON"} ║
║ Payload Off: {"state":"OFF"} ║
║ ║
║ Name: Toggle Relay ║
╚══════════════════════════════════════════════════╝

Configuration:

  • Node: MQTT Out
  • Topic: shellies/shelly1-ABC123/relay/0/command
  • QoS: 1
  • Retain: false
  • Name: Shelly Command
  • Server: Same Mosquitto broker

Note: Replace the Shelly topic with your actual Shelly device topic.

For easy import, here’s the complete flow:

[
{
"id": "btn_mqtt_in",
"type": "mqtt in",
"topic": "factory/button/#",
"qos": "1",
"datatype": "auto",
"broker": "your_broker_id",
"name": "Button Press",
"x": 100,
"y": 100,
"wires": [["btn_parse"]]
},
{
"id": "btn_parse",
"type": "function",
"func": "try {\n let data = typeof msg.payload === 'string' ? JSON.parse(msg.payload) : msg.payload;\n msg.buttonId = data.button_id;\n msg.batteryVoltage = data.battery_voltage;\n if (data.battery_percent < 20) {\n node.warn(`Low battery: ${data.button_id} at ${data.battery_percent}%`);\n }\n msg.payload = {action: data.action || 'toggle', source: data.button_id};\n return msg;\n} catch (error) {\n node.error('Parse error: ' + error.message, msg);\n return null;\n}",
"outputs": 1,
"name": "Parse Button Data",
"x": 300,
"y": 100,
"wires": [["btn_toggle"]]
},
{
"id": "btn_toggle",
"type": "toggle",
"name": "Toggle Relay",
"topic": "",
"onvalue": "{\"state\":\"ON\"}",
"onvalueType": "json",
"offvalue": "{\"state\":\"OFF\"}",
"offvalueType": "json",
"onstartup": false,
"startstate": "off",
"random": false,
"x": 500,
"y": 100,
"wires": [["btn_mqtt_out"]]
},
{
"id": "btn_mqtt_out",
"type": "mqtt out",
"topic": "shellies/shelly1-ABC123/relay/0/command",
"qos": "1",
"retain": "false",
"broker": "your_broker_id",
"name": "Shelly Command",
"x": 700,
"y": 100,
"wires": []
},
{
"id": "btn_debug",
"type": "debug",
"name": "Button Monitor",
"active": true,
"tosidebar": true,
"console": false,
"x": 500,
"y": 200,
"wires": []
}
]

Import this JSON into Node-RED using the Import menu (hamburger menu → Import → Clipboard).

  1. Deploy the flow in Node-RED
  2. Press the IoT button (or simulate with MQTT Explorer)
  3. Observe the debug panel for incoming messages
  4. Verify the Shelly device toggles on/off with each press

Manual test using MQTT CLI:

Terminal window
# Simulate button press
mosquitto_pub -h localhost -t "factory/button/01/press" \
-m '{"button_id":"BTN-001","action":"toggle","battery_voltage":3.85,"battery_percent":85}'

For demonstration purposes, add an Inject node that simulates a button press:

[Inject Node]
Button: Click to simulate press
Payload: {"button_id":"BTN-DEMO","action":"toggle","battery_voltage":3.85,"battery_percent":85}
Repeat: none
Name: Simulate Button

To support multiple buttons, add an MQTT In node with a wildcard topic and route by button ID:

// Function node: Route by button
let buttonId = msg.buttonId || "unknown";
switch(buttonId) {
case "BTN-001":
msg.topic = "shellies/shelly1-ABC123/relay/0/command";
break;
case "BTN-002":
msg.topic = "shellies/shelly1-DEF456/relay/0/command";
break;
default:
node.warn("Unknown button: " + buttonId);
return null;
}
return msg;
  • MQTT In node receives button messages
  • Toggle node switches state on each press
  • Shelly (or target device) responds correctly
  • Debug panel shows parsed data
  • Multiple presses alternate on/off consistently

Symptom: Debug panel shows nothing when button is pressed

Possible Causes:

  • MQTT broker connection issue
  • Topic mismatch
  • MQTT In node not connected to correct broker

Solution:

Terminal window
# Test directly with mosquitto_sub
mosquitto_sub -h localhost -t "factory/button/#" -v
# If no output here, the button isn't publishing
# Check WiFi credentials and MQTT broker on the ESP32

Symptom: Messages arrive but Shelly doesn’t toggle

Possible Causes:

  • Toggle output values don’t match Shelly expectations
  • MQTT Out node topic is wrong
  • Shelly not connected to MQTT

Solution: Bypass the toggle and send a direct command to verify:

Terminal window
# Test Shelly directly
mosquitto_pub -h localhost -t "shellies/shelly1-ABC123/relay/0/command" -m "on"
mosquitto_pub -h localhost -t "shellies/shelly1-ABC123/relay/0/command" -m "off"
  • Use wildcard topics (#) for multi-button installations
  • Include battery monitoring in the flow to send low-battery alerts
  • Add a notification node (email, SMS) for important button events
  • Store toggle state in flow context to survive Node-RED restarts
  • Do not use retained messages for button events
  • Avoid complex logic in the flow — keep it simple and reliable
  1. Node-RED receives button presses via MQTT In node with wildcard topic
  2. Toggle node provides on/off state switching with each press
  3. MQTT Out node sends commands to Shelly or other smart devices
  4. Battery monitoring can be integrated for proactive maintenance
  5. Multi-button support is easy with topic routing in a function node

Target Audience: Alibaba.com IoT Pre-sales Engineers
Status: ✅ Completed