Circadian Schedule - Piston Skipping Lights


#1

1) Give a description of the problem
I made a circadian schedule for level and color temp that updates when each included bulb is turned on. I also made a child piston that cycles through and updates the circadian bulbs at each mode change.

The problem is, when your turn on a bunch of bulbs at once, the piston skips like 30% to 40% of them.

2) What is the expected behaviour?
Every bulb should update, not just most of them.

3) What is happening/not happening?
See above. There are issues with the child piston leaving bulbs on instead of restoring the captured switch state, but that’s another problem.

**4) Post a Green Snapshot of the piston

5) Attach logs after turning logging level to Full
No logs yet, but I can post one if the problem isn’t obvious from the code.


#2

The global vars are brightness & color temp, which are updated at each mode change to create the circadian schedule. The 3rd global variable is the one changed by the child piston, when the foreach loop is supposed to each bulb during the above-mentioned cycling.

Thanks in advance for any help.

Addendum 1) I tried including a longer wait period, but that doesn’t prevent 10 bulbs triggering the piston when they’re turned on together. It seems like they need to be properly put into queue before triggering the piston (if they aren’t already).

Addendum 2) Is there a way in WC to see if a bulb is currently displaying its color or its color temperature? If there is, I haven’t found it yet.


#3

This is very convoluted land difficult to understand what the child piston is doing to the @circadianModeDeviceUpdating variable. Is that a device type? Note that if the other piston is updating this variable and then calling this piston in a loop that update may not make it into this piston since global variables are not written until a piston finished running.

Now to an issue in the piston you posted: You trigger of the lights turning on and then turn lights on (if the bulb is off, a set level command will turn it on). Perhaps you have guarded against this but it is hard to tell. Bottom line, it is not good to trigger on the state of a device you are updating in the same piston unless you are very careful.


#4

Yes, the reason for the child piston was exactly that issue you described for guarding against. Originally it was a single piston, but then the mode updates were causing the piston to trigger itself by turning lights on. That’s why I added the 2nd restriction up top to only run when a “circadian” light is turned on AND when @circadianModeDeviceUpdating isn’t set (count == 0).

I’ll try to clean up the child and post a snapshot of that one too.


#5

It’s a really simple & straightforward piston that just cycles through all the lights that we want to update early (shortly after mode changes).

During the loop, the current light is set as the global device variable @circadianModeDeviceUpdating. When the loop is finished, the @circadianModeDeviceUpdating gets unset/emptied so the main piston is able to continue working normally at the time that any of the circadian lights are turned on.

EDIT: That 15s wait is the shortest I was able to get away with before lights started stepping on each other. Remember, if @circadianModeDeviceUpdating is changed to the next light in the loop before the previous light finishes changing, all hell breaks loose. :smiley:


#6

In case I didn’t make it obvious in the last reply, yes it’s a device; the device currently being “worked on” to be more precise.


#7

OK, seeing the other piston I understand much better. So you loop through and each time you change the variable, it is supposed to trigger the piston to set the levels. The 15 second wait might be enough to get the global variable to update since webcore temporarily leaves this piston but it is unreliable. As I said earlier, webcore waits until the end of execution to update global variables. There was a case recently discussed by @WCmore where a wait allowed the global variable to be updated but it was very specific. I can’t find the thread at the moment.

Anyway, I believe your skipping issue is due to this global variable update problem. Since your main piston only operates on the change, I guess you are catching all the changes but some changes never register before the loop changes them again.

EDIT: Here is the thread I was talking about:


#8

Actually, the opposite is what’s happening. Lights are only skipped when the main piston is triggered by lights being turned on independently, and without the child piston (the other half of the conditional). If you light up a room that has several lights, they all come crashing into the piston at once. It sometimes even skips a light when only 2 are turned on simultaneously.

The loop in the child piston never skips lights, because it’s only executing the main piston with 1 device at a time. The global variable isn’t emptied until the bottom of the script, and that’s after the loop is complete. The issue I’m running into with the child piston is sometimes it leaves lights on when they started in the off state. That could be related to the WC global variable problem you described. I tried playing around with the wait times (note the Lifx exception…oh how I wish they ran locally!), but the trial & error got tedious after a while.


#9

Did anyone know the answer to this? Imagine you’re about to turn on a light. How do you know which one (color vs temp) it’s going to use when it comes on? And can that be checked and/or adjusted in webCoRE?


#10

It would be interesting to see what is actually happening if a lot of lights change to on at once. That is one event to be processed per light, and potentially a ten second semaphore wait for each (I’ve never seen a semaphore that isn’t the full ten seconds, even though it should be ‘up to ten’).

I’ve never been entirely sure if all the events do get honoured eventually or if some just get thrown away if there has already been a wait.


#11

I should also suggest that as a number of events are expected near simultaneously, and each event needs processing separately (only one device will match the ‘changes’ trigger at once), a case may have been made for enabling parallelism. I haven’t considered any implications the particular use of local or global variables might have on that possibility, I just suggest that in general terms this is the sort of thing parallelism is for.


#12

DING DING DING!

Thanks for preserving whatever sanity I had left.


#13

After almost a full 24h of testing, parallelism was 100% the problem with the main piston. Tremendous thanks to the 2 posters who helped narrow it down.

Next will be fixing the child piston (and adjusting wait times on the main) so that mode updates don’t leave lights on after cycling through the lights 5x a day.

I realize circadian scripts are common, but anyone is free to copy these and tidy them up a little. I will probably incorporate the child piston into the custom version of Robin’s advanced mode manager I use (found in Example Pistons, below) at some point soon.