Again - enabling/disabling a specific node

Well, this has been asked before so just checking if there is any improvements or new ways I can use. I have a specific case where I would need to do:

disable the node - deploy - enable the node - deploy

just to recover a connection the node makes

I think it would be possible, a bit heavy maybe, to use the Admin API to swap flows on a specific tab (where one flow has the node disabled, the other has it enabled)

But is there maybe a better and simpler way possible??

The node should allow to do it.

It is not that easy to do because the problem is to restart the node.

1 Like

What is the node exactly doing? where did the connection go? what does recover mean in this case?

For me, it seems that the node needs fixing since it should automagically recover the connection if that connection happens to fail. Or it should recover the connection automagically if the node receives a message (and therefore requires the connection).

An MQTT node does not need to be restarted if the connection drops for example - that should be the behaviour of this node.

1 Like

Yes, sure, you are of course correct, the node should handle all this - but it doesn't and it is an old one, last update like 5 years ago. I have added a new issue on github for it

It is the eWeLink node - it gets disconnected in Node-RED if you log in with the eWeLink app. This is all known since long. Myself I don't use & care about the app, just the node but if it should happen, I want it to automatically recover the connection (by disabling/enabling it does do that). So I was looking for a quick and dirty way of "putting lipstick on a pig"

It would be interesting to try this is real life. Most certainly this would literally be dangerous with a fully grown pig. Ouch.

I had a quick search for eWeLink - Library - Node-RED - and there are a bunch of nodes out there, have you tried something else then?

And what about just restarting the flow? Does that not work? I mean that would toggle the node also ...

EDIT: if you're using node-red-contrib-ewelink then one thing I noticed was the initialisation of the node:

  initializeDeviceNode(RED, node, config, method, params) {
    // Log in to eWeLink
    this.ready(RED, node, config).then(connection => {
      // Once logged in we can listen to inputs
      node.on('input', (msg) => {
        // Clean up device ID
        let deviceId='';
        if (config.deviceId && config.deviceId.trim()) {

that would make the assumption that everytime the node gets a message, the connection would be up and alive. If the server dropped the connection, then a restart would indeed be necessary. But that's my lipstick on the pig idea!

Or just restart node-red.

Restatring NR or all flows has too many drawbacks, system will then go through a full restart of (lots of) everything and that is something I would like to avoid. I will anyway verify if it helps, otherwise I might go the Admin API way (you teached me that path already @gregorius)

PS yes, it is that node, and I rather not hard code a fix in there...

EDIT: restarting the complete flow works but it affects too much, I think I will experiment a bit with the Admin API...

EDIT_AGAIN: Basically the code in the node should check if it is connected when a message is incoming, and if not, reconnect, but that is some javascript...I wish it was Python

I have a flow for that - it tries to determine what started node red i.e. inside docker, on the command line, or service start nodered on a raspberry and then do the appropriate thing to restart node red.

If node red is running in a docker instance, it does make the assumption that docker was started inside a loop:

while [ 1 ]; do 
  docker run -it -p 1880:1880 -v node_red_data:/data --name mynodered nodered/node-red 
done

Inside a docker image it does a kill 1!

Hm, why not? fork @ github, fix it, publish, reinstall ... or create a pkg and install it into your node-red as a .tgz.

I think that is the actual problem that the correct solution (fixing the node) is actually too hard and instead lipstick is smeared on the pig .... after all the poor pig isn't the problem (beside it being cruel)!

EDIT: there is a experimental third way (besides forking or smearing) and that is using the nodedev package to fix the node package in question within node red. Here's how:

  1. having installed the nodedev package, go to the sidebar and import the ewelink package:

(press import package)

  1. that will create a new flow with the codebase of the node package inside node red:

or cleaned up a bit:

(each group represents a directory in the original package)

  1. open the node that represents the code above:

Swap those two lines, i.e., the node.on(...) comes before the this.ready(....) and save the node & flow. (I have no idea whether that will fix the problem but it's worth a try.)

  1. Go to the NodeDevOps node at the top and press the button:

Eventually, depending on the speed of the node red instance this will appear;

  1. the changes are now installed and can be tested.

That installing is done using node reds API for installing local packages and is done by these two nodes at the end of the flow:

I.e. create a tarball from all the nodes and install that in node red.

If the package doesn't install - because version already installed - then update the version number in the package.json:

Anyway, that's the way I get around the hassle of updating custom nodes.

1 Like

Thanks for the extensive & detailed description, will be next step if I fail w the Admin API

I must be blind somehow, can't understand what is missing in the following example

I can GET info about the gate node but I cannot change it's state using PUT disable/enable, it says "Module not found"

I think the syntax in my call should be ok but I must have missed something, Any help is very appreciated


[
    {
        "id": "056c13cdd60e50f2",
        "type": "http request",
        "z": "c98c2efa62204262",
        "name": "",
        "method": "use",
        "ret": "txt",
        "paytoqs": "query",
        "url": "",
        "tls": "",
        "persist": false,
        "proxy": "",
        "insecureHTTPParser": false,
        "authType": "",
        "senderr": false,
        "headers": [],
        "x": 710,
        "y": 590,
        "wires": [
            [
                "170c52e615582814"
            ]
        ]
    },
    {
        "id": "170c52e615582814",
        "type": "debug",
        "z": "c98c2efa62204262",
        "name": "debug 380",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 910,
        "y": 590,
        "wires": []
    },
    {
        "id": "28653f93786fb06c",
        "type": "comment",
        "z": "c98c2efa62204262",
        "name": "request to enable/disable a node",
        "info": "",
        "x": 330,
        "y": 550,
        "wires": []
    },
    {
        "id": "51399a72f866f581",
        "type": "inject",
        "z": "c98c2efa62204262",
        "name": "enable",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "{\"enabled\": true}",
        "payloadType": "json",
        "x": 250,
        "y": 590,
        "wires": [
            [
                "c1186cf2353dd9cc"
            ]
        ]
    },
    {
        "id": "c1186cf2353dd9cc",
        "type": "change",
        "z": "c98c2efa62204262",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "url",
                "pt": "msg",
                "to": "\"http://localhost:1880/nodes/node-red-contrib-simple-gate\" & payload",
                "tot": "jsonata"
            },
            {
                "t": "set",
                "p": "method",
                "pt": "msg",
                "to": "PUT",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 500,
        "y": 590,
        "wires": [
            [
                "056c13cdd60e50f2"
            ]
        ]
    },
    {
        "id": "2f8de02fe16a3cf6",
        "type": "inject",
        "z": "c98c2efa62204262",
        "name": "disable",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "{\"enabled\": false}",
        "payloadType": "json",
        "x": 250,
        "y": 650,
        "wires": [
            [
                "c1186cf2353dd9cc"
            ]
        ]
    },
    {
        "id": "c206065ec8437241",
        "type": "http request",
        "z": "c98c2efa62204262",
        "name": "",
        "method": "use",
        "ret": "txt",
        "paytoqs": "query",
        "url": "",
        "tls": "",
        "persist": false,
        "proxy": "",
        "insecureHTTPParser": false,
        "authType": "",
        "senderr": false,
        "headers": [],
        "x": 710,
        "y": 780,
        "wires": [
            [
                "a30a9e6c5cfdcf4e"
            ]
        ]
    },
    {
        "id": "a30a9e6c5cfdcf4e",
        "type": "debug",
        "z": "c98c2efa62204262",
        "name": "debug 383",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 910,
        "y": 780,
        "wires": []
    },
    {
        "id": "7ada3db72c877d1b",
        "type": "inject",
        "z": "c98c2efa62204262",
        "name": "get info",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "{}",
        "payloadType": "json",
        "x": 250,
        "y": 780,
        "wires": [
            [
                "631c6a587ea7804f"
            ]
        ]
    },
    {
        "id": "631c6a587ea7804f",
        "type": "change",
        "z": "c98c2efa62204262",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "url",
                "pt": "msg",
                "to": "\"http://localhost:1880/nodes/node-red-contrib-simple-gate\"",
                "tot": "jsonata"
            },
            {
                "t": "set",
                "p": "method",
                "pt": "msg",
                "to": "GET",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 500,
        "y": 780,
        "wires": [
            [
                "c206065ec8437241"
            ]
        ]
    },
    {
        "id": "08a2b5132e286e00",
        "type": "gate",
        "z": "c98c2efa62204262",
        "name": "",
        "controlTopic": "control",
        "defaultState": "open",
        "openCmd": "open",
        "closeCmd": "close",
        "toggleCmd": "toggle",
        "defaultCmd": "default",
        "statusCmd": "status",
        "persist": false,
        "storeName": "memory",
        "x": 910,
        "y": 680,
        "wires": [
            []
        ]
    },
    {
        "id": "5c3ebeb7ec817d90",
        "type": "comment",
        "z": "c98c2efa62204262",
        "name": "request node info",
        "info": "",
        "x": 280,
        "y": 740,
        "wires": []
    }
]

From the docs, the enable/disable isn't a part of the URL path but a parameter that is sent as part of the request.

You're creating a url with http://localhost:1880/nodes/node-red-contrib-simple-gatetrue or http://localhost:1880/nodes/node-red-contrib-simple-gatefalse (it would also appear you're missing the '/' somewhere)

EDIT: just get rid of the "& payload" and the put should work - your payload is correct and is being sent with the PUT request - I just realised

You are a real champ!! Thank you so much! I will jump into it r away
The other part you teached us about with the NodeDev I will study carefully and try, for me this is a sort of new territory but you need to learn something every day

Thanks again,
Best regards, Walter

1 Like

Sorry, can't make that work, oops, I get as response

payload: "{"code":"invalid_request","message":"Invalid request"}"

Also tried some variants, no success

http://localhost:1880/nodes/node-red-contrib-simple-gate&false)
http://localhost:1880/nodes/node-red-contrib-simple-gate/enabled=false
http://localhost:1880/nodes/node-red-contrib-simple-gate/false

all wrong! remove the "& payload" the url should be http://localhost:1880/nodes/node-red-contrib-simple-gate and the payload should be { "enabled" : true } or { "enabled" : false }

I would really love to get feedback and questions if you do start playing around with NodeDev.

I definitely realise that it's not the "normal" way to develop nodes - it's a different approach that may or may not help someone to develop custom nodes and/or understand existing nodes better.

EDIT: this flow is the PUT part of what you posted with the fixes I mean:

[{"id":"9acb5178c7147535","type":"change","z":"ac8967655c48e455","name":"","rules":[{"t":"set","p":"url","pt":"msg","to":"http://localhost:1880/nodes/node-red-contrib-simple-gate","tot":"str"},{"t":"set","p":"method","pt":"msg","to":"PUT","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":538,"y":246,"wires":[["388cb4d9913a91ac"]]},{"id":"7de4a5f73d7b2db4","type":"inject","z":"ac8967655c48e455","name":"enable","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"enabled\": true}","payloadType":"json","x":288,"y":246,"wires":[["9acb5178c7147535"]]},{"id":"fb4d09c3a9dfb522","type":"inject","z":"ac8967655c48e455","name":"disable","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"enabled\": false}","payloadType":"json","x":288,"y":306,"wires":[["9acb5178c7147535"]]},{"id":"388cb4d9913a91ac","type":"http request","z":"ac8967655c48e455","name":"","method":"use","ret":"txt","paytoqs":"query","url":"","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"Content-Type","keyValue":"","valueType":"application/json","valueValue":""}],"x":748,"y":246,"wires":[["1b28f7c4ed984f3e"]]},{"id":"1b28f7c4ed984f3e","type":"debug","z":"ac8967655c48e455","name":"debug 380","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":948,"y":246,"wires":[]}]

Once again, thank you!

The command to enable seems to work but the disable seems to be an error
BTW, NR version 4.0.5

msg : Object
object
_msgid: "4327969577992c1a"
payload: "{"name":"node-red-contrib-simple-gate","version":"0.5.2","local":true,"user":true,"path":"/home/pi/.node-red/node_modules/node-red-contrib-simple-gate","nodes":[{"id":"node-red-contrib-simple-gate/gate","name":"gate","types":["gate"],"enabled":true,"local":true,"user":false,"module":"node-red-contrib-simple-gate","version":"0.5.2"}],"plugins":[]}"
url: "http://localhost:1880/nodes/node-red-contrib-simple-gate"
method: "PUT"
statusCode: 200
headers: object
responseUrl: "http://localhost:1880/nodes/node-red-contrib-simple-gate"
redirectList: array[0]
retry: 0
msg : Object
object
_msgid: "9a81c675e97cf382"
payload: "{"code":"type_in_use","message":"Type in use: gate"}"
url: "http://localhost:1880/nodes/node-red-contrib-simple-gate"
method: "PUT"
statusCode: 400
headers: object
responseUrl: "http://localhost:1880/nodes/node-red-contrib-simple-gate"
redirectList: array[0]
retry: 0

Ahhhhhhhh, sorry, now I learned a lesson!!!!

The disable does ONLY work if you don't have such node anywhere in your flows. If you don't have it in a flow it just disables it from the list of installed nodes (the left column). That was not what I hoped for

Dead end :cold_sweat:

Wait, you do realise that you are enabling/disabling the entire module, in this case node-red-contrib-simple-gate and that won't work because it's node (the gate) is actually being used!

It's the same functionality that is the disable in the manage palette:

i.e. the disable all button and that will only work if none of the nodes defined by the package are being used, i.e. included in some flow

EDIT:

indeed! - just had the same thought :slight_smile: