What is the optimal design for this simple goal


What is the optimal way to accomplish the following goal?

As day turns to evening, and my outside luminance sensor dips below 100 lux, fade living room lights from 0% to 50% over the course of 10 minutes.

Once the living room lights have been faded up to 50%, and outside luminance is safely below 100 lux, I’d like to be able to manipulate the light without this piston interferring.

Option 1:
Trigger: Outside Light Sensor’s illuminance drops below 100 lux
Fade level from 1% to 50% in 10 minutes
Never cancel tasks

Option 2:
Condition: Outside Light Sensor’s illuminance is less than 100 lux
Fade level from 1% to 50% in 10 minutes
Execute tasks on condition state change only

Option 3:
<something better I haven’t thought of>

I am obviously doing something wrong ;)
if outside light sensor drops below 100 lux
   fade level from 1% to 50% in 10 minutes
end if
if outside light sensor rises above 100 lux
   fade level from 50% to 1% in 10 minutes (or turn off)
end if
leave TCP set to default

EDIT: edited to remove the else so if a new event comes with the lux rising above 100, it triggers the fade down instead of fade up. TCP is still set to default.


Thank you, but this conflicts with advice I received here:Conditions and Triggers: The difference?
In that post, bobbles indicated that you must set TCP to Never, otherwise the fade command will get canceled because the trigger changes back to false as soon as the event has finished processing.


With respect, my answer was a general answer regarding your question about TCP and never.

If triggers are only briefly true when the event arrives, does that mean my task will get canceled a few milliseconds later?
In a word, yes. That’s why people set the TCP to ‘never’. This way when the expression becomes fslse, the actions will continue.
If there is a wait 5 minutes it will continue and mature. The only time this will stop is with motion for example. If motion should become active again before the timer matures, the timer stops and the actions run again. When it becomes inactive again the actions just carry on.

It may not be prudent in your use case.
I’m guessing because it has been stated ‘drops below’ then that will always be true, (well not always but you know what I mean), so leave TCP to default will work.

Thinking more about it and your use case, wouldn’t you want it to stop/change as the lux value goes below/above the lux setting.
I see completely why @bangali suggests this method.


@bobbles, your suggestion to set TCP to “never cancel” was correct. If I leave the TCP at default, then the next time LUX changes (even though it’s still below 100) the piston re-evaluates, the trigger shows as false (because it’s a trigger and not a condition), and the fade command halts. The examples suggested by @bangali do not work correctly unless you change the TCP to “never cancel”. This is based on testing I did a few minutes ago with my lux sensor and an adjustable flashlight :slight_smile:

Not trying to prove anyone wrong here, but I’ve been frustrated with WebCORE–it is not very intuitive when working with long-running actions like “fade”. I’m very inexperienced compared to most, so I’m hoping that some healthy discussion/debate will help me to understand better.

I’m beginning to think Option 2 is the optimal solution to my goal, since it allows you to leave TCP at default. But again, I’m still very inexperienced, and am hoping the experts can educate me.


i am all for this. to help me understand, would you please share how you did the experiment?

using a flashlight, if you point it at the lux sensor it should cancel the fade up action. that is intentional. (it should also trigger the fade down action, edited the snippet slightly so that the fade down is triggered.)

when you stop pointing the flashlight, it should drop below 100 and it should trigger the piston again to fade up and not cancel, if the lux stays below 100.

or are you saying that even without using a flashlight if it drops from 100 to 99, then 98, 97 …, then the fade command still halts because it gets cancelled?


Even without the flashlight, if it drops from 100 to 99, then 98, then 97, etc, the fade command still gets canceled because the trigger is technically false at all times except the very moment that lux dropped from 100 to 99.

I did this test using an adjustable brightness flashlight, so I could simulate a sunset. I then repeated the test using an actual sunset.

After doing this experiment I feel that Triggers are kinda janky.

I’ve moved beyond the simple requirements of my original question, so this snapshot isn’t totally applicable, but this is the structure I’ve settled on as being most efficient in my mind. It handles further lux changes just fine, and if lux wavers above and below 100, the lights just gradually adjust (no violent on/off thrashing).

I’d would be very thankful for any criticism or suggestions for improvement.


thanks for the update. i wish drops below would remain true till it rises to or above that level at which point it would become false. evaluating it at every lux change kind of defeats the purpose of a drops below

what you have done here achieves exactly the same logic as if drops below and rises above behaved as i wish it did. :slight_smile:

using remains below or remains above might achieve the same goal without changing TEP to condition state change. need to try that out myself.


for anyone reading this later, even remains below and remains above will not work. both drops below / remains below and rises above / remains above reevaluates every time a corresponding event comes in, so any wait like tasks will get cancelled by default.