Python to Node Red

I am using a Raspberry Pi and node red as a monitor for my motorhome. I have added a cheap flow sensor to monitor water use. Originally I tried to use a GPIO node to count the pulses but the results are inconsistent. I assumed this is because Node Red can not catch all the pulses. I have seen other threads suggesting running a Python script. I have limited knowledge of Node Red and knew nothing about Python until this week but I have managed to get a script running.

When the water pump starts, a GPIO pin goes high and sends "sudo python flowmeter.py" command through an Exec node. (not used this before and know little about it) . The script runs counting the pulses until the the pump turns off. To avoid quick on off changes like filling a kettle, stopping then adding a little more, the script runs for another 10 seconds to see if the pump starts again. Once the delay loop finishes, an MQTT message is sent to Node Red and the script stops. My questions are:

Is it better running the script permanently but paused with a wait for GPIO high statement rather than starting and stopping it each time. Script probably only runs once an hour.

Can I export a variable back to node red without having to use MQTT.

Is it better running the script permanently but paused with a wait for GPIO high statement rather than starting and stopping it each time.

I think that's entirely up to you. You can use systemd to start the program at boot and to restart it if it fails.
If you suspect that node-red is missing gpio transitions (seems unlikely actually), this might be the best way to run it.

If you run it like this, mqtt is the easiest way to get data into node-red. A mqtt-in node is an entry point into a flow when data arrives, whereas an exec mode sits in the middle of the flow.

By the way, if you do decide to call it with exec, it's almost certainly bad to use sudo.

I have no idea what exactly your python script is doing or returning.... but... the exec node will return any output from the script - so that could contain the count for example. If you want to run it for a long time then maybe node-red-node-daemon would be useful as that is similar to the exec node but does auto-restart, can accept input while running and by default expects continuous output.

Thanks. Sadly I have no idea what daemon is but will have a Google. The only output from the script is a count of the number of pulses. Again showing my lack of Python knowledge, I can see a print statement will send the count to the terminal screen. What Python command sends results back to the Exec node?

Hi -
daemon is an extra node - node-red-node-daemon (node) - Node-RED .

Anything python sends to stdout will come out of pin1 on the exec (or daemon) node. so yes a simple print("Hello"); should do fine.

With python you may also need to add -u to the command line to make it not buffer any output before sending it on... ie python -u yourapp.py

PS - AH sorry - I didn't spot you were not using the exec node yet - use that to call your script and it should be fine the way you have it.

Thanks I will give it a try. Final attack on the Exec Node what does spawn mode do?

What rate are the pulses coming in at?
What sort of output is it from the flow sensor?
What circuit did you use to connect to the GPIO?

I guess that the pulses are about 50/second. The flow sensor has a hall sensor sending high/low pulses. I think there are 8 magnets on the rotor. The sensor is rated at 3v5 to 12v. I am running on a 3v3 as it seems to work. I did try 5v with a voltage divider on the signal and the results were the same. I have a 5 ltr container that i use as a test volume. On a node red GPIO node I got readings between 250 and 600 pulses to fill the container. With the Python script running on 3v3 I get 4600 pulses +/- 3%.

Just tried the output from the exec node and it works a treat. Should have spotted it myself. Thanks to everyone on the forum who take time to help beginners like me.

If you have it working then that's fine. There is no reason i can think of why it should not work in node-red though.I think it would be necessary to look at the flow to see why. If you are interested in working out what the the problem was, then were you using flow or global context in the flow for something?

My lack of knowledge may be to blame. At each pulse of 1 I added it to a global variable then saved the global variable. I did not know how to do a count=count+1 as I would in a while loop etc.

Can you select the nodes doing the counting and export them, and paste here please? I suspect you have some sort of race condition going on that caused the pulses to get lost.

I deleted the original flow but I have reproduced it. When I export and paste the flow it is not in the format preferred on this forum. What do I need to do to put it in the correct format.

[
    {
        "id": "0b7b3d7829d8444d",
        "type": "rpi-gpio in",
        "z": "0b714342850326f5",
        "name": "",
        "pin": "19",
        "intype": "up",
        "debounce": "250",
        "read": false,
        "bcm": true,
        "x": 140,
        "y": 1260,
        "wires": [
            [
                "52f0483431b1acab"
            ]
        ]
    },
    {
        "id": "cad93d8390dea9d3",
        "type": "function",
        "z": "0b714342850326f5",
        "name": "",
        "func": "//  1 pulse is approx 5ml \nvar contents= global.get(\"Contents\")-msg.payload*0.005\nmsg.payload=contents\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 440,
        "y": 1260,
        "wires": [
            [
                "f87d78fbbccb0b48"
            ]
        ]
    },
    {
        "id": "f87d78fbbccb0b48",
        "type": "ui_gauge",
        "z": "0b714342850326f5",
        "name": "",
        "group": "c1220f6a1b9ea855",
        "order": 4,
        "width": 0,
        "height": 0,
        "gtype": "wave",
        "title": "Fresh Water",
        "label": "units",
        "format": "{{value}}",
        "min": 0,
        "max": "120",
        "colors": [
            "#00b500",
            "#e6e600",
            "#ca3838"
        ],
        "seg1": "",
        "seg2": "",
        "className": "",
        "x": 670,
        "y": 1260,
        "wires": []
    },
    {
        "id": "52f0483431b1acab",
        "type": "switch",
        "z": "0b714342850326f5",
        "name": "",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "1",
                "vt": "num"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 290,
        "y": 1260,
        "wires": [
            [
                "cad93d8390dea9d3"
            ]
        ]
    },
    {
        "id": "805f00c4e3c00be7",
        "type": "ui_button",
        "z": "0b714342850326f5",
        "name": "",
        "group": "c1220f6a1b9ea855",
        "order": 5,
        "width": 0,
        "height": 0,
        "passthru": false,
        "label": "Refil",
        "tooltip": "",
        "color": "",
        "bgcolor": "",
        "className": "",
        "icon": "",
        "payload": "120",
        "payloadType": "num",
        "topic": "topic",
        "topicType": "msg",
        "x": 230,
        "y": 1200,
        "wires": [
            [
                "136eae2cbe56b9af"
            ]
        ]
    },
    {
        "id": "136eae2cbe56b9af",
        "type": "function",
        "z": "0b714342850326f5",
        "name": "",
        "func": "global.set(\"Contents\",msg.payload)\nreturn msg",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 380,
        "y": 1200,
        "wires": [
            [
                "f87d78fbbccb0b48"
            ]
        ]
    },
    {
        "id": "c1220f6a1b9ea855",
        "type": "ui_group",
        "name": "Water",
        "tab": "80907cc2e6b6f810",
        "order": 1,
        "disp": true,
        "width": "6",
        "collapse": true,
        "className": ""
    },
    {
        "id": "80907cc2e6b6f810",
        "type": "ui_tab",
        "name": "Dashboard",
        "icon": "dashboard",
        "disabled": false,
        "hidden": false
    }
]

apologies thought I had found how to paste the code. Obviously not!

Yes you had, it is fine. I am on my phone so can't test at the moment, but eyeballing it I suggest this may be the problem:

        "type": "rpi-gpio in",
        "z": "0b714342850326f5",
        "name": "",
        "pin": "19",
        "intype": "up",
        "debounce": "250",

You appear to have specified a 250 ms denounce value, but your pulses are coming in at 20ms intervals, so many will be lost. Try dropping that right down.

Also I see you are reading the context value in one node and saving it in another, that is dangerous as you might have multiple messages flowing through at once, so it would be possible for a second message to fetch the value from context before the previous message has saved it, you should always read and save in the same function.
I may have misinterpreted what you are doing though, looking at the flow on my phone.

Thanks. I will try with a smaller debounce. If it works it will be a lot simpler than using Python. You are correct about 2 Nodes in use. They will not run at the same time but I will remember in future as I have done it in other applications where I have less control over the timings of messages - another lesson learnt.

Thanks for the help it is now working with a debounce of 5ms. I thought at first that it was still missing some as the count for 5ltrs about 2000 whereas the Python script returned about 4000. The difference of a factor of 2 was the clue. Python script was counting state change 1,0,1... Node red was counting 1s. Sorted. Much simpler setup. Thanks for your help

Have you fixed the potential problem with context? You can never guarantee that a message will not catch up with the one in front, for example, garbage collection can cause a delay so messages already in the flow can get bunched up.