This is of limited usefulness as I never got the Node Red on the NSPP to connect to the same NSPP it would however connect to an iHost on the same network and the iHost Node Red could connect to both. Thought I’d post my learning anyway. Suspect the solution is via Matter whereby the NS Panel pro put things on matter and they are secondarily commissioned by a matter palette in Node Red, but haven’t had the energy since doing this to find a working matter palette and have no devices attached to the NSPP to test it
Plan: Auto‑Start Node‑RED and MQTT on Sonoff NS Panel Pro
This works on firmware V4.0.0 and above (as F‑Droid is built in).
You’ll only need to type a few commands on the panel’s touchscreen. After that, you can do everything from your computer.
Step 1 – Install Termux (on the panel, via touchscreen)
Open Termux (install from F‑Droid store)
step 2 - install ssh in termux |(on the panel)
type in it on on screen keyboard on the NSPP
- “pkg update && pkg upgrade”
- “pkg install openssh”
Step 3 – Enable SSH (still on the panel)
Set a password for the Termux user (you’ll use this to log in):
in termux type
- “passwd”
(Type your chosen password twice – you won’t see characters as you type.)
Start the SSH server: - “sshd”
- “whoami”
- “pwd”
take photo of your username and baseline path.
That’s it. SSH is now running on port 8022 and you know who you are and where you are.
Step 4 – leave it running and Connect from Your Computer (do not kill termux)
This is easiest if the address is static (IP v4) on your router
On the panel, find its IP address (e.g., 192.168.x.x). You can check this in the eWeLink app, by running ifconfig in Termux or often from your router.
From your laptop/computer, open a terminal and connect:
“ssh -p 8022 username-fromphoto@ipv4-address”
it will ask you for the password you set earlier
You’re now in! From here on, every command can be typed on your computer’s proper keyboard – just copy & paste.
step 5 install other packages
- “pkg install termux-services nodejs-lts cronie nano git”
Step 6 – Install Node‑RED
“npm config set unsafe-perm true”
“npm install -g --unsafe-perm node-red”
Step 7 – Create the Auto‑Start Script
- “nano ~/start_node_red.sh”
Paste this: - -----------------start----------------
#!/bin/bash
Log everything to a file in your home
exec >> ~/node_red_cron.log 2>&1
Set PATH so cron can find Node‑RED
export PATH=/data/data/com.termux/files/usr/bin:$PATH
export HOME=/data/data/com.termux/files/home
echo “$(date): Cron ran the script”
Only start Node‑RED if it’s not already running
if ! pgrep -f “node-red” > /dev/null; then
nohup node-red --max-old-space-size=512 >/dev/null 2>&1 &
echo “$(date): Node‑RED was not running, started it”
fi"
-------------end--------------------
Save the new file (Ctrl+O, Enter) and exit (Ctrl+X).
Make it executable:
3) “chmod +x ~/start_node_red.sh”
Step 8 – Set Up a timer (to check every 5 minutes. I’ve chosen 5 minutes, but you can change it. For example, “*/1 * * * *” runs every 1 minute if you need faster recovery.)
- “sv-enable crond”
- “sv up crond”
Edit your crontab: - “crontab -e”
Add this line: - “*/5 * * * * /data/data/com.termux/files/home/start_node_red.sh”
Save and exit.(CTRL O, RETURN and CTRL X)
Step 9 – Test the script by running it manually
- “~/start_node_red.sh”
Wait a couple of minutes, then check the log:
“cat ~/node_red_cron.log”
You should see timestamps every 5 minutes. Node‑RED will now restart automatically if it crashes or the panel reboots.
step 10 keeping SSH alive
- ‘echo “sshd” >> ~/.bashrc’
- “termux-wake-lock”
After a full reboot, you’ll need to open Termux once to trigger .bashrc as termux is dead and your SSH is into Termux not the device itself. The wake‑lock then keeps it alive in the background as long as you don’t kill it
step 11) return to homescreen and exit ssh
- “am start -a android.intent.action.MAIN -c android.intent.category.HOME”
- “exit”
step 12) change settings file to add a password and have a save to file option.
- “nano ~/.node-red/settings.js”
find and change
1)
’
//adminAuth: {
// type: “credentials”,
// users: [{
// username: “admin”,
// password: “$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN.”,
// permissions: “*”
// }]
//},
’
to (same indentation as active section above and below)
’
adminAuth: {
type: “credentials”,
users: [{
username: “chosen-username”,
password: “hash-of-password”,
permissions: “*”
}]
},
’
I’d suggest a password of 8-20 length and avoid symbols to hide from possible interpretation issues but no reason really. It should be okay 1 - 72 characters including symbols. The password can be hashed on your computer, online or the NSPP itself, Just remember where it says password is actually the hash, not the password. It is possible to use the wrong type of hash. Node-RED requires a “bcrypt” hash (recognised by starting with “$2a$”, “$2b$”, or “$2y$”). Copy the entire line and not just the hash. on Linux you can run “npx node-red-admin hash-pw” if you have nodejs and npm installed (sudo pacman -S nodejs npm on Arch Linux).
and
’
//contextStorage: {
// default: {
// module:“localfilesystem”
// },
//},
’
to
’
contextStorage: {
default: “memoryOnly”,
memoryOnly: {
module: “memory”
},
fileStore: {
module: “localfilesystem”,
config: {
flushInterval: 30 //The flushInterval of 30 seconds means data is written to disk every 30 seconds. You can adjust this if you need more or less frequent writes
}
}
},
’
saving this file after the edits. (CTRL O, RETURN and CTRL X)
kill the process so it starts with the new config next time
‘pkill -f “node-red”’
no need to restart it as It will start automatically in five minutes or less so go get a coffee. It’s a good place for a break.
step 13) – Access Node‑RED webpage
Open a browser on the same network and go to:
yourNSPP-ipV4-address:1880
(Use your NS panel pro’s actual IP v4 address you know from earlier.)
step 14) install MQTT palette etc (node-red-contrib-aedes)
In hamburger-symbol>Manage palette on the Node Red web interface → Install:
-
node-red-contrib-os - System monitoring
-
node-red-contrib-moving-average - Data analytics
-
node-red-contrib-aedes - MQTT broker (port 1888)
I’ve chosen port 1888 (instead of the default 1883) to avoid any potential conflict with eWeLink’s built‑in MQTT usage on port 1883.
step 15) import starter flows
This flow includes system monitoring (CPU, memory, network) and a working MQTT broker. You can use it as a starting point for your own automations.
NR webpage>hambuger-symbol>“import” copy and paste this
-------------------------------------------start---------------------------------------------
[
{
“id”: “643b47c11224f8b5”,
“type”: “tab”,
“label”: “System”,
“disabled”: false,
“info”: “”,
“env”: []
},
{
“id”: “c6e5631c9ad3e525”,
“type”: “tab”,
“label”: “MQTT”,
“disabled”: false,
“info”: “”,
“env”: []
},
{
“id”: “a98f4ed9c18c8b27”,
“type”: “mqtt-broker”,
“name”: “Local Aedes Broker”,
“broker”: “localhost”,
“port”: “1888”,
“clientid”: “”,
“autoConnect”: true,
“usetls”: false,
“protocolVersion”: 4,
“keepalive”: 60,
“cleansession”: true,
“autoUnsubscribe”: true,
“birthTopic”: “”,
“birthQos”: “0”,
“birthRetain”: “false”,
“birthPayload”: “”,
“birthMsg”: {},
“closeTopic”: “”,
“closeQos”: “0”,
“closeRetain”: “false”,
“closePayload”: “”,
“closeMsg”: {},
“willTopic”: “”,
“willQos”: “0”,
“willRetain”: “false”,
“willPayload”: “”,
“willMsg”: {},
“userProps”: “”,
“sessionExpiry”: “”
},
{
“id”: “aa6bb613f2151df9”,
“type”: “inject”,
“z”: “643b47c11224f8b5”,
“name”: “”,
“props”: [
{
“p”: “payload”
},
{
“p”: “topic”,
“vt”: “str”
}
],
“repeat”: “300”,
“crontab”: “”,
“once”: true,
“onceDelay”: 0.1,
“topic”: “”,
“payload”: “”,
“payloadType”: “date”,
“x”: 270,
“y”: 180,
“wires”: [
[
“dd9e00343fbb2b16”
]
]
},
{
“id”: “feaeb2a4bee30ed7”,
“type”: “debug”,
“z”: “643b47c11224f8b5”,
“name”: “Memory Stats”,
“active”: true,
“tosidebar”: true,
“console”: false,
“tostatus”: false,
“complete”: “payload”,
“targetType”: “msg”,
“statusVal”: “”,
“statusType”: “auto”,
“x”: 620,
“y”: 180,
“wires”: []
},
{
“id”: “dd9e00343fbb2b16”,
“type”: “Memory”,
“z”: “643b47c11224f8b5”,
“name”: “”,
“scale”: “Byte”,
“x”: 420,
“y”: 180,
“wires”: [
[
“feaeb2a4bee30ed7”,
“ba46d9bbc8152978”
]
]
},
{
“id”: “fca702b5c2f7d24e”,
“type”: “OS”,
“z”: “643b47c11224f8b5”,
“name”: “”,
“x”: 410,
“y”: 140,
“wires”: [
[
“9e89bd95de26b935”
]
]
},
{
“id”: “1e65cae5d73c272a”,
“type”: “inject”,
“z”: “643b47c11224f8b5”,
“name”: “”,
“props”: [
{
“p”: “payload”
},
{
“p”: “topic”,
“vt”: “str”
}
],
“repeat”: “”,
“crontab”: “”,
“once”: false,
“onceDelay”: 0.1,
“topic”: “”,
“payload”: “”,
“payloadType”: “date”,
“x”: 260,
“y”: 140,
“wires”: [
[
“fca702b5c2f7d24e”
]
]
},
{
“id”: “9e89bd95de26b935”,
“type”: “debug”,
“z”: “643b47c11224f8b5”,
“name”: “OS info”,
“active”: true,
“tosidebar”: true,
“console”: false,
“tostatus”: false,
“complete”: “payload”,
“targetType”: “msg”,
“statusVal”: “”,
“statusType”: “auto”,
“x”: 600,
“y”: 140,
“wires”: []
},
{
“id”: “77eb4496170bd7ea”,
“type”: “debug”,
“z”: “643b47c11224f8b5”,
“name”: “CPU”,
“active”: true,
“tosidebar”: true,
“console”: false,
“tostatus”: false,
“complete”: “payload”,
“targetType”: “msg”,
“statusVal”: “”,
“statusType”: “auto”,
“x”: 590,
“y”: 220,
“wires”: []
},
{
“id”: “29bd13d32c5092f2”,
“type”: “inject”,
“z”: “643b47c11224f8b5”,
“name”: “”,
“props”: [
{
“p”: “payload”
},
{
“p”: “topic”,
“vt”: “str”
}
],
“repeat”: “”,
“crontab”: “”,
“once”: false,
“onceDelay”: 0.1,
“topic”: “”,
“payload”: “”,
“payloadType”: “date”,
“x”: 260,
“y”: 220,
“wires”: [
[
“fcf2793f03d162f0”
]
]
},
{
“id”: “fcf2793f03d162f0”,
“type”: “CPUs”,
“z”: “643b47c11224f8b5”,
“name”: “”,
“x”: 410,
“y”: 220,
“wires”: [
[
“77eb4496170bd7ea”
]
]
},
{
“id”: “8a145c104d064cf5”,
“type”: “NetworkIntf”,
“z”: “643b47c11224f8b5”,
“name”: “Network Stats”,
“x”: 440,
“y”: 260,
“wires”: [
[
“f012596eb6ecd30a”
]
]
},
{
“id”: “bf027507a06d34b4”,
“type”: “inject”,
“z”: “643b47c11224f8b5”,
“name”: “”,
“props”: [
{
“p”: “payload”
},
{
“p”: “topic”,
“vt”: “str”
}
],
“repeat”: “”,
“crontab”: “”,
“once”: false,
“onceDelay”: 0.1,
“topic”: “”,
“payload”: “”,
“payloadType”: “date”,
“x”: 260,
“y”: 260,
“wires”: [
[
“8a145c104d064cf5”
]
]
},
{
“id”: “f012596eb6ecd30a”,
“type”: “debug”,
“z”: “643b47c11224f8b5”,
“name”: “debug 4”,
“active”: true,
“tosidebar”: true,
“console”: false,
“tostatus”: false,
“complete”: “false”,
“statusVal”: “”,
“statusType”: “auto”,
“x”: 600,
“y”: 260,
“wires”: []
},
{
“id”: “8a17f07e9299f212”,
“type”: “debug”,
“z”: “643b47c11224f8b5”,
“name”: “average memory use percentage output1”,
“active”: true,
“tosidebar”: true,
“console”: false,
“tostatus”: true,
“complete”: “payload”,
“targetType”: “msg”,
“statusVal”: “”,
“statusType”: “msg”,
“x”: 1180,
“y”: 340,
“wires”: []
},
{
“id”: “0c438ae8d960f27d”,
“type”: “sf:637727819e8b21c6”,
“z”: “643b47c11224f8b5”,
“name”: “”,
“SIZE”: 36,
“x”: 880,
“y”: 340,
“wires”: [
[
“8a17f07e9299f212”
],
[]
]
},
{
“id”: “ba46d9bbc8152978”,
“type”: “change”,
“z”: “643b47c11224f8b5”,
“name”: “isolate only percentage”,
“rules”: [
{
“t”: “set”,
“p”: “payload”,
“pt”: “msg”,
“to”: “payload.memusage”,
“tot”: “msg”
}
],
“action”: “”,
“property”: “”,
“from”: “”,
“to”: “”,
“reg”: false,
“x”: 650,
“y”: 340,
“wires”: [
[
“0c438ae8d960f27d”,
“eba24bd1f4799103”
]
]
},
{
“id”: “eba24bd1f4799103”,
“type”: “debug”,
“z”: “643b47c11224f8b5”,
“name”: “debug 5”,
“active”: false,
“tosidebar”: true,
“console”: false,
“tostatus”: false,
“complete”: “false”,
“statusVal”: “”,
“statusType”: “auto”,
“x”: 860,
“y”: 300,
“wires”: []
},
{
“id”: “b8d7da622b919daa”,
“type”: “aedes broker”,
“z”: “c6e5631c9ad3e525”,
“name”: “”,
“mqtt_port”: “1888”,
“mqtt_ws_bind”: “port”,
“mqtt_ws_port”: “”,
“mqtt_ws_path”: “”,
“cert”: “”,
“key”: “”,
“ca”: “”,
“certname”: “”,
“keyname”: “”,
“caname”: “”,
“persistence_bind”: “memory”,
“dburl”: “”,
“usetls”: false,
“x”: 470,
“y”: 520,
“wires”: [
[
“2426718ac0d5f63c”
],
[
“b08ae5d0dacdbedb”
]
]
},
{
“id”: “2426718ac0d5f63c”,
“type”: “debug”,
“z”: “c6e5631c9ad3e525”,
“name”: “Broker Top”,
“active”: true,
“tosidebar”: true,
“console”: false,
“tostatus”: false,
“complete”: “payload”,
“targetType”: “msg”,
“statusVal”: “”,
“statusType”: “auto”,
“x”: 690,
“y”: 500,
“wires”: []
},
{
“id”: “b08ae5d0dacdbedb”,
“type”: “debug”,
“z”: “c6e5631c9ad3e525”,
“name”: “Broker Bottom”,
“active”: true,
“tosidebar”: true,
“console”: false,
“tostatus”: false,
“complete”: “payload”,
“targetType”: “msg”,
“statusVal”: “”,
“statusType”: “auto”,
“x”: 700,
“y”: 540,
“wires”: []
},
{
“id”: “2603596461908280”,
“type”: “mqtt in”,
“z”: “c6e5631c9ad3e525”,
“name”: “”,
“topic”: “testTopic”,
“qos”: “2”,
“datatype”: “auto-detect”,
“broker”: “a98f4ed9c18c8b27”,
“nl”: false,
“rap”: true,
“rh”: 0,
“inputs”: 0,
“x”: 460,
“y”: 600,
“wires”: [
[
“1380b840d29e7947”
]
]
},
{
“id”: “3cb86d288b2ee421”,
“type”: “mqtt out”,
“z”: “c6e5631c9ad3e525”,
“name”: “”,
“topic”: “testTopic”,
“qos”: “”,
“retain”: “”,
“respTopic”: “”,
“contentType”: “”,
“userProps”: “”,
“correl”: “”,
“expiry”: “”,
“broker”: “a98f4ed9c18c8b27”,
“x”: 460,
“y”: 660,
“wires”: []
},
{
“id”: “1380b840d29e7947”,
“type”: “debug”,
“z”: “c6e5631c9ad3e525”,
“name”: “MQTT in”,
“active”: true,
“tosidebar”: true,
“console”: false,
“tostatus”: false,
“complete”: “payload”,
“targetType”: “msg”,
“statusVal”: “”,
“statusType”: “auto”,
“x”: 600,
“y”: 600,
“wires”: []
},
{
“id”: “b04f21e6e83fed59”,
“type”: “inject”,
“z”: “c6e5631c9ad3e525”,
“name”: “”,
“props”: [
{
“p”: “payload”
}
],
“repeat”: “”,
“crontab”: “”,
“once”: false,
“onceDelay”: 0.1,
“topic”: “”,
“payload”: “1”,
“payloadType”: “num”,
“x”: 290,
“y”: 660,
“wires”: [
[
“3cb86d288b2ee421”
]
]
},
{
“id”: “b79c8f7581e1e363”,
“type”: “global-config”,
“env”: [],
“modules”: {
“node-red-contrib-os”: “0.2.1”,
“@racksync/node-red-contrib-moving-average”: “0.0.5”,
“node-red-contrib-aedes”: “1.2.0”
}
}
]
-----------------------------------end---------------------------------------------------------
basic troubleshooting
Issue and Solution
SSH says connection refused: sshd isn’t running — open Termux and run “sshd”
Node‑RED not starting: Check log: “cat ~/node_red_cron.log”
crontab (timer) not running: Ensure crond is running: “ps aux | grep crond”
Can’t find hash generation command in Arch Linux: Install Node.js first: “sudo pacman -S nodejs npm”