Really struggling with 1 button and 3 states

Been using node red for about a year now and feel i have somewhat of a half decent understanding with it. But there's one flow I can't get my head around, the "simple garage door".

I feel like this could be the same with allot of peoples garages but mine doesn't have an open and a close state. It has one button which when pressed is Start. Press it again it stops but flips into reverse ready to be pressed again. This repeats. So press it again it starts in reverse, press it again it stops and flips.

To make it even more complicated if you don't press stop, after 20 seconds it switches automatically.

A flow to get the garage working is fine, easy. The problem comes when you want to know its state. If i press it a couple of times my switch state couldn't tell me if the garage was open or closed. I feel node red is perfect for this, but its just me who can't quite grasp it.

Unfortunately i can't show the flow so far because i don't know where to start with it, I feel like using the interval node could be the way to go. IE if pressed again within 20 seconds it keeps the position of my switch the same, but should that be reset after so the node is ready for the next press and if so how do i let it know that it needs to go to the open state. Is there such a thing as a 3 state button? am I making it more complicated than it should be?

If anyone has any experience with this kind of switch please let me know what you did, even just a nudge in the right direction would be helpful . I've searched garage doors on here but can't find anything related to what im asking for. Does this kind of switch have a specific name, if you know, let me know so i can investigate that further too.


I'll get back to you shortly.

How's this?

I tested it and it seems to work.

The trap is not to watch too closely the direction value.

Sorry I couldn't make it say UP and DOWN.

But if you watch it, it seems to work.

[{"id":"abff1141.b21bf8","type":"trigger","z":"8bb4de19.f72c88","name":"","op1":"START","op2":"STOP","op1type":"str","op2type":"str","duration":"20","extend":false,"overrideDelay":false,"units":"s","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":3250,"y":2060,"wires":[["97a7ed4c.3efb88","351a954b.03123a"]]},{"id":"97a7ed4c.3efb88","type":"change","z":"8bb4de19.f72c88","name":"Get direction.","rules":[{"t":"set","p":"direction","pt":"msg","to":"DIRECTION","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":3430,"y":2060,"wires":[["18065360.3e56d5"]]},{"id":"cd0f9550.345fa8","type":"inject","z":"8bb4de19.f72c88","name":"Button","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"BUTTON","payload":"PRESSED","payloadType":"str","x":3070,"y":2020,"wires":[["abff1141.b21bf8","f382d08d.cf66f8"]]},{"id":"351a954b.03123a","type":"switch","z":"8bb4de19.f72c88","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"STOP","vt":"str"},{"t":"eq","v":"START","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":3410,"y":2120,"wires":[["92408e16.10e55"],["1d6432c0.1b9ccd"]]},{"id":"da97a79a.044ea","type":"change","z":"8bb4de19.f72c88","name":"Reset","rules":[{"t":"set","p":"reset","pt":"msg","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":3070,"y":2120,"wires":[["abff1141.b21bf8","c9f39f28.7295a8"]]},{"id":"18065360.3e56d5","type":"debug","z":"8bb4de19.f72c88","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":3610,"y":2060,"wires":[]},{"id":"c9f39f28.7295a8","type":"change","z":"8bb4de19.f72c88","name":"STOP","rules":[{"t":"set","p":"payload","pt":"msg","to":"STOP","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":3270,"y":2120,"wires":[["97a7ed4c.3efb88","351a954b.03123a"]]},{"id":"f382d08d.cf66f8","type":"switch","z":"8bb4de19.f72c88","name":"Active?","property":"ACTIVE","propertyType":"flow","rules":[{"t":"true"}],"checkall":"true","repair":false,"outputs":1,"x":3060,"y":2070,"wires":[["da97a79a.044ea"]]},{"id":"1d6432c0.1b9ccd","type":"change","z":"8bb4de19.f72c88","name":"","rules":[{"t":"set","p":"ACTIVE","pt":"flow","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":3570,"y":2140,"wires":[["50770a55.fd22fc"]]},{"id":"92408e16.10e55","type":"change","z":"8bb4de19.f72c88","name":"","rules":[{"t":"set","p":"ACTIVE","pt":"flow","to":"false","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":3570,"y":2100,"wires":[[]]},{"id":"50770a55.fd22fc","type":"function","z":"8bb4de19.f72c88","name":"Toggle direction","func":"//  `direction` `0` = UP `1` = DOWN.\nvar direction = flow.get(\"DIRECTION\") || 0;\n\n//  Button pressed.\ndirection = (direction + 1) % 2;\n\nif (direction == 0)\n{\n    flow.set(\"DIRECTION\",direction);\n} else\n{\n    flow.set(\"DIRECTION\",direction);\n}\n\nnode.status({text:direction});\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":3770,"y":2140,"wires":[[]]}]

Ok, after thought:
START needs the direction part set.
STOP doesn't care.
So when you see the STOP message and the direction has changed, don't worry.
That is used at the next invocation of the message.

So further down the flow (your part) you will have to separate the STOP/GO and direction and handle them individually.

1 Like

I know this will not answer your question but just wanted to share my view.

Indeed, a switch does not have a state. They are stateless. They report events (button pressed or released). The state of the door garage is kept by the controller. The same logic used in the controller can be mimic with Node-RED indeed. You will use context variables to keep track of the state. Alternatively you may use a finite state machine node if you feel you need something more elaborated.

1 Like

This is a good example for ladder logic :blush:

I get a nose bleed at high altitudes because I am short. So I avoid ladders. :wink:

1 Like

(seriously not wanting praise for the code I posted)

Have either of you two (@iiot2k @Andrei ) looked at it?

It does work - yes? I bashed it together in .... about 5 minutes.
I think I tested it and it seems to work.

I didn´t. I can´t access my Node-RED environment right now. :neutral_face:

Sorry. It isn't I want to sound desperate - and I know that in itself isn't good saying that.

I am just having a lot of bad luck and I think things work when they don't.

I was kind of pleased with myself for doing it and tested it - or I hope - and would prefer to not make a monkey of myself claiming it works.

But doesn't matter.

It is what it is.

@Trying_to_learn can you program this in Node-Red ?

You may need to elaborate on what happens.

I don't know if it is me or what, but I can't parse that.

Hi here is a simple example

[{"id":"8aa47e1b.779118","type":"delay","z":"57675e72.26a0d8","name":"","pauseType":"delay","timeout":"20","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":330,"y":3140,"wires":[["d1ae1036.33226"]]},{"id":"e9293e29.99df88","type":"function","z":"57675e72.26a0d8","name":"","func":"let position = flow.get(\"position\") || 0;\nmsg.payload = [\"up\",\"stop\",\"down\",\"stop\"][position];\nflow.set(\"position\", (position >= 3 ? 0 : position + 1));\nnode.send([null,{\"reset\":true}]);\nreturn [msg,{\"payload\":position}];","outputs":2,"noerr":0,"initialize":"","finalize":"","x":330,"y":3080,"wires":[["371e17f.dc0ede8"],["8aa47e1b.779118"]]},{"id":"d1ae1036.33226","type":"function","z":"57675e72.26a0d8","name":"","func":"if (msg.payload % 2 === 0){\n    flow.set(\"position\", (msg.payload > 0 ? 0 : msg.payload+2));\n}\n//msg.payload=[\"up\",\"stop\",\"down\",\"stop\"][(msg.payload >= 3 ? 0 : msg.payload+1)];\n//return msg;\nreturn null;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":490,"y":3140,"wires":[[]]},{"id":"5679f3d6.13615c","type":"inject","z":"57675e72.26a0d8","name":"Button","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"PRESSED","payloadType":"str","x":120,"y":3080,"wires":[["e9293e29.99df88"]]},{"id":"371e17f.dc0ede8","type":"debug","z":"57675e72.26a0d8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"msg","x":590,"y":3080,"wires":[]}]

it will cycle up, stop, down, stop.
If set on down or up for 20 seconds it will skip stop, and cycle to next up or down.

1 Like

Looks like this (I have not implement all parts).
Sorry for nose bleed.

You have already told us the reason for that, it is because you get nose bleeds at high altitude.

I suggest it would be better if discussion of this application were moved to a different thread, rather than polluting this one with topics not related to the original subject.

Very impressed with this, I think i blinked and you posted it. I'm been messing around, trying to do this for a while now and couldn't get near it. This is exactly how the door works. I will try and hook this up tonight with an open and closed state or binary sensor and see how it all works, but think you've nailed it. Thank you very much!

1 Like

No problems.

Glad I could be of help.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.