If the suggestion from @cymplecy works it will be a very simple solution. If you decide moving forward with python and mqtt, below is a sample. It's a matter of taste what to select. Advantage in using mqtt could be that you would like to extend some functionality in the future. Let's say in future you would like to be able to control your relays from outside your home network in a safe way. With mqtt it is pretty easy using public mqtt servers
Install mosquitto broker in your RPi (there are many guides on the net):
Assuming we are using Python3, you eventually have to install some python libraries to make the script below work
sudo pip3 install paho-mqtt
sudo pip3 install setproctitle
sudo pip3 install subprocess
Copy the script below to your /home/pi directory in the RPi and start it from a command prompt
python3 relay_control.py
From Node-RED you just send very simple commands to control the relays. There is also a command to abort the script. Commands sent are strings like "R3_ON", "R3_OFF" and "abort"

# coding: utf-8
import sys
import os
import socket
import datetime
import time
import subprocess
import signal
import paho.mqtt.client as mqtt
from setproctitle import setproctitle
def on_connect(client, obj, flags, rc):
client.subscribe("commands", 0)
def on_subscribe(client, userdata, mid, granted_qos):
print ('Subscribed:', userdata, mid, granted_qos)
print ('We are here, waiting for button commands...')
def on_message(mosq, obj, msg):
global abort
TCP_IP = '192.168.12.183'
TCP_PORT = 2101
BUFFER_SIZE = 1024
cmds = {
"R1_ON" : bytes ((170,3,254,108,1,24)),
"R1_OFF" : bytes ((170,3,254,100,1,16)),
"R2_ON" : bytes ((170,3,254,109,1,25)),
"R2_OFF" : bytes ((170,3,254,101,1,17)),
"R3_ON" : bytes ((170,3,254,110,1,26)),
"R3_OFF" : bytes((170,3,254,102,1,18)),
"R4_ON" : bytes ((170,3,254,111,1,27)),
"R4_OFF" : bytes ((170,3,254,103,1,19)),
"R5_ON" : bytes ((170,3,254,112,1,28)),
"R5_OFF" : bytes ((170,3,254,104,1,20)),
"R6_ON" : bytes ((170,3,254,113,1,29)),
"R6_OFF" : bytes((170,3,254,105,1,21)),
"R7_ON" : bytes ((170,3,254,114,1,30)),
"R7_OFF" : bytes ((170,3,254,106,1,22)),
"R8_ON" : bytes ((170,3,254,115,1,31)),
"R8_OFF" : bytes ((170,3,254,107,1,23))
}
event = msg.payload.decode("utf-8")
print (event)
if event == 'abort':
abort = True
if "_O" in event:
print ("filtered:", event)
print (cmds[event])
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
s.send((cmds[event]))
s.close()
p = subprocess.Popen(['ps', '-A'], stdout=subprocess.PIPE)
out, err = p.communicate()
for line in out.splitlines():
#print (line)
if b'relay_control' in line:
pid = int(line.split(None, 1)[0])
print ('Killing ', pid)
os.kill(pid, signal.SIGKILL)
time.sleep(2)
nn = 'relay_control'
setproctitle (nn)
abort = False
client = mqtt.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()
#if not os.geteuid() == 0:
# sys.exit("script only works as root")
while not abort:
time.sleep(1)
client.loop_stop()
client.disconnect()
del client
exit(0)