Programatically changing piston subscription time


#4

The piston that sets the global should not call the lighting piston. This is because a global is not written until the very last line has been executed, so the lighting piston will usually see the old times.


You could make a block:

IF @global changes
    Then do X
END IF

…but I would limit this to only one piston. There’s no need for 5 pistons to fire whenever that time changes


#5

Ah, duh, I knew that. Thanks, I’ll probably just go with the first recommendation.


#6

So, that didn’t work.

The earliest my @turnOnTime global can be set to is 40 minutes before sunset. The calculation is done 50 minutes before subset. So I added the the recommended block to run and do nothing 45 minutes before sunset:

Every day at 45 minutes before $sunset
do
end every

Here is the trace from the last two runs. One right after I made the code change (I guess it runs to update the next run time). You can see it scheduled the next run for 5:40, which is in fact 45 minutes before sunbset. And then the one that ran at that time, which set the next run for 6:07PM, which was the time stored in @turnOnTime before it was updated. Based on the new value in @turnOnTime, it should have ran and turned on the lights at 5:45:

10/15/2019, 5:39:59 PM +76ms
+0ms ╔Received event [PRM].time = 1571186400000 with a delay of -925ms
+160ms ║RunTime Analysis CS > 29ms > PS > 80ms > PE > 52ms > CE
+163ms ║Runtime (51078 bytes) successfully initialized in 80ms (v0.3.110.20191009) (162ms)
+164ms ║╔Execution stage started
+209ms ║╚Execution stage complete. (45ms)
+211ms ║Setting up scheduled job for Tue, Oct 15 2019 @ 6:07:00 PM PDT (in 1620.713s), with 4 more jobs pending
+217ms ╚Event processed successfully (218ms)
10/15/2019, 5:17:52 PM +412ms
+0ms ╔Starting piston... (v0.3.110.20191009)
+206ms ║╔Subscribing to devices...
+261ms ║║Subscribing to Phone - Pat's Pixel 3.presence...
+275ms ║║Subscribing to Phone - Rochele's Pixel 3.presence...
+353ms ║║Subscribing to Front Porch 1...
+355ms ║║Subscribing to Front Porch 2...
+356ms ║║Subscribing to Balcony Lights...
+357ms ║║Subscribing to Backyard String Lights...
+358ms ║║Subscribing to Back Porch Lights...
+359ms ║║Subscribing to Front Porch Lights...
+361ms ║║Subscribing to Garage Exterior Lights...
+362ms ║╚Finished subscribing (166ms)
+477ms ║Evaluating switch with values [[i:55:null:0, v:[t:string, v:Halloween, vt:string]]]
+481ms ║Comparison (string) Halloween is (string) Halloween = true (2ms)
+569ms ║Comparison (time) 62272966 is_between (time) 65220000 .. (time) 28020000 = false (10ms)
+597ms ║Setting up scheduled job for Tue, Oct 15 2019 @ 5:40:00 PM PDT (in 1326.992s), with 4 more jobs pending
+627ms ╚Piston successfully started (627ms)

#7

Just to clarify, the global must be changed before the 5:40 empty trigger runs.

The only time I have ever seen this fail is if I use super global variables.
(with two @@ in front)


#8

The global was updated at 5:35 (it was changed to 5:45). Empty trigger ran at 5:40, which should have updated the schedule for the new gonna value, but didn’t.

It’s not a super global


#9

…One quick question please:
Did you manually change the global to 5:45, or did a piston change the global?


#10

My “Set Globals” piston changed it.


#11

So I did a little debugging in a separate piston, with a separate global. Mind you, I was changing this global manually. Your last comment implied that might make a difference, but it seems that the behavior is the same. So let me know if the test is invalid

Here is a screenshot of the test piston. You can see the next scheduled runtime is 4am, which is the previous value stored in @tempGlobal

I changed the global manually at 10:46:43, when the trace started. Below is the log from that. You can see it ran fine, but the last line - it didn’t update the next scheduled run to the new value in @tempGlobal (Which should be 5pm)

10/16/2019, 10:46:43 AM +94ms
+0ms ╔Received event [PRM].:a4a1ff5e4c41075d612263cbb8e1f7fd: = @tempGlobal with a delay of 52ms
+129ms ║RunTime Analysis CS > 31ms > PS > 80ms > PE > 19ms > CE
+132ms ║Runtime (39939 bytes) successfully initialized in 80ms (v0.3.110.20191009) (130ms)
+132ms ║╔Execution stage started
+139ms ║║Comparison (time) 61200000 changes = true (0ms)
+140ms ║║Condition #3 evaluated true (4ms)
+141ms ║║Condition group #2 evaluated true (state did not change) (4ms)
+143ms ║║Cancelling statement #4's schedules...
+149ms ║║Calculating (string) Global changed to + (string) 5:00:00 PM PDT >> (string) Global changed to 5:00:00 PM PDT
+152ms ║║Global changed to 5:00:00 PM PDT
+153ms ║║Executed virtual command log (1ms)
+171ms ║╚Execution stage complete. (39ms)
+175ms ║Setting up scheduled job for Thu, Oct 17 2019 @ 4:00:00 AM PDT (in 61996.731s)
+189ms ╚Event processed successfully (189ms)

Although this ran immediately since it has the changes trigger. The behavior is the same as my Exterior Lighting piston with the empty time trigger


#12

Tried saving the global to a local variable, and scheduling based on that. No change


#13

Because the ‘every day at construct’ executes only that section of code when activated and that code cannot be run any other time, my suspicion is, once set, you can’t change it even by doing this extra block. If instead, you change you main code conditional to ‘if $time is @globaltime’ it might work but I haven’t tested it myself. Or, as I think about it, maybe your extra block needs to be if Time happens daily at 16:00 so that the rest of the code is executed to update the other every conditional.


#14

All good ideas, thanks. I added this as debug towards the end to try and see which (if any) run at the proper time.

In the meantime, I have added this (which I don’t really care for). This basic logic worked in a test piston, but it feels sloppy to me


#15

I can say with 100% confidence that this method works well:

global

My global @nextMoonEvent changes twice a day, so the empty blocks every 8 hours will always capture the new global time before the real event happens (and schedule my wakeup accordingly)


As far as changing the global manually vs programmatically…

The reason I asked is because there are a few red flags in your piston that sets the global time:

A) I think this highlight should be enclosed in parenthesis (like B & D)

B, C & D) I have never tried using a dash to invert a number to a negative number.

define variable = 20
addMinutes($sunset,-variable)

is not the same as

define variable = -20
addMinutes($sunset,variable)

(Notice the dash moved)

If I want a negative offset, I always use the second method.
I make the variable negative in a previous command, and then just call the variable like normal.


If there is a bug with your code, then the global will not be set properly, and the other piston will not react to the new time.


#16

By the way, a quick way to invert a positive variable to a negative number is:

posVar - (posVar * 2)

So, for example, 25 - 50 = -25


For the record, I always convert to a negative number before the addMinutes section


#17

I am completely positive that the global time variables are being calculated and updated properly. I have tested and logged this several times and it’s correct.

Parenthesis aren’t needed on A as there is only 1 operator so there’s no order of precedence to consider (it wouldn’t hurt, but it wouldn’t help either)

Actually those two statements would (and do) evaluate to be exactly the same. When you negate the number doesn’t matter, as long as you pass a negative number to addMinutes it will offset to before the specified time. In both of your examples you are passing -20 to the function

From the wiki:

addMinutes

Syntax

addMinutes(datetime value, integer minutes)

Returns

Returns a datetime that is minutes minutes after the value . For negative values of minutes , it returns a datetime that is minutes minutes before value .

Again, I have checked the values of the calculated times after they are calculated and the values are correct, but the lighting piston isn’t updating it’s schedule to those new values for whatever reason. Fundamentally I don’t know what the difference is between your nextMoonEven subscription and mine. They should behave the same


#18

is not the same as:
addMinutes(datetime value, integerVariable+anotherIntegerVariable)

I would write it like this:
addMinutes(datetime value, (integerVariable+anotherIntegerVariable))
so the math is done FIRST, and then there is only a single integer for the rest of the formula


This can actually be one of the toughest things to get right. Just because a log shows X, does not mean the global was written correctly. (and of course, the same piston cannot report/log any changes to the global until the NEXT execution)


At the risk of sounding like a broken record:
dash(posVar) is not treated the same as {negVar}

Do with that what you will…


#19

If you look at my piston I am saving the calculated value into a temporary variable. Which I then use to update the piston state, as well as the global. That value in the state (and after completion, in the global) is always right.

Can you substantiate this? Because my experience in webCoRE, as well as several other programming languages says otherwise. It’s a very common and simple way to negate an integer, which is what we’re dealing with. Nothing too fancy


#20

OK, no problem… I have invested enough time with this one, so I’ll let someone else chime in…


#21

Please ignore everything I said about the red flags above
I ran a few tests, and in this case, your syntax holds up. :+1:

Everything else I said was accurate…


#22

Thanks. I wasn’t trying to be a dick or anything, but the calculation of the time was one part I was confident was correct. It was the scheduling/execution of the other piston I was questioning.

Anyways, further testing this morning. As recommended by guxdude, I experimented with using Time as the the trigger as can be seen below:

image

In this case, both "Test number 3" & "Test number 4" executed as expected, as can be seen by the logs

10/17/2019, 8:54:29 AM +159ms
+1ms ╔Received event [PRM].time = 1571327670000 with a delay of -841ms
+126ms ║RunTime Analysis CS > 29ms > PS > 73ms > PE > 24ms > CE
+129ms ║Runtime (42313 bytes) successfully initialized in 73ms (v0.3.110.20191009) (127ms)
+130ms ║╔Execution stage started
+159ms ║║Comparison (time) 32069315 happens_daily_at (time) 32040000 = false (1ms)
+160ms ║║Cancelling condition #8's schedules...
+161ms ║║Condition #8 evaluated false (5ms)
+165ms ║║Cancelling statement #8's schedules...
+170ms ║║Requesting time schedule wake up at Fri, Oct 18 2019 @ 8:54:00 AM PDT
+172ms ║║Cancelling condition #7's schedules...
+173ms ║║Condition group #7 evaluated false (state changed) (18ms)
+178ms ║║Comparison (time) 32069334 happens_daily_at (time) 32040000 = true (0ms)
+179ms ║║Time restriction check passed
+181ms ║║Cancelling condition #12's schedules...
+181ms ║║Condition #12 evaluated true (6ms)
+190ms ║║Cancelling statement #12's schedules...
+195ms ║║Requesting time schedule wake up at Fri, Oct 18 2019 @ 8:54:30 AM PDT
+197ms ║║Cancelling condition #11's schedules...
+198ms ║║Condition group #11 evaluated true (state changed) (23ms)
+200ms ║║Cancelling statement #13's schedules...
+205ms ║║Test number 4
+206ms ║║Executed virtual command log (1ms)
+231ms ║╚Execution stage complete. (101ms)
+238ms ║Setting up scheduled job for Fri, Oct 18 2019 @ 8:52:00 AM PDT (in 86250.604s), with 3 more jobs pending
+249ms ╚Event processed successfully (249ms)
10/17/2019, 8:53:59 AM +71ms
+1ms ╔Received event [PRM].time = 1571327640000 with a delay of -929ms
+121ms ║RunTime Analysis CS > 21ms > PS > 74ms > PE > 25ms > CE
+123ms ║Runtime (42315 bytes) successfully initialized in 74ms (v0.3.110.20191009) (122ms)
+124ms ║╔Execution stage started
+159ms ║║Comparison (time) 32039227 happens_daily_at (time) 32040000 = true (1ms)
+160ms ║║Time restriction check passed
+162ms ║║Cancelling condition #8's schedules...
+163ms ║║Condition #8 evaluated true (6ms)
+166ms ║║Cancelling statement #8's schedules...
+170ms ║║Requesting time schedule wake up at Fri, Oct 18 2019 @ 8:54:00 AM PDT
+173ms ║║Cancelling condition #7's schedules...
+174ms ║║Condition group #7 evaluated true (state changed) (18ms)
+176ms ║║Cancelling statement #9's schedules...
+181ms ║║Test number 3
+182ms ║║Executed virtual command log (2ms)
+188ms ║║Comparison (time) 32039256 happens_daily_at (time) 32040000 = false (1ms)
+189ms ║║Condition #12 evaluated false (4ms)
+195ms ║║Cancelling statement #12's schedules...
+199ms ║║Requesting time schedule wake up at Thu, Oct 17 2019 @ 8:54:30 AM PDT
+202ms ║║Condition group #11 evaluated false (state did not change) (17ms)
+226ms ║╚Execution stage complete. (102ms)
+233ms ║Setting up scheduled job for Thu, Oct 17 2019 @ 8:54:30 AM PDT (in 30.696s), with 3 more jobs pending
+243ms ╚Event processed successfully (243ms)

I believe this is because are now subscribed to the Time object, rather than relying on a schedule. So whenever Time changes and matches our condition, it fires.

I still question why the schedule didn’t work, but at least for my scenario where the schedule is changing daily, this other approach seems more reliable. I am going to implement this change into my lighting piston and see if it works. Based on my testing, I suspect it will.

Thanks again for your help


#23

Following up. I changed my code to use the following trigger and it’s been working perfectly since

Time happens daily at {@turnOnTime}

Thanks