Polling with rpi-gpio input node - pull request review

607 views
Skip to first unread message

Bart Butenaers

unread,
Jan 2, 2017, 4:17:15 PM1/2/17
to Node-RED

Hi folks,


First of all my best wishes for 2017 !!!

I have created my first github fork to contribute some new functionality to the core Node-Red nodes, more specific the rpi-gpio input node.

I would be great to get some constructive feedback, before I start a pull request.  Thanks !


Current implementation

The current implementation of the input node, offers the following functionality:

The value of the gpio pin (0 or 1) appears as a message on the output port, only if a rising OR falling edge is detected. Optionally this message is also generated at flow startup (when the checkbox is checked by the user).


New implementation

However, I would like the node to have some extra functions:

*/ I would like to configure which edges need to be detected: none, leading, trailing, both

*/ I would like to read the port value whenever I want (by polling)

*/ I would like to combinate polling with edge detection (to avoid overlooking small pulses between two measurements)


Fortunately, the required functionality was already available in the python module that is used underneath. The nodes start (i.e. spawn) the python script with input parameters, and the python script returns results using standard io:


Since I want to decide myself when the port value should be read, I have added an input pin to the node. As soon as a message arrives, the pin value will be read (the message content can be whatever since it is ignored):


The above example flow allows us to read the value periodically, and plot the result in a graph (like a low-budget oscilloscope):

In some conditions it would be nice to combine a periodical polling like above, with an edge detection: this way we can make sure that small glitches don't get lost. E.g. when polling the value every 4 seconds, someone could open a door (with a reed relay) during 2 seconds, and we would not detect it:

To accomplish this, different edge detection capabilities have been added in the new implementation:

The default is set to 'both' for compatibility with the current node implementation. When only polling is required, the edge property can be set to 'none'. When only edge detection is required, it is sufficient not to send any messages on the input port.


Remark: I have removed following checkbox from the properties:


Reason for this decision is that the same result can be achieved, by linking an inject node (to the new input port) that is triggered at startup:

This looks to me a more typical Node-red approach.  Moreover, allowing the user to mix both solutions seems to be very confusing to me... The disadvantage of this approach is that it is not backwards compatible: a existing flow that has this checkbox activated, should be changed manually to add an inject node. Is there some way to validate this automatically? Something like 'if the old node version is loaded (from the flow json with the old checkbox = 'true' value) into a new node version, an error is displayed to indicate that an inject node should be added...????

Dave C-J

unread,
Jan 2, 2017, 5:05:39 PM1/2/17
to node...@googlegroups.com
Hi

thanks for your feedback, and the obvious time you have spent on this.

The main issue I have with this approach is why do you want to turn an event based system that only changes state when something happens - into an old style clocked/polling based system ?  I know it's a philosophical point of view, but it is fundamental to the way Node.js works anyway, (and indeed the human brain). It's also a lots more energy and storage efficient not to have to handle non-events (which is not a typical concern I'll admit but, on a low powered device only having to deal with changes in data would be preferable, as you can assume if you hear nothing then nothing has changed...)

Secondly - we aren't going to break existing users - so we can't remove the read on start unless existing behaviour can be maintained for existing flows (even if the option was hidden from new users... uurgh)

Another way of accomplishing the same thing could be a simple function node with a setInterval command internally - repeatedly sending the output (having saved it in local context) at whatever interval you want... and / or only outputting on the 1 edge or zero edge as required... 

thoughts ?

Bart Butenaers

unread,
Jan 2, 2017, 6:14:11 PM1/2/17
to Node-RED
Hi Dave,

Thank for your quick response.
  • I totally agree with you, for most of my stuff the events are much more efficient (in every way) compared to the polling solution.  But a.o. I wanted to have an extra way of visualising my data, as a said like some kind of oscilloscope (that is always available where ever I go ...).  I hoped that the Node-Red gadget-man would like the idea ...
  • The breakage of existing flows is indeed something that came into my mind.  Since I'm new to Node-Red, it wasn't clear to me whether I could solve this in coding (some kind of migration code between node versions or something else ...).
  • Since it seems that my enhancement will never be accepted, I will have to reimplement my solution in another way (outside the core Node-Red nodes).  So your function node idea could be perhaps of some help to me.  Am I correct that you would workaround my issue like this:
The rpi-gpio input node only creates messages at some event (system startup or signal change), the Msg cloner function node clones the last message at some periodical interval (e.g. every second), and all these (duplicated) messages can be visualised at the end using a graph node. 

One more thought about this: not reading the values periodically but waiting for an event to arrive, feels like loosing control of things.  Like my wife always says: "trust is good, but control is better" ;-)  You don't know for sure if simply no events have happened, or the system (that is responsible for generating the events) is completely stuck.  In the latter case, polling would most probably give an exception or at least a timeout exception.  But it is just a thought ...

Kind regards,
Bart

Dave C-J

unread,
Jan 3, 2017, 8:32:35 AM1/3/17
to node...@googlegroups.com
Hi Bart

yes - in theory not breaking old flows could be coded around... it's just software after all :-0... but yes - hiding something, and yet still providing the function under the covers just for those that need it and... it's just a pain... especially on the other hand you are adding more stuff in... of course it could just be left and people could choose how to do it.

Yes - that exactly the workaround I had in mind, use setInterval in the function node to output the state every x seconds... and the input can either just change the state - or also pass through as an extra data point as well. I could almost see this as a node in its own right... (it's sort of like the opposite of the RBE (report by exception) node that only passes on changes) - but I could potentially see repeat message mode being an option on the Delay node... as that already has most of the timing capability necessary.

Have to be very careful with wife analogies... but... when does too much control become nagging ? Re - knowing things are happening... yes - that is one of flip sides... and does need to be thought about in the context of the devices and links in question... for example that is why protocols like MQTT has things like keep-alive pings and Last Will and Testament (to report if client not seen). Certainly if your device must report every x hours then it's easy enough to use a trigger node in hold-off mode to report if not seen. But if it's just on a hard wired GPIO with solid copper then it should really be there.

Bart Butenaers

unread,
Jan 3, 2017, 7:10:11 PM1/3/17
to Node-RED
Hey Dave,

It would be pity, if my first fork ever would never see the daylight :-)
So I have adapted it again, and hopefully you like the idea a little bit more now ...

Updated implementation
I have added the original checkbox back to the properties screen.
And the default value for the new edge detection dropdown is 'both', like the original input node used underneath.
So it seems to me that existing flows are not impacted by this enhancement.

The properties window looks now like this:

The info text has been updated to reflect your concerns about polling, and that initial values can be captured in two different ways:

I have done a series of tests, to check the new implementation.  To avoid signal bouncing (that occurs when the input pin is manually connected to GND or 3,3V), I have connected an output pin to the input pin (using a resistor to limit the current to 3,3mA).  By controlling the output pin, the edge detection could be tested without bouncing interference:

The only weakness I see, occurs when users only select 'rising' or 'falling' edges.  Because the system now not detects all edges (at python level), the visualised value doesn't always reflect the real voltage level.  For example: pin18 is high (1) and edge detection is 'rising'.  When pin18 becomes low (0), the python module will not report this (since it is a 'falling' edge).  As a result the old value 1 will stay visualized:
However, I assume this kind of setup will mostly be used (rarely) by users for short glitches.  And in that case the new value will be displayed immediately afterwards.  Please correct me if I'm wrong.

Extra fix
During development, I came across another bug in the existing code.  The default value of the 'resistor' popup was set here:


However, the popup doesn't contain this value:

As a result the popup was displayed empty.  I have changed it to show 'none' by default, which kind of corresponds to the empty value.

Workaround
You have already given me a lot of hints for creating my own custom node, to generate new messages as clones of the original message.  However, my beginner knowledge isn't enough to understand it correctly.  The delay and rbe nodes act when a new message arrives at the input port, and then they decide what to do with that message.  However, I need to create message clones in an endless loop (create a clone every second, even during long periods when no new messages arrive at the input port).  From what I understand, such an endless loop has to be avoided in Nodejs.

An example in pseudo code:
while true {
" The msgoriginal should be updated by the function node as soon as as a new message arrives
var msgclone = RED.util.cloneMessage(msgoriginal);
node.send(msgclone);
}

Could you please give me some extra information, how this could be done?

Hope to hear from you soon.
Greetings,

Bart

Colin Law

unread,
Jan 4, 2017, 4:04:41 AM1/4/17
to node...@googlegroups.com
The code below will pass a message on each time one is received, then repeatedly re-send it at the specified interval until another is received.  I was a bit concerned about re-sending the same message object and wondered whether I should clone it, but have not had any problems with it as it is.

[
    {
        "id": "f64617a2.a9db18",
        "type": "function",
        "z": "7ec53a1b.321374",
        "name": "2 Min Repeater",
        "func": "// Repeatedly sends the last message passed in\nvar repeatInterval = 120*1000;          // the repeat interval in milliseconds\n\n// pass the message on\nnode.send(msg);\n// loop at given interval re-sending it\nvar tick = context.get('tick') || 0;\n// clear the repeater and restart\nif (tick) {\n\tclearInterval(tick);\n}\ntick = setInterval(function() {\n\tnode.send(msg);\n}, repeatInterval); // re-send at appropriate rate\ncontext.set('tick', tick);\nreturn null;",
        "outputs": 1,
        "noerr": 0,
        "x": 357,
        "y": 88,
        "wires": [
            [
                "55cc4a80.63db7c"
            ]
        ]
    }
]

Colin

--
http://nodered.org
 
Join us on Slack to continue the conversation: http://nodered.org/slack
---
You received this message because you are subscribed to the Google Groups "Node-RED" group.
To unsubscribe from this group and stop receiving emails from it, send an email to node-red+unsubscribe@googlegroups.com.
To post to this group, send email to node...@googlegroups.com.
Visit this group at https://groups.google.com/group/node-red.
To view this discussion on the web, visit https://groups.google.com/d/msgid/node-red/bef2d734-2acb-408d-8eee-10a7d8a1c34f%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Bart Butenaers

unread,
Jan 4, 2017, 4:42:53 PM1/4/17
to Node-RED
Hey Colin,

your code to implement the workaround of Dave is short, simple, works fine, and I learned a lot reading it.  Thanks !!!!

Greetings,
Bart

Op woensdag 4 januari 2017 10:04:41 UTC+1 schreef Colin Law:
To unsubscribe from this group and stop receiving emails from it, send an email to node-red+u...@googlegroups.com.

To post to this group, send email to node...@googlegroups.com.
Visit this group at https://groups.google.com/group/node-red.
Reply all
Reply to author
Forward
0 new messages