When did the four lights complete the last loop?

Hi guys, need some help here. I have this flow that applies variable color and transitions to four lights (red rectangle in the picture). Whithin the green rectangle there’s a traffic light I want only to allow traffic when the four lights have completed the last cycle. Problem is, even though all lights are set to the same transition, they don’t always finish at the same time. It even happens that sometimes a light hasn’t finished the current transition that a new transition is called. How can I know when all four light finished the last loop so I can allow the traffic in the wait node?

I tried with a join node set to a count of 4, but I don’t know how the join node can distinguish whether those 4 parts are from 4 different lights a,b,c,d instead of a,a,b,c for example. Tried with a counter with the same problem.

Any help will be appreciated

My understanding of transition is that the state is updated then the actual transition is done.
So there is nothing that can tell you when it’s done.

But you could capture the transition time and delay the sequence I guess.

That can be a tricky issue, but one thing needs to be cleared up first.
Is a sequence start allowed to start before the previous one is ended?

Just to get your idea startedgen the solution is a queue or list.
When a sequence start then an entry with a timestamp is stored in the list and the timestamp is forwarded with the call to each of the nodes.
When the nodes finish their part, then the timestamp is added to the list too and after that a node checks if there are 5 of the same timestamps.
If there are 5, then the sequence with that timestamp has finished and the timestamps are then removed from the list.

1 Like

Can you do the transitions manually?
If you loop and do smal increments until the state is as desired then the message wont get out of sync

Yes, it is allowed. Problem is that the four lights are set to change to a different color each with a transition of the same amount of time. However, for some reason, usually the bathroom light takes a few more seconds to complete and sometimes the new sequence overlaps the current one.

If it’s not too much effort, could you please provide an example with two entities please? I’m hesitant on how to built the list.

I’m not sure I understand you. The flow is intended to operate automatically all the time.

thanks guys

Ok, I believe I got a solution following your idea. I created an individual sensor for each light. Sensors are set to wait when each individual transition starts and stores the timestamp when a transition ends . Each trigger node applies the current transition of the light for each timestamp so they should take care of any possible overlap

Then, instead of a traffic light, with a trigger: state node I limit the traffic. When the four sensors are the same and different than wait, continue.

Thanks a lot guys!

EDIT: @WallyR I’d still be interested in seeing how that list you suggedted would work.

What is the transition you do?
Is it brightness from x to y?
Then set up a function node

if brightness < y { 
   brightness++; 
   return msg;
}

Possibly you could have two outputs if the brightness is at y.
The first output goes past a delay then to a call service, then loops back to the function node.

I’m currently using my phone so I can’t draw it for you.

The transition is moving from x color to y color for a z amount of time. The transition is z, the time it takes.

That shouldn’t be very hard to do with a function node, delay node and call service in a loop.

This is my loop I use on our kids lights.
It loops the color wheel round all the time, but you could set a “destination” color.

[{"id":"59a5198c14c1c36b","type":"change","z":"a787a77.9c16458","name":"","rules":[{"t":"set","p":"fade_matilda","pt":"flow","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":1840,"y":1840,"wires":[["e7c4ef9c673488ef"]]},{"id":"e7c4ef9c673488ef","type":"api-current-state","z":"a787a77.9c16458","name":"","server":"4bbca37b.1700ec","version":2,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"light.matildas_lampa","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":2180,"y":1840,"wires":[["6eb898ea299f708c"]]},{"id":"ae70b00d41e2ce93","type":"switch","z":"a787a77.9c16458","name":"","property":"fade_matilda","propertyType":"flow","rules":[{"t":"true"}],"checkall":"true","repair":false,"outputs":1,"x":2330,"y":1760,"wires":[["e7c4ef9c673488ef"]]},{"id":"6eb898ea299f708c","type":"function","z":"a787a77.9c16458","name":"","func":"var sat =100;\n\nif (msg.dir == true){\n    if (msg.data.attributes.hs_color[1] > 70){\n        sat = msg.data.attributes.hs_color[1]+1;\n    }else{\n        sat = msg.data.attributes.hs_color[1]+2;\n    }\n    if (sat > 100) sat = 100;\n    msg.dir = true;\n    if (sat == 100) msg.dir = false;\n}else{\n    if(msg.data.attributes.hs_color[1] > 70){\n        sat = msg.data.attributes.hs_color[1]-1;\n    }else{\n        sat = msg.data.attributes.hs_color[1]-2;\n    }\n    if (sat < 40) sat = 40;\n    msg.dir = false;\n    if (sat <= 40) msg.dir = true;\n}\n\nmsg.payload = { data: {\n    'entity_id': 'light.matildas_lampa',\n    'hs_color': [(msg.data.attributes.hs_color[0]+3)%360, sat]\n } };\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":2420,"y":1840,"wires":[["ba91cfac6c4a4111"]]},{"id":"ba91cfac6c4a4111","type":"api-call-service","z":"a787a77.9c16458","name":"","server":"4bbca37b.1700ec","version":3,"debugenabled":false,"service_domain":"light","service":"turn_on","entityId":"light.matildas_lampa","data":"","dataType":"jsonata","mergecontext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":2610,"y":1840,"wires":[["2679851f4e79ce84"]]},{"id":"2679851f4e79ce84","type":"delay","z":"a787a77.9c16458","name":"","pauseType":"delay","timeout":"50","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":2830,"y":1840,"wires":[["ae70b00d41e2ce93"]]},{"id":"701e18e47e9df3bd","type":"api-call-service","z":"a787a77.9c16458","name":"","server":"4bbca37b.1700ec","version":3,"debugenabled":false,"service_domain":"light","service":"turn_on","entityId":"light.matildas_lampa","data":"","dataType":"jsonata","mergecontext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1570,"y":1880,"wires":[["59a5198c14c1c36b"]]},{"id":"4bbca37b.1700ec","type":"server","name":"Home Assistant","version":1,"legacy":false,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true}]

Regarding the transition time, is the time fixed, or does it depend on “how far” it has to change the color.

1 Like

Here is my take on a solution.
I have sort of made the entire flow.set and flow.get function into my list, because I simply create a new variable and set it to 0 when a sequence start with the variable name containing the timestamp of the start.
The timestamp is always forwarded to the following nodes, so they know what timestamp the sequence started and what flow variable name to relate to.
When a light/sensor/whatever finish its part, then it increase the value of the flow variable stored.
After the value have been increased the next node checks if the correct value has been reached for a complete sequence.
If not, then it just dies there, but if it has then it continues and make a final presentation.

To test this I used 4 random delay nodes as light/sensor/whatever.
This works great, but the higher number of nodes in the sequence gets the more stable the result gets, so if you would like to really see fluctuations, then lower the number of nodes in the sequence.
The chance of a sequence getting all low delays are bigger with only 2 nodes, than with 4.
Increasing the random delay to like 30 seconds also helps seeing the results better.

[{"id":"8f587dd245b5fd29","type":"inject","z":"be03f9025a1f137a","name":"Send timestamp","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":130,"y":210,"wires":[["512543cb0e3ef013"]]},{"id":"512543cb0e3ef013","type":"function","z":"be03f9025a1f137a","name":"Create sequence","func":"sequence = 'seq'+msg.payload;\nflow.set(sequence,0);\nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":195,"y":270,"wires":[["7458e1a2feabb6e1","b4ec6aafadf92033","e6ee9e90f56b3107","fff53f6a97bf533f"]]},{"id":"e6ee9e90f56b3107","type":"delay","z":"be03f9025a1f137a","name":"Random delay (1-10sec)","pauseType":"random","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"10","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":455,"y":180,"wires":[["bc62bac9c79cc935"]]},{"id":"7458e1a2feabb6e1","type":"delay","z":"be03f9025a1f137a","name":"Random delay (1-10sec)","pauseType":"random","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"10","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":455,"y":240,"wires":[["b2e1a219cbf3d74b"]]},{"id":"b4ec6aafadf92033","type":"delay","z":"be03f9025a1f137a","name":"Random delay (1-10sec)","pauseType":"random","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"10","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":455,"y":300,"wires":[["097ff3dd4446e21c"]]},{"id":"fff53f6a97bf533f","type":"delay","z":"be03f9025a1f137a","name":"Random delay (1-10sec)","pauseType":"random","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"10","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":455,"y":360,"wires":[["00a75a23df201e0f"]]},{"id":"bc62bac9c79cc935","type":"function","z":"be03f9025a1f137a","name":"Increase sequense counter","func":"sequence = 'seq'+msg.payload;\nflow.set(sequence,flow.get(sequence)+1);\nmsg.sequencecounter = flow.get(sequence);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":720,"y":180,"wires":[["9aa7ee5c345dabda"]]},{"id":"b2e1a219cbf3d74b","type":"function","z":"be03f9025a1f137a","name":"Increase sequense counter","func":"sequence = 'seq'+msg.payload;\nflow.set(sequence,flow.get(sequence)+1);\nmsg.sequencecounter = flow.get(sequence);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":720,"y":240,"wires":[["9aa7ee5c345dabda"]]},{"id":"097ff3dd4446e21c","type":"function","z":"be03f9025a1f137a","name":"Increase sequense counter","func":"sequence = 'seq'+msg.payload;\nflow.set(sequence,flow.get(sequence)+1);\nmsg.sequencecounter = flow.get(sequence);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":720,"y":300,"wires":[["9aa7ee5c345dabda"]]},{"id":"00a75a23df201e0f","type":"function","z":"be03f9025a1f137a","name":"Increase sequense counter","func":"sequence = 'seq'+msg.payload;\nflow.set(sequence,flow.get(sequence)+1);\nmsg.sequencecounter = flow.get(sequence);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":720,"y":360,"wires":[["9aa7ee5c345dabda"]]},{"id":"9aa7ee5c345dabda","type":"switch","z":"be03f9025a1f137a","name":"Check sequence counter","property":"sequencecounter","propertyType":"msg","rules":[{"t":"eq","v":"4","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":1010,"y":270,"wires":[["0cec77b21f2e8b3a"]]},{"id":"0cec77b21f2e8b3a","type":"function","z":"be03f9025a1f137a","name":"Present final result","func":"msg.starttime = msg.payload;\nmsg.stoptime = Date.now();\nmsg.difference = msg.stoptime-msg.starttime;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1065,"y":330,"wires":[["98abc8a16634adfc"]]},{"id":"98abc8a16634adfc","type":"debug","z":"be03f9025a1f137a","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1235,"y":330,"wires":[]}]
1 Like

Thanks a lot guys for your answers, I’ve learned a number of things with your function nodes. The timestamp was definetely a great pointer in the right direction to get the flow to distinguish whether the last cycle was actually finished.

thanks again, I’ll keep those examples.

Glad to be able to help.

If you did not know it, then Node Red actually have a huge and great website with docs and guides.
Here is the section on context storing, like the flow variables I used.
https://nodered.org/docs/user-guide/context#what-is-context

1 Like