Rpi-gpio in node - always incorrect first read after boot

Hi All,

First post on here so hopefully I'm in the right place.

I am having a strange issue with rpi-gpio in...

The box on the rpi-gpio in node that says "Read initial state of pin on deploy/restart?" is ticked on all my inputs.

I'm running on an RPi3B, when the pi boots up, the initial automatic read of all of the gpio pins gives wrong values on the flow. If I restart the flow, it is always correct. If I restart node-red, it is always correct. If I disable the nodered.service, reboot and start it manually, the initial read is still always wrong.

This is a little frustrating as I have to log-in after every system boot and click "Restart all flows" for it to read the correct states of the input pins.

I suspect that it may be trying to read the pins before it has set them up properly, which is why it never works first time after boot.

I did an apt upgrade today and I think (not 100% sure) that it didn't do this before the upgrade. I think it did have some node packages listed but unfortunately I wasn't paying as much attention as I perhaps should have been.

Any thoughts would be very much appreciated.

Dave

Can you start node-red in a terminal and post the resulting output please so we can see what versions of the toolset is installed and check for anything unusual there. Assuming you installed using the recommended script for the pi you can do that using

node-red-start
node-red-stop

Are you absolutely certain that after reboot the last message that you got from the i/o node does not match the physical state of the pin? To check that connect a Change node to the i/o node and use it to set an global context variable. Then have an inject node that feeds a Change node to set msg.payload the the context variable and feed it to a debug node. Then you can reboot and click the inject to see what actually comes out of the i/o node.

Hi Colin,

Thanks very much for the reply.

Below is the output of node-red-start

Start Node-RED
 
Once Node-RED has started, point a browser at 
On Pi Node-RED works better with the Firefox or Chrome browser
 
Use   node-red-stop                          to stop Node-RED
Use   node-red-start                         to start Node-RED again
Use   node-red-log                           to view the recent log output
Use   sudo systemctl enable nodered.service  to autostart Node-RED at every boot
Use   sudo systemctl disable nodered.service to disable autostart on boot
 
To find more nodes and example flows - go to http://flows.nodered.org
 
Starting as a systemd service.
9 May 10:24:05 - [info]
Welcome to Node-RED
===================
9 May 10:24:05 - [info] Node-RED version: v1.0.6
9 May 10:24:05 - [info] Node.js  version: v10.16.3
9 May 10:24:05 - [info] Linux 4.19.97-v7+ arm LE
9 May 10:24:06 - [info] Loading palette nodes
9 May 10:24:10 - [info] Dashboard version 2.22.1 started at /ui
9 May 10:24:11 - [info] Settings file  : /home/pi/.node-red/settings.js
9 May 10:24:11 - [info] HTTP Static    : /home/pi/.node-red/webroot
9 May 10:24:11 - [info] Context store  : 'default' [module=memory]
9 May 10:24:11 - [info] User directory : /home/pi/.node-red
9 May 10:24:11 - [warn] Projects disabled : editorTheme.projects.enabled=false
9 May 10:24:11 - [info] Flows file     : /home/pi/.node-red/flows_pi.json
9 May 10:24:11 - [info] Server now running at 
9 May 10:24:11 - [warn]
---------------------------------------------------------------------
Your flow credentials file is encrypted using a system-generated key.
If the system-generated key is lost for any reason, your credentials
file will not be recoverable, you will have to delete it and re-enter
your credentials.
You should set your own key using the 'credentialSecret' option in
your settings file. Node-RED will then re-encrypt your credentials
file using your chosen key the next time you deploy a change.
---------------------------------------------------------------------
9 May 10:24:11 - [info] Starting flows
9 May 10:24:12 - [info] Started flows
9 May 10:24:12 - [info] [tcp in:f463c890.1c4428] listening on port 2012

I have been doing a bit more debugging, it seems to be an issue with the software pullups set by rpi-gpio in.

If I do a soft reboot, everything is fine on initial read of the pins by node red.

If I power down, unplug and reconnect the power, performing a a cold boot, the following happens:

-gpio readall - pins are read wrong as no pullups set yet (pins are connected to open collector outputs of an alarm system) so are floating in the "1" state, hence the need for the software pullups.
-start nodered service - initial read on startup matches the above gpio readall (wrong - suspect pullups not applied before read)
-gpio readall again - all now correct, would seem rpi-gpio in has set pullups
-node red restart flows - all reads correct now until next cold boot regardless of how many warm reboots, nod red restarts etc.

I am thinking that "rpi-gpio in" is reading the pin states and sending the initial message before it applies the pull-ups?

Any further comments would be much appreciated,

Cheers,

Dave

It probably does them effectively at the same time, but reads them before the pullups take effect.
If the initial state is important to you then you should most definitely add external pullups, that is the only way to be safe.
Presumably on startup you get the initial wrong message followed immediately by the correct message. In which case you could add a Trigger node set to send nothing immediately and after a short while to send the latest message. Personally I wouldn't rely on the internal pullups for anything connected to the outside world though, external will be better at absorbing noise pickup for example.

Thanks Colin,

I would now prefer external pullups, and as you say, I may end up having to add them which will be a bit of a nightmare as the project is built. It was previously running with a system I coded in PHP/mysql/Python and I didn't have this issue as I was setting the pullups way before any other scripts started.

With regard to the initial start-up, no, unfortunately it only reads the initial incorrect state without pullup applied, then sits there at that, presumably waiting for an edge trigger from the pi. I have to restart flows to get the correct value. I could probably live with it if it sent the correct message shortly after. Just wondering if I turn off the "read initial state" option, is there a way to programmatically get rpi-gpio in to force read the pins, e.g. using a trigger node to do it after 5 seconds of flow start, then do nothing.

I am regretting not fitting the external pullups before deployment, in my ignorance I just saw the option for internal software pullups and thought "Brilliant!", and to be fair, they have been fine so far.

Cheers,
Dave

Can you do my suggested test with the context setting please in order to confirm that. If you are correct that that is a bug.

OK here it goes, hopefully this is what you mean...
image

The state of this pin is always 1 (floating) unless the alarm is set, then it is pulled to ground by the transistor in the alarm module. The pin should always be read as 1 throughout this test if pullup applied correctly. The alarm is never powered down.

Now I will do a poweroff and cold boot...
On startup, reads as 0 (should be 1 with pullup)...
image

Debug node shows 0 in global variable now after injecting so a message is being sent with the incorrect initial value...

If I now restart flows, forcing a read of the pins for a second time, the pin is read correctly and all is good for every subsequent state change or restart until the pi is physically unplugged from power...
image

Hopefully this is what you were after?

Cheers,
Dave

Hi
I'm slightly confused. If the pin is set with a pull up - on start - even if it does initially read low - then as soon as the pull takes effect it should see the transition and report high. The only time the node sends something is when it sees a transition - so that first one must really going low. but once the pullup take effect it should see another transition.

Maybe try increasing the debounce time to 100mS or larger to give it time to settle ?
PS - which pins in particular are casing the issue - I know it should matter but.

Hi dceejay,

I have tried with the debounce time all the way up to 1500ms to no avail.

Looking at what I think is the source code at /usr/lib/node_modules/node-red-node-pi-gpio/nrgpio.py, it looks like the callback is applied after the pullup is set...

    elif cmd == "in":
        #print("Initialised pin "+str(pin)+" to IN")
        bounce = float(sys.argv[4])
        def handle_callback(chan):
            if bounce > 0:
                sleep(bounce/1000.0)
            print(GPIO.input(chan))

        if sys.argv[3].lower() == "up":
***1     GPIO.setup(pin,GPIO.IN,GPIO.PUD_UP)
        elif sys.argv[3].lower() == "down":
            GPIO.setup(pin,GPIO.IN,GPIO.PUD_DOWN)
        else:
            GPIO.setup(pin,GPIO.IN)

***X 

***2  print(GPIO.input(pin))                         
        if bounce > 0:
***3       GPIO.add_event_detect(pin, GPIO.BOTH, callback=handle_callback, bouncetime=int(bounce))
        else :
            GPIO.add_event_detect(pin, GPIO.BOTH, callback=handle_callback)

        while True:
            try:
                data = raw_input()
                if 'close' in data:
                    sys.exit(0)
            except (EOFError, SystemExit):        # hopefully always caused by us sigint'ing the program
                GPIO.cleanup(pin)
                sys.exit(0)

It look like at point marked ***1, it sets the pullup

Then at ***2 it manually prints the value of the pin immediately after (perhaps not giving it enough time for the pullup to be applied as you previously suggested.

The callback is then applied at ***3, so if the pin has already transitioned to 1 with the pullup before the callback is enabled, it will not report this and the state reported by node-red will remain the same until another edge trigger. Perhaps this is why I don't get another message after the pullup is applied.

Maybe I could try inserting sleep (2) at point ***X to see if it makes a difference. Appreciate that modifying this is not a solution, but maybe a good test to see if I am on the right lines?

Thanks,

Dave

1 Like

Without knowing how it works it does look as if there could be a race condition there, I agree.

certainly looks like a plan - also can try moving the if bounce... and else section above the print also
(ensuring to keep the indenting correct as this is python...) e.g.

        if bounce > 0:
            GPIO.add_event_detect(pin, GPIO.BOTH, callback=handle_callback, bouncetime=int(bounce))
        else :
            GPIO.add_event_detect(pin, GPIO.BOTH, callback=handle_callback)
        sleep(0.1)
        print(GPIO.input(pin))

That looks like a better solution as then if the race occurs (a change of state between the add_event and the print) I think the worst that will happen is that you get a repeated message.

Colin, dceejay,

Thanks for all your help, that works perfectly after making those changes. I assume that my changes will be overwritten if there are any updates though? How do I go about reporting this as a bug?

Thanks,

Dave

You already have :slight_smile:
I’ll fix the node and release it

1 Like

Ah, brilliant, sorted!
How do I update it once released? Is it just npm update node-red-node-pi-gpio from my home .node-red directory?

You will be able to update it from the browser using Manage Palette.

Smashing, thanks, didn't even know that existed until now! Makes life much simpler. Learn something new every day.

Much appreciated,

Dave

ok - pushed to npm as version 1.1.1
flows.nodered.org should update soon.
If you can't wait then

cd ~/.node-red
npm i node-red-node-pi-gpio@latest

and restart

Thanks :+1:

Thanks for finding it and helping to fix it.