Sunset/Sunrise Switch not operating as expected


#1

Hello all,

I have just started with webCoRE, and would very much appreciate help with this issue I’m having (the first of many, I’m sure). Thanks in advance!

1) Give a description of the problem
My sunset/sunrise timed switch is not working consistently.

2) What is the expected behaviour?
I am expecting the switch to turn on between sunset and sunrise (and turn off otherwise). I would like the ON time to be randomly generated, anywhere from -10 minutes to +10 minutes with respect to sunset. Similarly, I would like the OFF time to be randomly generated, anywhere from -10 minutes to +10 minutes with respect to sunrise.

3) What is happening/not happening?
For this example (see log below), I have manually set the switch to ON, and have set the piston running. When it runs, the switch is turned OFF, which I’m not wanting to at this time (night time, after sunset and before sunrise the next morning).

**4) Post a Green Snapshot of the piston!

5) Attach logs after turning logging level to Full
1/27/2020, 9:53:54 PM +72ms
+1ms ╔Received event [Home].time = 1580180034653 with a delay of -581ms
+187ms ║RunTime Analysis CS > 41ms > PS > 121ms > PE > 24ms > CE
+189ms ║Runtime (38190 bytes) successfully initialized in 121ms (v0.3.110.20191009) (188ms)
+190ms ║╔Execution stage started
+246ms ║║Calculating (decimal) 0.0 - (decimal) 10.0 >> (decimal) -10.0
+248ms ║║Calculating (decimal) -10.0 + (decimal) 17.0 >> (decimal) 7.0
+255ms ║║Calculating (decimal) 0.0 - (decimal) 10.0 >> (decimal) -10.0
+257ms ║║Calculating (decimal) -10.0 + (decimal) 14.0 >> (decimal) 4.0
+269ms ║║Comparison (time) 78834268 is_between (time) 1580163540000 … (time) 1580128680000 = true (9ms)
+271ms ║║Time restriction check passed
+272ms ║║Condition #2 evaluated true (77ms)
+273ms ║║Cancelling statement #2’s schedules…
+278ms ║║Calculating (decimal) 0.0 - (decimal) 10.0 >> (decimal) -10.0
+281ms ║║Calculating (decimal) -10.0 + (decimal) 13.0 >> (decimal) 3.0
+291ms ║║Calculating (decimal) 0.0 - (decimal) 10.0 >> (decimal) -10.0
+293ms ║║Calculating (decimal) -10.0 + (decimal) 9.0 >> (decimal) -1.0
+298ms ║║Requesting time schedule wake up at Tue, Jan 28 2020 @ 7:37:00 AM EST
+304ms ║║Comparison (datetime) 1580180034373 is_after (datetime) 1580180034653 = true (2ms)
+305ms ║║Time restriction check passed
+307ms ║║Cancelling condition #7’s schedules…
+308ms ║║Condition #7 evaluated true (7ms)
+309ms ║║Cancelling statement #7’s schedules…
+314ms ║║Requesting time schedule wake up at Mon, Jan 27 2020 @ 9:53:54 PM EST
+316ms ║║Cancelling condition #1’s schedules…
+317ms ║║Condition group #1 evaluated true (state changed) (122ms)
+319ms ║║Cancelling statement #5’s schedules…
+326ms ║║Skipped execution of physical command [Porch Light].on([]) because it would make no change to the device. (2ms)
+326ms ║║Executed [Porch Light].on (4ms)
+344ms ║║Executed virtual command [Porch Light].setVariable (4ms)
+347ms ║║Fast executing schedules, waiting for 234ms to sync up
+593ms ║║Calculating (decimal) 0.0 - (decimal) 10.0 >> (decimal) -10.0
+595ms ║║Calculating (decimal) -10.0 + (decimal) 15.0 >> (decimal) 5.0
+600ms ║║Calculating (decimal) 0.0 - (decimal) 10.0 >> (decimal) -10.0
+603ms ║║Calculating (decimal) -10.0 + (decimal) 19.0 >> (decimal) 9.0
+614ms ║║Comparison (time) 78834659 is_between (time) 1580163540000 … (time) 1580128680000 = true (9ms)
+615ms ║║Time restriction check passed
+616ms ║║Condition #2 evaluated true (29ms)
+617ms ║║Cancelling statement #2’s schedules…
+622ms ║║Calculating (decimal) 0.0 - (decimal) 10.0 >> (decimal) -10.0
+625ms ║║Calculating (decimal) -10.0 + (decimal) 14.0 >> (decimal) 4.0
+632ms ║║Calculating (decimal) 0.0 - (decimal) 10.0 >> (decimal) -10.0
+635ms ║║Calculating (decimal) -10.0 + (decimal) 15.0 >> (decimal) 5.0
+641ms ║║Requesting time schedule wake up at Tue, Jan 28 2020 @ 7:43:00 AM EST
+646ms ║║Comparison (datetime) 1580180034715 is_after (datetime) 1580181834401 = false (2ms)
+647ms ║║Cancelling condition #7’s schedules…
+648ms ║║Condition #7 evaluated false (5ms)
+650ms ║║Cancelling statement #7’s schedules…
+653ms ║║Requesting time schedule wake up at Mon, Jan 27 2020 @ 10:23:54 PM EST
+655ms ║║Cancelling condition #1’s schedules…
+656ms ║║Condition group #1 evaluated false (state changed) (69ms)
+658ms ║║Cancelling statement #3’s schedules…
+680ms ║║Executed physical command [Porch Light].off() (20ms)
+681ms ║║Executed [Porch Light].off (21ms)
+689ms ║║Executed virtual command [Porch Light].setVariable (3ms)
+692ms ║╚Execution stage complete. (502ms)
+694ms ║Setting up scheduled job for Mon, Jan 27 2020 @ 10:23:54 PM EST (in 1799.636s), with 2 more jobs pending
+702ms ╚Event processed successfully (701ms)

Thank you :smile:


#2

I’m not sure if I understand the timeout part.

Your piston will be starting fresh each time it runs. So, those random numbers might change, and the condition may or may not be true. I’d consider something like this:

Every day at 1am
  Set Variable RandomOffset = -10 + random(20)

Every day at $sunset + RandomOffset
  with Switch 1
  turn on

Every day at $sunrise + RandomOffset
  with Swtich 2
  turn off

Is this what you were thinking?


#3

I believe it turns off due to ELSE statement you have.

instead create another/seperate IF block - outside of current IF block - and choose a trigger for it.

ie:

IF time is between sunset and sunrise
and
Date time is after {timeout} (I don't know why you use it this way btw)
Then 
Switch 1 
Turn ON

IF time is NOT between sunseet and sunrise
Then 
Switch 1
Turn OFF

#4

sorry didn’t see you responded…
Your piston is more of what he wants.


#5

A couple of thoughts:

A piston doesn’t sit around waiting for the time conditions to be met. It schedules timers to fire the piston at times of potential interest. So the piston has started up, evaluated the time restriction as true, using random numbers, and then scheduled a run for around sunrise, again with a random number. So come sunrise the piston might fire at three minutes to sunrise (based on the old day) and then compare it to four minutes past sunrise (based on the new day).

The reason the light turns off is that the {Timeout} seems to be the time the piston ran, so presumably it had got scheduled to run at that time. As the time being after {Timeout} is of interest to you, the piston has scheduled a new run for that time and as soon as it has turned the light on (or kept it on in this case) it immediately executes the piston again. Only you’ve just changed {Timeout} to 30 minutes time so the comparison fails and turns the light off.

I must admit to not being entirely sure what the purpose of the {Timeout} actually is, so it is difficult to comment on it.


#6

I just thought I’d dissect the logs.

1/27/2020, 9:53:54 PM +72ms
+1ms ╔Received event [Home].time = 1580180034653 with a delay of -581ms
+187ms ║RunTime Analysis CS > 41ms > PS > 121ms > PE > 24ms > CE
+189ms ║Runtime (38190 bytes) successfully initialized in 121ms (v0.3.110.20191009) (188ms)
+190ms ║╔Execution stage started
The piston was fired by a timer set for 9:53:54.653 PM that was running 581ms early.

+246ms ║║Calculating (decimal) 0.0 - (decimal) 10.0 >> (decimal) -10.0
+248ms ║║Calculating (decimal) -10.0 + (decimal) 17.0 >> (decimal) 7.0
+255ms ║║Calculating (decimal) 0.0 - (decimal) 10.0 >> (decimal) -10.0
+257ms ║║Calculating (decimal) -10.0 + (decimal) 14.0 >> (decimal) 4.0
+269ms ║║Comparison (time) 78834268 is_between (time) 1580163540000 … (time) 1580128680000 = true (9ms)
+271ms ║║Time restriction check passed
+272ms ║║Condition #2 evaluated true (77ms)
+273ms ║║Cancelling statement #2’s schedules…
The time restriction looked for the time being between seven minutes after sunset and four minutes after sunrise and so was true.

+278ms ║║Calculating (decimal) 0.0 - (decimal) 10.0 >> (decimal) -10.0
+281ms ║║Calculating (decimal) -10.0 + (decimal) 13.0 >> (decimal) 3.0
+291ms ║║Calculating (decimal) 0.0 - (decimal) 10.0 >> (decimal) -10.0
+293ms ║║Calculating (decimal) -10.0 + (decimal) 9.0 >> (decimal) -1.0
+298ms ║║Requesting time schedule wake up at Tue, Jan 28 2020 @ 7:37:00 AM EST
The piston needed to schedule a wake up. It reevaluated the time restriction with new random numbers and saw that it needed to wake up one minute before sunrise, calculated using today’s value for sunrise.

+304ms ║║Comparison (datetime) 1580180034373 is_after (datetime) 1580180034653 = true (2ms)
+305ms ║║Time restriction check passed
Now there is an interesting one. That comparison doesn’t look like it should be true but presumably there is some wriggling going on to compensate for the piston running early.

+307ms ║║Cancelling condition #7’s schedules…
+308ms ║║Condition #7 evaluated true (7ms)
+309ms ║║Cancelling statement #7’s schedules…
+314ms ║║Requesting time schedule wake up at Mon, Jan 27 2020 @ 9:53:54 PM EST
The piston has seen that {Timeout} is of particular interest so it has added that to the schedule.

+316ms ║║Cancelling condition #1’s schedules…
+317ms ║║Condition group #1 evaluated true (state changed) (122ms)
+319ms ║║Cancelling statement #5’s schedules…
+326ms ║║Skipped execution of physical command [Porch Light].on([]) because it would make no change to the device. (2ms)
+326ms ║║Executed [Porch Light].on (4ms)
+344ms ║║Executed virtual command [Porch Light].setVariable (4ms)
As the earlier ‘if’ was true, the ‘then’ block has been run. The piston knows the switch is on so skips actually turning it on again. {Timeout} is updated for thirty minutes time.

+347ms ║║Fast executing schedules, waiting for 234ms to sync up
The piston sees there is a schedule right on top of it so rather than exit, it hangs around and then gets on with it.

+593ms ║║Calculating (decimal) 0.0 - (decimal) 10.0 >> (decimal) -10.0
+595ms ║║Calculating (decimal) -10.0 + (decimal) 15.0 >> (decimal) 5.0
+600ms ║║Calculating (decimal) 0.0 - (decimal) 10.0 >> (decimal) -10.0
+603ms ║║Calculating (decimal) -10.0 + (decimal) 19.0 >> (decimal) 9.0
+614ms ║║Comparison (time) 78834659 is_between (time) 1580163540000 … (time) 1580128680000 = true (9ms)
+615ms ║║Time restriction check passed
A different time restriction this time, but still true.

+616ms ║║Condition #2 evaluated true (29ms)
+617ms ║║Cancelling statement #2’s schedules…
+622ms ║║Calculating (decimal) 0.0 - (decimal) 10.0 >> (decimal) -10.0
+625ms ║║Calculating (decimal) -10.0 + (decimal) 14.0 >> (decimal) 4.0
+632ms ║║Calculating (decimal) 0.0 - (decimal) 10.0 >> (decimal) -10.0
+635ms ║║Calculating (decimal) -10.0 + (decimal) 15.0 >> (decimal) 5.0
+641ms ║║Requesting time schedule wake up at Tue, Jan 28 2020 @ 7:43:00 AM EST
Evaluate the new schedule. This time it comes out as five minutes past sunrise.

+646ms ║║Comparison (datetime) 1580180034715 is_after (datetime) 1580181834401 = false (2ms)
{Timeout} is still thirty minutes away so the comparison fails.

+647ms ║║Cancelling condition #7’s schedules…
+648ms ║║Condition #7 evaluated false (5ms)
+650ms ║║Cancelling statement #7’s schedules…
+653ms ║║Requesting time schedule wake up at Mon, Jan 27 2020 @ 10:23:54 PM EST
Schedule a wake up for {Timeout}.

+655ms ║║Cancelling condition #1’s schedules…
+656ms ║║Condition group #1 evaluated false (state changed) (69ms)
+658ms ║║Cancelling statement #3’s schedules…
+680ms ║║Executed physical command [Porch Light].off() (20ms)
+681ms ║║Executed [Porch Light].off (21ms)
+689ms ║║Executed virtual command [Porch Light].setVariable (3ms)
+692ms ║╚Execution stage complete. (502ms)
The ‘if’ comparison failed so run the ‘else’ block, updating {Timeout}.

+694ms ║Setting up scheduled job for Mon, Jan 27 2020 @ 10:23:54 PM EST (in 1799.636s), with 2 more jobs pending
+702ms ╚Event processed successfully (701ms)
The piston will wake up at {Timeout}.


#7

When we want a random offset to be added to a timer, it helps to have the random number generated before the scheduled event.

Here is a way to grab two unique random offsets each day, and then assign them to the sunrise/set times…

(No need for a {Timeout} variable with this method)


#8

Hello all, and thank you everyone for your insight!

Sorry, I wasn’t clear about the Timeout variable’s purpose.
My first attempt at this piston actually seemed to work (the same code, but no variable or variable condition). On closer inspection however, it seemed like after the switch would change state (in the morning, for instance), the random time-frame was immediately being re-evaluated - the result was that, after a minute or so potentially, the current time might fall outside of the previously met condition, and it ultimately meant that the switch had the potential to flip on and off several times before it settled on its final state.
The Timeout variable was meant to allow the piston to run once to change state, and then prevent further execution for a period of 30 minutes (after which, the 20 minute random swing would be out of the picture). Strangely enough, this actually seemed to work the first few times I monitored it, but I think that was just random coincidence now.

Thanks again for your help - I’ll rewrite this, monitor for a while, and will post an update.


#9

I hadn’t considered the looping scenario, but it makes perfect sense. As the piston executes it is constantly considering whether it needs to schedule a wake up. So if the piston executed due to a timer set for sunrise + randomX, it would actually decide whether to turn the light on or off based on sunrise + randomY, and finally if sunrise + randomZ was yet to happen that day it would have scheduled the piston to wake up then, and so it could cycle. Eventually it would hit a new time which it could assume was the next day and move on.

I see what the Timeout variable was doing now. The ‘gotcha’ was that, because there were no explicit trigger conditions in the piston telling it when to run, the piston will have scheduled executions for any time that seemed of interest, and so potentially executed the piston at the time specified by Timeout too. The piston can be told not to do that, but that is not ‘just started with webCoRE’ stuff.


#10

Ah, thanks for the additional info! I think I’m beginning to understand the concepts here, and I think I was thinking of this more like a continually running “dumb” main loop, rather than a more intelligent system that schedules itself after analyzing the code.


#11

Given piston rvd9, would you have to add/subtract “{randomAM} * 1000” to convert from seconds to Milliseconds? Also, I was finding strange values when using “interger”, and used “long” instead.


#12

A piston is literally an event handler. The code behind the piston will subscribe to changes in device attributes, schedule a run for a certain time, or webCoRE will generate some internal events such as the ‘test’ button in the dashboard being pressed or an external URL being used to fire the piston. Nothing happens without an event. If you have the full logging turned on you can see what the event was at the top.

You will hear much about triggers and conditions. Both are forms of comparison. If there are triggers in a piston it will subscribe to changes in the device attributes on the left side of those comparisons, and it will also fire at the times used in them. If there aren’t any triggers, the conditions will be looked at instead to attempt to make the piston fire when it might have something to do. When the piston does fire it usually just starts from the top (‘every’ blocks are different) and then follows the flow of the code. Triggers and conditions are just comparisons. Triggers tend to work with data carried in the event itself (and hence can generally only be true if the event relates to them), whereas conditions look at current values of things. It is important to realise pistons don’t fire because triggers (or conditions) have been met, they fire because something has happened that could affect what the piston does.


#13

Evening all, I’ve a related (and presumably simpler) issue, this code doesn’t work - WC ignores the Wait till sunrise command, waits 1 hour then turns off.

I’ve implemented a simple workaround (second timer triggered at sunrise) but wondered if I’d missed something simple in this version which would permit a single timer use?


#14

@60milesmile, You likely need to use $nextSunrise. Since this is happening in the evening, $sunrise is in the past so it is basically skipped.


#15

I wouldn’t write it this way, but if you want to do it in a single trigger, maybe something like this? (not tested)


#16

You cannot see it in the screen shot, but piston rvd9 offsets between -10 and +10 minutes. (you will see it when you import it)


Integer has always been rock solid for me… I’d have to see the code you used to analyze why integer failed for you. (it works perfectly in rvd9 above)


#17

I am not sure why you are avoiding two timers… This is how I would do it:

Every day at 7AM
    Turn On
    Piston State blah blah
END EVERY

Every day at 1 hour after sunrise
    Turn Off
    Piston State blah blah
END EVERY

At each scheduled time, the piston will only execute what is inside that precise block.
(the other block will be ignored)


#18

Same here…

But perhaps he is just playing around with possibilities? (I’ve done that before LOL)


#19

I guess the point that I failed to mention is, with a WAIT, he is going to have two timers anyways… In my opinion, it is better to make it a hard-coded trigger.


#20

Thank you everyone for your help with this. It’s running like a dream now after I implemented a solution much like the first reply.
At 1 am, I’m randomly setting an offset variable. At sunrise plus this offset, i perform the action.
At 1 pm I re randomize this variable, and use this in a similar way at sunset.

:smiley: