[SOLVED] Are rules multi-entrant?

I posted the same code before, though with a different question… this time I wonder if the rules are actually multi-entrant.

Why does this code:

timerLockEmailLocus_1  and blnEmailLockLocus_1  are properly defined outside the rule

          // if within 400 metres of Locus_1
          if (DistanceFromLocus_1.state < 0.400) {
            logInfo("Geo.3.3", "DistanceFromLocus_1....: {}", DistanceFromLocus_1.state)
            // if we haven't sent an email yet
            if (blnEmailLockLocus_1 == false) {
              logInfo("Geo.3.4", "Send email at Locus_1")
              sendMail(emailToMax,  "Max is 20 minutes away", "Max is roughly 20 minutes away")
              blnEmailLockLocus_1 = true
              logInfo("Geo.3.5", "set blnEmailLockLocus_1 to true (={})", blnEmailLockLocus_1)
              // start timer to reset blnEmailLockLocus_1 to false in 120 seconds
              timerLockEmailLocus_1 = createTimer(now.plusSeconds(120), [|
                blnEmailLockLocus_1 = false
                logInfo("Geo.3.6", "set blnEmailLockLocus_1 to false (={}) in 120s timer", blnEmailLockLocus_1)
                timerLockEmailLocus_1 = null

produce this result:

2018-11-21 06:05:30.823 [INFO ] [g.openhab.model.script.Geo.3.3] - DistanceFromLocus_1....: 0.199
2018-11-21 06:05:31.870 [INFO ] [g.openhab.model.script.Geo.3.4] - Send email (at Locus_1)

2018-11-21 06:05:37.606 [INFO ] [g.openhab.model.script.Geo.3.3] - DistanceFromLocus_1....: 0.199
2018-11-21 06:05:37.616 [INFO ] [g.openhab.model.script.Geo.3.4] - Send email (at Locus_1)

2018-11-21 06:05:43.888 [INFO ] [g.openhab.model.script.Geo.3.3] - DistanceFromLocus_1....: 0.018
2018-11-21 06:05:43.898 [INFO ] [g.openhab.model.script.Geo.3.4] - Send email (at Locus_1)

2018-11-21 06:05:47.258 [INFO ] [g.openhab.model.script.Geo.3.3] - DistanceFromLocus_1....: 0.018
2018-11-21 06:05:47.268 [INFO ] [g.openhab.model.script.Geo.3.4] - Send email (at Locus_1)

2018-11-21 06:05:49.275 [INFO ] [g.openhab.model.script.Geo.3.5] - set blnEmailLockLocus_1 to true (=true)
2018-11-21 06:05:50.851 [INFO ] [g.openhab.model.script.Geo.3.5] - set blnEmailLockLocus_1 to true (=true)
2018-11-21 06:05:56.433 [INFO ] [g.openhab.model.script.Geo.3.5] - set blnEmailLockLocus_1 to true (=true)
2018-11-21 06:05:57.561 [INFO ] [g.openhab.model.script.Geo.3.3] - DistanceFromLocus_1....: 0.215
2018-11-21 06:06:00.192 [INFO ] [g.openhab.model.script.Geo.3.5] - set blnEmailLockLocus_1 to true (=true)
2018-11-21 06:06:04.486 [INFO ] [g.openhab.model.script.Geo.3.3] - DistanceFromLocus_1....: 0.396
2018-11-21 06:07:52.817 [INFO ] [g.openhab.model.script.Geo.3.6] - set blnEmailLockLocus_1 to false (=false)
2018-11-21 06:07:53.260 [INFO ] [g.openhab.model.script.Geo.3.6] - set blnEmailLockLocus_1 to false (=false)
2018-11-21 06:07:56.444 [INFO ] [g.openhab.model.script.Geo.3.6] - set blnEmailLockLocus_1 to false (=false)
2018-11-21 06:08:00.202 [INFO ] [g.openhab.model.script.Geo.3.6] - set blnEmailLockLocus_1 to false (=false)

It looks to me that the rule gets hit and before the lock is set to true, it is triggered a few more times… and then the rest of the rule (see log 3.5 and 3.6) kick in. Also indicating the timer is set multiple times (4 times in this example).

What do I need to do to have this code set the email lock after the first time I am in the <400m radius?

What I have done is moving the email lock = true before the sending of the email; however, I can test and report the result only the next morning…

If this works, then the rule is entered in at every GPS event, is then held up by the sending of the email, and once that’s sent, it continues with setting the lock to true (As it currently does), and then finishes the (four) timers 120 seconds later. – It sort of seems to work like that!?

How offen this rule is triggered depends in the trigger selected. Each change of the position would have caused such behaviour.
I would set the lock in the first line, check if closer and do stuff. Under the lock if times run out or if position isn’t close enough.

Well, the log file provides the timings; every 4-5 seconds I get a GPS update; completion of the first email takes 19 seconds, I drive through the 800m in less than that; hence, by the time I am through, the first email sending has finished, and the rest of the rule happens.

As I said, I moved the line blnEmailLockLocus_1 = true:

            if (blnEmailLockLocus_1 == false) {
              logInfo("Geo.3.4", "Send email at Locus_1")
              blnEmailLockLocus_1 = true
              logInfo("Geo.3.5", "set blnEmailLockLocus_1 to true (={})", blnEmailLockLocus_1)
              sendMail(emailToMax, "Max is 20 minutes away", "Max is roughly 20 minutes away")

before sending the email, which should, if my assumptions are correct, fix the problem; by blocking subsequent email after hitting the first GPS location with the 400m.

[Later edit: Shifting the lock before the sendMail fixed the issue!]

To be clear, yes. So you need to take precautions as you’ve already worked out.

var/val declared inside the rule should be “safe” and each running version of the rule has it’s own private copy.

Global var/val declared outside the rule, and of course Items, are shared. So sometimes you’ll need to take precautions about that specifically. e.g some other rule might have changed a var since the last time you looked at it, you may need to take a local copy or somehow lock it.

Unfortunately I have a headache today and am clearly not thinking super clearly. I really don’t understand why your current Rule is behaving the way it is, unless you have some Thread::sleep lines in this Rule not shown above.

Does it really take like 18 seconds to send the email? If so that is probably the root of the problem. As Opus said, set the lock before you send the email. That will probably clear up the immediate problem.

Were I to implement something like this though, I would probably not use a Timer at all. Instead I’s set a flag. When you are outside 400M the flag gets set to false. The first time you move from outside 400M to inside 400M set the flag to true and then send the email.

When the Rule triggers, if you are inside 400M and the flag is true don’t send the email. Then the email will only ever be sent once until you leave and return again.

Thank you all for looking at this and providing solutions.

In short: shifting the emaillock before the sendMail fixed the problem for good.

I get that there are multiple ways to skin a cat (or code the code).

So it is clear to me now, that:
a) the rule will be executed with every trigger; here = new geoLocation
b) while I coded it as the logical flow goes -> send email then lock it; because of the time it takes for the sendMail to do its bit, I have to set the lock then send the mail.

@rlkoshak: I used a timer to avoid evaluating another geoLocation; also the location to report on may relocate elsewhere, depending on the 'warning time" I want to provide. All I have to do is shift the trigger location; the timer to reset it no matter what and where.

There is often more behind the set-up that meets the eye or is worthwhile sharing.
This is already the third trigger location. It is only active in the sixth hour of the day of every workday; it has a main switch (switching off this rule part in the actual rule).

I use a similar rule, *which I had first, before this one), which reacts to a decreasing distance in a radius to open the gate on approach. A timer closes the gate, as I did not want to install further hardware in the field to close it.

In any case, thank you all :slight_smile: