How do I start with the correct flow from SSH?

I am updating my reliability system, which up to now has been using Home Assistant to restart Node-RED when the events stop coming into the receiving end of the MQTT system, but it has had two misfires in the last two months, and that's at least five too many! :laughing:

So I figured I'd do the easy thing and make Plink (Putty's command line tool) batch files. The command line is like this:

plink -ssh pi@192.168.1.101 -pw mypassword -batch sudo node-red-stop
plink -ssh pi@192.168.1.101 -pw mypassword -batch sudo node-red-start

So it stops Node-RED and starts it again. The problem is that when I run that, I get an empty flow. Gave me a fright (even if I have backups, it's still scary to see an empty work space where there should be hours of flow programming), and I had to reboot the Pi to get it back to where it should be. What should I use to get my standard flow going?

a couple of things

  1. I would recommend you generate SSH Keys between the machines so you are not embedding passwords in batch files

  2. You have to start Node-red as the correct user to get your flow loaded - i would however recommend using something like pm2 as you can call this from the commandline and tell it to restart instances etc

Craig

Thanks, but I have six Pi's that I have to do this with, and security is not a concern at all because you need to break into a cellar and then a locked server cabinet to get to where the batch files are, and the system is on a closed purpose created network where nothing but the one computer has access to it. :slight_smile: So I just want to do it the easiest way possible. Is it not possible to do that without messing around more, just in the batch file?

Why are you using 'sudo' to stop & start node-RED?

Good question. I thought it was necessary when using it from SSH. So I'm wrong?

On a Pi I would not recommend using anything other than the service our install script sets up for you - just as you are doing.

When Node-RED starts, it logs the flow it is using. I suggest you compare the log output when you start it this way versus however you start it normally. That should give you a big clue as to why it's using a different (blank) flow file.

Problem solved, it was the sudo, @Paul-Reed ! Thanks for the help! :grinning:

1 Like

Now I only have to find out how to exit the Plink batch file after the job is done, as it is now it keeps the conection open with ouput from Node-RED.

Instead of those commands use
sudo systemctl restart nodered
Then you will not get the log.

Great, thanks a lot! :slight_smile: That works in another way too, where I can choose the time in between (so I can make a batch fil that can take a longer pause):

plink -ssh pi@192.168.1.101 -pw mypassword -batch node-red-stop
PING 192.168.10.188 -n 1 -w 10000
plink -ssh pi@192.168.1.101 -pw mypassword -batch sudo systemctl start nodered

192.168.10.188 is not a valid address, so that adds a ten second pause before the next step. I have a few Pi's where I need to keep Home Assistant (for the Z-Wave door lock integration that worked on Home Assistant before it worked reliably on Node-RED, and I don't want to replace all my Z-Wave code, that takes too much time), so I want to be able to shut down first Node-RED, then Home Assistant, wait for a while and then start them up again in the opposite order, with a few seconds in between.

Hey,

Instead of node-red-stop, you can use sudo systemctl stop nodered

Or why not try a 1-liner

sudo systemctl restart nodered

EDIT: sorry missed that you need that delay for HA, the one-liner might be to fast for your setup

Hi, Walter! :slight_smile: No problem, and thanks for wanting to help!

Btw does anybody know if there is a sneaky way to break the Plink connection to the Pi if it isn't responding? Sometimes (maybe once every two weeks or so) one of my Pis have Node-RED lock up in such a way that running "node-red-stop" makes it stand there churning. I think it's because it has a long (15 m) active USB cable up to the RFXtrx and the Tellstick Duo, because none of the others with the same installation does that.

So if I try a simple Node-RED restart on those occasions I'm pretty sure the window will sit there without doing anything. I have a third fail-safe in Z-Wave plugs on all the Home Automation Pi's so that the system turns the power off and then on again, but it would be nice if I could make Plink disconnect after X seconds no matter if there is activity or not. I haven't found that in the command line documentation, but maybe I'm just bad at looking?

If I understand correctly, this is what you would like to do

HA (is not receiving anything via MQTT from NR any longer) -> Stop NR -> Stop HA -> wait a while -> Start HA -> Start NR

I would think about having a Python script running (just because I trust Python) for monitoring & handling this. The Python script would subscribe to a topic for relevant commands. So you could just send a MQTT "restart" command to the topic (from HA I suppose?) and the Python script would

  1. Stop NR
  2. Stop HA
  3. wait a while
  4. Start HA
  5. Start NR
  6. Wait for next time...

You know the commands to use so it would not be difficult to write such a script

The script could be autostarted at boot, just add an entry, crontab -e

@reboot python /home/pi/theScript.py

If you show the commands you use to stop/start HA, I can write you a simple script example

Thanks, but there are a few variables because I send "check alive" events and have mail warnings from EventGhost on the server, which means that I think I'd prefer to do the monitoring from Windows. Also I only restart what needs to be restarted, so the script with restaring of both HA and NR is only used on certain occasions, most of the time it's enough to restart the one of them that's messing around.

But is it possible to make a script that saves me from a full reboot, where it kills the processes if they first don't exit gracefully within say 5 seconds? That would save me from doing a reboot on the Pi's that run both NR and HA if one of them locks up and has to be killed because I can't do a regular restart of the programs. I use the standard command for HA, which is sudo systemctl stop home-assistant@homeassistant

This python script will kill a process (in this example, node-red). But be aware of the following:

  • the script needs to executed in the same pi where the process is running (to support commands via network, you would need to add a mechanism for sending commands over the network, i.e. mqtt)
  • processes started by systemd (like node-red) will be automatically restarted if you kill them
  • the process you want to kill needs to have a unique name
import subprocess
import signal
import os

p = subprocess.Popen(['ps', '-A'], stdout=subprocess.PIPE)
out, err = p.communicate()

for line in out.splitlines():
    #print (line)
    if b'node-red' in line:
        pid = int(line.split(None, 1)[0])
        print ('Killing ', pid)
        os.kill(pid, signal.SIGKILL)
exit(0)

Maybe a misunderstanding in the previous, you could still control everything from Windows, just send the command via mqtt from there, the script will get the command and execute the stuff locally in the pi. You could easily have separate commands for each start and stop of HA and NR and handle the necessary delay in Windows. The advantage of executing such commands locally is that sometimes sudo is necessary...anyway you might be happy doing the same with Plink

Thanks! So how do I best run that script on the Pi? Is that something you could easily add an MQTT trigger for?

As for that last part, I see! In that case, yes, then that script would be very interesting to see, if you don't mind! :slight_smile:

Here is a python script you can use to control processes. The script support the following commands that you can send as text payload via mqtt to the topic restarter

stopNR
startNR
stopHA
startHA
disconnect (terminates the script itself)
reboot (reboots the Pi)

When the script receives the message, it will execute the corresponding command

Put the script in /home/pi and try to start it with python restarter.py. Now you should be able to test commands. I assume that you have a mqtt broker running in the pi and that you are sending commands to the same broker as the script has subscribed to

As mentioned you can configure this to autostart
crontab -e
and add this line at the end
@reboot python /home/pi/restarter.py

# import the necessary packages
import time
import mosquitto
import os
import subprocess
import signal
from setproctitle import setproctitle


def on_connect(client, obj, rc):
    client.subscribe("restarter", 0)


def on_subscribe(client, userdata, mid, granted_qos):
    print ('Subscribed:', userdata, mid, granted_qos)
    print ('We are here, waiting for commands...')


def on_message(client, userdata, msg):
    global th_abort
    #print(msg.topic, msg.payload)

    if 'restarter' in msg.topic:
        event = msg.payload.decode("utf-8")
        if 'stopNR' in event:
            os.system('sudo systemctl stop nodered.service')
        if 'startNR' in event:
            os.system('sudo systemctl start nodered.service')
        if 'stopHA' in event:
            os.system('sudo systemctl stop home-assistant@homeassistant')
        if 'startHA' in event:
            os.system('sudo systemctl start home-assistant@homeassistant')
        if 'disconnect' in event:
            th_abort = True
        if 'reboot' in event:
            reboot()

def reboot():
    try:
        os.system('sudo reboot')
    except:
        pass    

    

# Main starts here -----------------------------------------------------------
th_abort = False

p = subprocess.Popen(['ps', '-A'], stdout=subprocess.PIPE)
out, err = p.communicate()

for line in out.splitlines():
    #print (line)
    if b'restarter' in line:
        pid = int(line.split(None, 1)[0])
        print ('Killing ', pid)
        os.kill(pid, signal.SIGKILL)

time.sleep(5)

nn = 'restarter'
setproctitle (nn)

client = mosquitto.Mosquitto()
client.on_connect = on_connect
client.on_message = on_message
client.on_subscribe = on_subscribe

client.connect("127.0.0.1", 1883, 60)
client.loop_start()

while th_abort == False:
    time.sleep(1)
    
client.loop_stop()
client.disconnect()
del client
print ('Restarter process terminated')
exit(0)

Thanks a lot! :smile: Great! I will play with this in the weekend and let you know. I have a central broker (a separate Pi only running the broker, so there's less chance for anything at all locking it up, and for almost a year it hasn't), but I'll just replace the 127.0.0.1 with the IP for that.