If statements and task cancellation


#1

1) Give a description of the problem
If statements do not cancel tasks on change of variable

2) What is the expected behaviour?
I expected from reading posts on here that when the If statement changed to false, it would cancel the block.

3) What is happening/not happening?
I run this piston and the log is
One
Two
Three
Four

I had expected just One, Three. I want the tasks to stop running when the variable changes.

Is there any way to do that please?

Thank you!

**4) Post a Green Snapshot of the piston![image|45x37]


#2

This piston has no triggers…


#3

Thanks. I’m running the piston from Test. I get

One
Two
Three
Four

and what I expected is that when I change the variable, the block would stop, so I would get

One
Three

I’ve simplified this from the actual piston.

What I want to do, if you’re interested, is have the piston stop running when another device changes.


#4

Your current piston runs top to bottom in a quarter second…

The normal logic is:
If there is a WAIT in progress, and another trigger comes in, then the piston will begin again at the top.


#5

That’s what I understood. See the attached. I put a wait statement in and it doesn’t help.
So my understanding (running as Test) is that changing the variable in the second step to false should stop the whole block, but it doesn’t, the block runs to the end.

(as I say, the actual thing I’m trying to get to is a series of steps on one light which are aborted if something else changes)


#6

Notice that no other trigger came in during the WAIT…

Personally, the fake execution via Test is probably not the way I would approach this.

Simplifying a piston is wise during testing, but keeping the trigger consistent is usually preferred.

That being said, on line 17 you are forcing TRUE each time the piston begins (or returns from a WAIT).


Pro Tip:

This logic is usually best avoided:

IF X changes
    Then change X
END IF

#8

Thanks.
Perhaps it’s too artificial the way I’m asking.
This is what I’m trying to do. Changing the second light stops the first light from its shutting down process.

I expected that if the boolean variable changed it would abort the If block.
I can put each action in its own If statement, but this makes me think there’s something I’m missing.

Is it that If is a Condition not a Trigger? But what Trigger would I use?


#9

I am wondering if perhaps you’ve been reading some of the older posts about the task cancellation policy where it, and the behaviour of triggers in particular, was rather badly misunderstood. It didn’t stop users creating correct pistons, they just didn’t work for the reasons they thought they did.

A webCoRE piston is an event handler that generally executes from top to bottom like a script. Because there is an execution time limit on webCoRE pistons, a ‘wait’ of five seconds or more (and a shorter one where there would be less than ten seconds execution time left afterwards) is implemented by scheduling a new instance of the piston at the appropriate time and exiting the piston. This is called a ‘scheduled task’. When the piston wakes up it will fast forward to where it was and continue.

If the a piston responds to another event while in a ‘wait’ it will run a new instance which might evaluate the conditions differently. If this happens it assumes, by default, that as the condition has changed you aren’t going to need the scheduled tasks that were set up previously and so cancels the scheduled tasks (you’ll see that appear a lot in the logs). The piston will still wake up but it will just exit again.

In older posts you will see people thought that triggers (e.g. switch changes to on) were only true for a short period of time and that when waits were over the condition controlling its execution was reevaluated. Neither was true.


#10

In reference to piston g743:

There is no trigger on Bulb 9, so that piston will only execute when Bulb 10’s level changes.
(as seen by the lightning bolt in the left margin)

When Bulb 10’s level changes, it starts at the top, and changes Bulb 9 first.

In other words, Bulb 10 will not abort the piston… It in fact executes it.


Pro Tip:

If you want Bulb 10 to abort Bulb 9, then they both needs to be a trigger.


#11

Just to clarify a bit…

This was true, and is still true if another trigger executes the piston.


Depending on the way it is nested, this can also still be true.


#12

My point is that triggers are just comparisons so they have no inherent value. In older posts they were described like an object that was true for a fixed time (e.g. ten seconds) and then became false.

Again in older posts you see the process of waking up from a wait being described as if the condition governing it gets magically evaluated again and that is where it decides whether to continue or not. In reality if it hasn’t already been cancelled by another instance of the piston it just continues after the wait.


#13

Thank you for your explanations, both of you, I have learnt a lot.

I now have it working pretty much as I expected, attached.

  1. I had to turn on Parallelism in settings

  2. I had to include that Wait statement at line 33, and that doesn’t matter, but this seems odd behaviour to me. Say I want to stop the bulb shutting down by changing “Bulb 10” during the 20 second wait on Warm White at line 37. That works as I want, the change of variable cancels the block. But without that wait at line 33, the bulb will go red again and then stop. So the change in variable causes the task to restart, but then it runs the first statement in the block only, even though the variable in the conditional if statement is false. That’s a bit strange. But it works!

@WCmore, thank you also. I have been running the Piston from Test because I want it to be launched from another piston with arguments, so I don’t think the first part needs its own trigger.

Thanks again


#14

In that case, you are correct.


#15

Actually, excuse me, it seems it works without Parallelism too, now. I don’t know what happened to make me think I needed that on.


#16

On piston 5avt0, I would love to see the events in the Logs when set to Full…
(if you are willing)


#18

Here goes.

And it seems I do need parallelism to stop the task again. I wonder why sometimes I do not.


Logs
19/11/2020, 02:36:06 +66ms
+0ms	╔Received event [Home].time = 1605753367055 with a delay of -990ms
+219ms	║RunTime Analysis CS > 19ms > PS > 176ms > PE > 25ms > CE
+222ms	║Runtime (40910 bytes) successfully initialized in 176ms (v0.3.10a.20190223) (220ms)
+223ms	║╔Execution stage started
+227ms	║╚Execution stage complete. (5ms)
+234ms	╚Event processed successfully (234ms)

19/11/2020, 02:36:04 +922ms
+1ms	╔Received event [Lounge Right].level = 48 with a delay of 78ms
+107ms	║RunTime Analysis CS > 16ms > PS > 66ms > PE > 24ms > CE
+109ms	║Runtime (40901 bytes) successfully initialized in 66ms (v0.3.10a.20190223) (107ms)
+110ms	║╔Execution stage started
+117ms	║║Comparison (boolean) false is (boolean) true = false (1ms)
+119ms	║║Condition #2 evaluated false (4ms)
+120ms	║║Condition group #1 evaluated false (state did not change) (5ms)
+124ms	║║Comparison (integer) 48 changes = true (0ms)
+126ms	║║Condition #10 evaluated true (3ms)
+127ms	║║Condition group #9 evaluated true (state did not change) (4ms)
+129ms	║║Cancelling statement #11's schedules...
+134ms	║║Executed virtual command setVariable (3ms)
+151ms	║╚Execution stage complete. (41ms)
+158ms	╚Event processed successfully (158ms)

19/11/2020, 02:36:03 +24ms
+0ms	╔Received event [Lounge Right].level = 50 with a delay of 104ms
+91ms	║RunTime Analysis CS > 17ms > PS > 52ms > PE > 22ms > CE
+93ms	║Runtime (40898 bytes) successfully initialized in 52ms (v0.3.10a.20190223) (92ms)
+94ms	║╔Execution stage started
+101ms	║║Comparison (boolean) false is (boolean) true = false (1ms)
+102ms	║║Cancelling condition #2's schedules...
+103ms	║║Condition #2 evaluated false (5ms)
+104ms	║║Cancelling condition #1's schedules...
+105ms	║║Condition group #1 evaluated false (state changed) (7ms)
+110ms	║║Comparison (integer) 50 changes = true (1ms)
+111ms	║║Condition #10 evaluated true (4ms)
+112ms	║║Condition group #9 evaluated true (state did not change) (5ms)
+114ms	║║Cancelling statement #11's schedules...
+119ms	║║Executed virtual command setVariable (2ms)
+136ms	║╚Execution stage complete. (42ms)
+142ms	╚Event processed successfully (142ms)

19/11/2020, 02:36:00 +930ms
+1ms	╔Received event [Lounge Right].level = 53 with a delay of 77ms
+103ms	║RunTime Analysis CS > 16ms > PS > 65ms > PE > 23ms > CE
+105ms	║Runtime (40901 bytes) successfully initialized in 65ms (v0.3.10a.20190223) (103ms)
+106ms	║╔Execution stage started
+113ms	║║Comparison (boolean) true is (boolean) true = true (1ms)
+115ms	║║Condition #2 evaluated true (5ms)
+116ms	║║Condition group #1 evaluated true (state did not change) (6ms)
+118ms	║║Cancelling statement #3's schedules...
+123ms	║║Executed virtual command [Lounge Left].wait (1ms)
+124ms	║║Requesting a wake up for Thu, Nov 19 2020 @ 2:36:07 AM GMT (in 6.0s)
+132ms	║║Comparison (integer) 53 changes = true (1ms)
+133ms	║║Cancelling condition #10's schedules...
+134ms	║║Condition #10 evaluated true (5ms)
+135ms	║║Cancelling condition #9's schedules...
+136ms	║║Condition group #9 evaluated true (state changed) (8ms)
+138ms	║║Cancelling statement #11's schedules...
+143ms	║║Executed virtual command setVariable (2ms)
+160ms	║╚Execution stage complete. (54ms)
+165ms	║Setting up scheduled job for Thu, Nov 19 2020 @ 2:36:07 AM GMT (in 5.96s)
+178ms	╚Event processed successfully (178ms)

19/11/2020, 02:35:56 +67ms
+0ms	╔Received event [Home].time = 1605753357660 with a delay of -1593ms
+127ms	║RunTime Analysis CS > 25ms > PS > 71ms > PE > 31ms > CE
+130ms	║Runtime (40909 bytes) successfully initialized in 71ms (v0.3.10a.20190223) (129ms)
+131ms	║╔Execution stage started
+187ms	║║Executed physical command [Lounge Left].setColor([[hex:    #DAF17E, hue:20, saturation:20, level:72]]) (37ms)
+188ms	║║Executed [Lounge Left].setColor (39ms)
+191ms	║║Executed virtual command [Lounge Left].wait (1ms)
+192ms	║║Requesting a wake up for Thu, Nov 19 2020 @ 2:36:16 AM GMT (in 20.0s)
+213ms	║╚Execution stage complete. (82ms)
+218ms	║Setting up scheduled job for Thu, Nov 19 2020 @ 2:36:16 AM GMT (in 19.975s)
+228ms	╚Event processed successfully (228ms)

19/11/2020, 02:35:51 +100ms
+1ms	╔Received event [Home].time = 1605753352899 with a delay of -1799ms
+515ms	║RunTime Analysis CS > 31ms > PS > 456ms > PE > 28ms > CE
+518ms	║Runtime (40911 bytes) successfully initialized in 456ms (v0.3.10a.20190223) (516ms)
+520ms	║╔Execution stage started
+552ms	║║Executed physical command [Lounge Left].setColor([[hex:    #FF0000, hue:0, saturation:100, level:50]]) (8ms)
+553ms	║║Executed [Lounge Left].setColor (11ms)
+557ms	║║Executed virtual command [Lounge Left].wait (1ms)
+559ms	║║Requesting a wake up for Thu, Nov 19 2020 @ 2:35:57 AM GMT (in 6.0s)
+583ms	║╚Execution stage complete. (64ms)
+591ms	║Setting up scheduled job for Thu, Nov 19 2020 @ 2:35:57 AM GMT (in 5.97s)
+602ms	╚Event processed successfully (601ms)

19/11/2020, 02:35:46 +752ms
+1ms	╔Received event [Home].test = 1605753346752 with a delay of 0ms
+120ms	║RunTime Analysis CS > 20ms > PS > 70ms > PE > 30ms > CE
+123ms	║Runtime (40905 bytes) successfully initialized in 70ms (v0.3.10a.20190223) (120ms)
+124ms	║╔Execution stage started
+133ms	║║Comparison (boolean) true is (boolean) true = true (1ms)
+135ms	║║Condition #2 evaluated true (6ms)
+136ms	║║Condition group #1 evaluated true (state did not change) (8ms)
+139ms	║║Cancelling statement #3's schedules...
+144ms	║║Executed virtual command [Lounge Left].wait (0ms)
+146ms	║║Requesting a wake up for Thu, Nov 19 2020 @ 2:35:52 AM GMT (in 6.0s)
+158ms	║║Condition #10 evaluated false (6ms)
+159ms	║║Condition group #9 evaluated false (state did not change) (8ms)
+174ms	║╚Execution stage complete. (51ms)
+180ms	║Setting up scheduled job for Thu, Nov 19 2020 @ 2:35:52 AM GMT (in 5.968s)
+192ms	╚Event processed successfully (192ms)

#19

I am honestly surprised this piston works at all…

When you spin a dial to set a light’s level, it spams the hub with many triggers… back to back… Each one trying to execute the same piston…

02:36:00.9 = Received event [Lounge Right].level = 53
02:36:03.0 = Received event [Lounge Right].level = 50
02:36:04.9 = Received event [Lounge Right].level = 48

In the example above:
at 2:36:00, the piston ran top to bottom (Condition #2 evaluated true)
at 2:36:03, the piston did not run top to bottom (Condition #2 evaluated false)
at 2:36:04, the piston did not run top to bottom (Condition #2 evaluated false)

Normally, anytime a piston executes, the variables defined up top are forced.
(although the spam you are creating seems to bypass that sometimes)


If this were my piston, I would ditch the ASYNC and Parallelism entirely, and find a solution without using either of those.


#20

OK. I think I’ll investigate only executing these steps if the other device has not been changed in the last X minutes.


#21

The piston is fired by the change in level on bulb 10. It initialises the variable to ‘true’ and evaluates the ‘async if’. It is true so it enters the ‘then’ block and starts executing it normally. When it comes to the first long wait, instead of scheduling a new run in x seconds time and exiting, it schedules the run and moves on to the next block where it sets the variable to false. That is how ‘async’ works. Without the initial ‘wait’ the variable doesn’t get set until after the light is set to red.

You should also bear in mind that it is the second change in level that hits the breaks on the first block. The first one sets the variable to false, the second one runs the piston and cancels the wait tasks. Except that I don’t know why it hasn’t reinitialised the variable to true.

Parallelism might sometimes help if the second level change catches the piston while it is executing the first rather than in one of the waits. Possibly. Maybe.

Not just me then. I’m certainly struggling with the variable not being initialised to true every time.


#22

Thank you for the explanation, that all makes sense.
And, yes, the piston was working for me, but not in the way I thought it was.

Oh. Ooops. That’s my fault. Between posting the piston and trying to understand it, I realised it was difficult to reset the light to test it each time, so I changed the variable definition to no initial value and just edited it true and false under variables in webCoRE before running it.

Why didn’t I just set it white at the beginning of the piston? I have no idea.

I wouldn’t have done that if I’d realised it was significant! I know the variable resets on each piston run, but I thought pressing Test was a single run. Something else I’m now understanding I’m wrong about.

I think that solves your mystery, sorry about that

I’m also seeing how my instinct to try to get things to work abstractly in code and then use the actual devices and triggers seems like it ought to be quicker and simpler, but isn’t really helping.

I’m now going to go away and see if I can get the same result in a less haphazard way.
Funny, I thought it was so simple!