[Solved] Postponed rule execution? Do rules get put on stack?

Thanks, that seems to be what I wanted.

Is there any better solution for that? I can imagine that using “persistence” I could set some time after motion detection?

So you say this rule would be better?:

var Timer doorlighttimer = null
rule "door light" 
when
    Item door_contact changed to OPEN
then
    if (door_light.state != ON) {
        sendCommand(door_light,ON)
        if(doorlighttimer === null) {
            doorlighttimer = createTimer(now.plusMinutes(1), [|
                if (door_light.state != OFF) {
                    if ((door_contact.state != CLOSED) || ( door_motion.state != 0 )) {
                    doorlighttimer.reschedule(now.plusMinutes(1))
                    }
                    else {
                        sendCommand(door_light,OFF)
                        doorlighttimer = null
                    }
                }
                else {
                    doorlighttimer = null
                }
            ])
        }
    }
end

No idea. I don’t know what you want to happen.

Persistence in openHAB is about keeping historical records, Can’t see the application here?

I wanted exactly what you described. I just thought you were suggesting there is something that can be done better or differently, like checking when the motion was triggered or something… never mind. I’ll be happy with that rule if it won’t cause problems

With all respect, there is no grizzle here. I cannot program, even as simple things. I can only copy and paste and adjust what exists. That’s how I wrote the timer rule. I don’t know for sure, but I can imagine there are other people like me, that can be clumsy in writing rules. I would not use an uncertain rule for security devices. But I can imagine things, and I can possibly imagine there is someone who would do that - write a poorly designed rule and use it inadequately. It is a security risk for me. Using thread::sleep I had one problem in 3 years with my light and try to do things better. You tell me I use the worst possible solution, but I don’t even know why the Thread::sleep exists. You can be sure I didn’t invent it. I found it on this forum. So people do use it for some reasons.
I tried another system before, where there was a manual lock for maximum number of rule instances that can be run simultaneously. Even more, you could check how many instances are already running and do a simple “if there are already 3, then don’t execute the rule at all”.
Now that’s something I call giving user the choice. For other reasons I don’t want to use the other system, I want to use OH. I am very sorry my invalid assumption disturbs you, but in that other system they did it for a reason. So I don’t think I’m the only one thinking the decisions on what to do with incorrectly invoked rules may be more granular.
From what I understood of your answer, this system is not designed to ignore clumsy rules automatically and is not allowed to silently exit with errors. I don’t know the mechanisms behind that. I accept that. I need (want) to have an insightful opinion on that.

This is correct. There is no way round it, the vast flexibility of openHAB does require some technical skills and the learning curve is steep.
Part of that flexibility is that if you dislike DSL rules you can use other rules setups. Look into NodeRed.

The distinction is that queuing events and activities is a design feature, not an error. By design, this system is intended to run on underpowered cheap hardware and cope as well as it can. That necessitates this kind of action.

If you want to write rules to ignore events under some circumstances, that’s your business, it’s no problem. You’ve just done one. There are other ways to do it too.

If someone else wants to write a rule that counts how many times you can push a button in a minute, they can do that without fear of missing one.

If you want to reduce the number of rule threads to 3, you can.

So far as I know there is no simple way to limit the number of times you can trigger a given rule “simultaneously”.
But here comes openHABs flexibility …

It would be possible to construct some complicated mechanism involving reentrant locks and a counter if you really wanted it.
Note, that there is nothing inherently wrong with using reentrant locks - BUT it’s a complete arse to develop, because
(a) you have to reeaally think about multithreading and
(b) when you make a tiny error in your rule you’ve “lost” the lock (or rather,the unlock) … making thorough development of anything non-trivial very difficult.
I would not recommend it and see no value in it here.

@hoomee I would look at the expire binding personally for this task.

I use it for my motion detector. If motion gets triggered on then the light switch gets updated. This intern updates the expire timer.

This in my mind is an alternate way to handle the problem and I believe it takes some complexity out of the rule.

2 Likes

Yes. But only if you write your rules in a way that supports that. Long running rules do not allow that.

To avoid long running rules, you must use timers instead of sleeps.

I don’t know how to answer that. It runs one second from now (based on your example). Exactly what runs depends on what code you put between the . If you want to log out “hello world” one second from now:…

createTimer(now.plusSeconds(1), [|
    logInfo("test", "hello world")
])

The stuff between [ and | is how you world pass arguments to the that little block of code, which you don’t have to do for timers so you will usually either see the | omitted or nothing between the [ and |. To see an example when full explanation where stuffy is put been the [ and| see Reusable Functions: A simple lambda example with copious notes.

tl:dr, because the underlying programming language offers it. There is no way to hide that it exists not any way to prevent it’s use. And in certain circumstances, it can be useful, so long as the sleeps are short (fractions of a second).

You can find lots of stuff on this forum that either were never right, never a good idea, or is no longer the best way. It’s hard enough keeping up with the docs let alone going around and cleaning up everyone’s forum postings. Pay attention to the age of the post. If it’s more than a year old, look for more recent examples of you can. There might be a better way.

Thank you, I will check that, just to understand it better.

Thanks for the idea, but if I got you right, anytime you turn the light on, it will turn off after given time.
I want to have the possibility to turn it on manually without expiring. I use “expire” on few other lights though.

So it’s there for passing the arguments. It seems to be exactly the answer to my question. Thanks.

Sorry for bothering you, but I have some cron invoked rules (midnight in that case) and I’ve read the advice somewhere to make the thread sleep for second or two just to let Astro binding to recalculate times of day.
Also some system stuff may be happening at midnight.
Would you consider this a valid point?
Or is there a better way of how to write a rule to be run at midnight? (beside the obvious one to make it run at 0:01)

Thinking about it I have another question. Do timers - invoked from withing a rule - live outside the rule? In other words: the rule is executed and finished but the timer continues to count down in a separate thread?
If not, how does it work?
If yes: wouldn’t my new rule with timers, the one I have written above, also call many timers and wouldn’t they end after some time with blinking light? If not, can you explain why?

And one last (hopefully) question. In a rare case there are 10 different, good written, rules called simultaneously - will execution of the 6th and next be blocked until the 1st is closed? If there are timers in each of the hypothetical rules, the execution will be almost immediate? (in seconds?)

Why wouldn’t you do that? It costs nothing.

Nearly. A separate system manager looks after the scheduling. createTimer() really just registers “run this code at 0845 please”. No thread is consumed until it executes.
The rule that registered it has long since exited.

Look at the rule again. If the timer already exists, a new one is not made. (consider what the ‘handle’ being null means here)

@rossko57 Thanks for the explanations.

Now, I see that :slight_smile:
I assume the timer is identified with its name and not with the process ID.

It costs nothing indeed, that’s why I considered it obvious, but the idea was not mine, remember?
I don’t know why the author chose it this way. I can only change my rule now and hope it won’t break anything.

I have deleted all sleep times from all my rules now, and I have another problem.
One rule (let’s call it Rule 1) should only trigger some action if it is already “night”. The other rule (let’s call it Rule 2) takes about 90 msec to check and write “night” to the variable (the one needed to accomplish my action in Rule 1). Both rules are triggered by the same astro-event.
(Rule 1 depends on the output of Rule 2)

Considering:

and my 90 msec delay (87 msec in the last log to be precise),
will 100 msec delay be always sufficient? Or is it possible that sometimes, due to heavier load for instance, Rule 2 would get more delay, so Rule 1 wouldn’t work as intended?

I think/imagine the Rule 1 takes also some time (few msecs?) to execute, so it exits/ends at some point after the triggering effect, in fact diminishing the difference a little (probably little less than 87 msec), but is 100 msec enough? Will it be 100% reliable?

Can’t you concatenate then into one rule? Where the one that checks if it’s night runs last. Then you can use a variable instead of an item temporarily (updating an item and then reading it right after is not reliable, but you can still update it for later rule runs of course).

I believe it’s best practice to do this for rules that share the exact same trigger, unless they are completely independent.

1 Like

Triggering two processes from the same event is a design choice, perfectly acceptable.

If process B relies on some output of process A however, you have designed in a race condition. Unpredictable outcomes.

Giving one process a head start in the race - adding a delay - improves your odds, but is not a cure. The longer the delay, the better the odds, but still no guarantee.

The way to make it entirely predictable is to make it a relay race; process B triggered not from the original event, but from process A.

These truths I hold to be self-evident :wink:

2 Likes

Well, most probably I could, but they are completely independent. Rule 1 is triggered by and responsible for quite other events. But you got me thinking about design and…
is it possible for a rule to be triggered by a variable change/update?
So instead of triggering Rule 1 by the same astro-event, it could start only when the variable changes to “night”?

No, but Items are available to you.

OK, so basically I’d need a virtual switch, which is ON when the variable is set to “night”?
I can do it only from Rule 2 (the one responsible for updating the variables from astro-events)? or is there any other way?
Then I trigger Rule 1 from that virtual switch, correct?

As it’s getting more and more complicated :wink: do you know of a good way to document my setup? So I don’t loose track of those dependencies…
I’m afraid that when I for whatever reason have to recreate or slightly change it, I won’t be able to follow all the dependencies. Like what was that switch here for? Shall I remove it completely or will the house burn if I do it?

With little idea of what you’re trying to do, I can’t advise much.
Using virtual Items to represent stuff like “nighttime” is pretty standard practice, it’s then available to any rule in the system for any purpose - command, update, interrogate, trigger from.

For documentation I assume I’ve been run over by a bus and dropped the paperwork down a drain.
As I develop rules I simply add explanatory comment lines. Costs nothing.
I use mostly xxx.items and xxx.things files, which allow for comments about the stuff defined there. Relationships, purpose, naming conventions, etc.
What PaperUI users do, I don’t know.

Sample from one of my items files

// GENERAL.ITEMS

// NAMING CONVENTIONS
// dt_xxx   DateTime item
// sw_xxx   Switch item
// ct_xxx   Contact item
// nm_xxx   Number item
// sg_xxx   String item
// v_xxx    virtual item, any type

// for restore on startup etc.
Group gRestore "for restore on startup"
Group gChart "for graphing numeric data"
Number nm_chart_period "Graphing period" <line> (gRestore)

//  switch to indicate darkness by rule
Switch vsw_Darkness "Nighttime [%s]" <dark>
// ALARMS status
// coded status 0=fault 1=disarmed 2=partset 3=fullset 4=ringing   not all may be implemented in hardware
Number vnm_Fire "Fire Alarm [MAP(alarms.map):fire%s]" <ifire> (gRestore)
Number vnm_Intruder "Intruder Alarm [MAP(alarms.map):intruder%s]" <ialarm> (gRestore)

Thank you.
Apart of my layman’s naming patterns (and having multiple files for items of different kind), that’s what I’m trying to do already, but even if I write a comment in switches for instance and forget to add a comment in the rule, there is no way to trace it back. I guess I’ll have to live with it.

I have a similar usecase as yours (bet many users do) where I have a Switch item named Daylight that gets set to ON when Astro binding triggers sunrise and OFF at sunset. Then I can query this item in other rules that depend on it. For me this makes the code quite self-documenting:

if (Daylight.state == ON) {
   // Do stuff
}

If your Rule 1 is triggered by sunrise/sunset and is also dependant on the state of your Nighttime item you could change the trigger to Nighttime changed from OFF to ON.

1 Like

Have you seen [Deprecated] Design Pattern: Time Of Day? That’s one of the of the reasons that DP exists. Process time of day events in only one place and update an Item with the result (i.e. the time of day). Everywhere else that cares about the time of day triggers on that Item changing or checks the state of that one Item.

This should make things much simpler over all. Need to add another time of day that you care about? You’ve one place to look and edit. Need to have another Rule that needs to know the time of day? Just check the one vTimeOfDay Item.

And if you use meaningful names for your Items, the name of the Item itself should tell you what it’s there for.

You trace it back using the Item name. If you forget what the “Nighttime” is for, open your .items file and look for it. If you’ve put comments in at least one of the places you will find it. But for the most part, the fact that the Item is named “Nighttime” and is used as a Switch in the Rule should be just about all you need to understand that it’s a Switch that turns on when it is night.

This is one of the reason why I’m a big proponent of using meaningful Item names and why I recommend naming Items independent of the technology they are linked to. “Livingroom_Lamp” is a whole lot more meaningful than “Zwave_Switch7”.

while (door_light.state != OFF) {
}

That looks like an infinite loop to me…