OH3: Prevent Rule from re-run within a few seconds

After upgrading from OH2.5 to OH3 one of my rules stopped working.

var DateTime until = null

rule "TV on"
when
    Channel "homematic:HmIP-BSM:ccupi:000858A99D1234:1#BUTTON" triggered LONG_PRESSED
then
    if(until !== null && until.isAfter(now)) return;
    until = now.plusSeconds(5)

        if(Socket_TV.state == ON) {
            //Socket_TV.sendCommand(OFF)
            Scene_Cinema.sendCommand(OFF)
            logInfo("Cinema switch", "OFF")
        } else {
            Socket_TV.sendCommand(ON)
            logInfo("TV switch", "ON")
        }
end

The reason for the DateTime var outside of the rule itself was, that in this case it was possible to trigger the rule only once within 5 seconds. Otherwise the rule is running several times during the LONG_PRESS.

I created a new rule:

triggers:
  - id: "1"
    configuration:
      event: LONG_PRESSED
      channelUID: homematic:HmIP-BSM:ccupi:000858A99D1234:1#BUTTON
    type: core.ChannelEventTrigger
conditions: []
actions:
  - inputs: {}
    id: "2"
    configuration:
      type: application/vnd.openhab.dsl.rule
      script: |
        var ZonedDateTime until = null
        if(until !== null && until.isAfter(now)) return;
        until = now.plusSeconds(5)

        if(Socket_TV.state == ON) {
            //Socket_TV.sendCommand(OFF)
            Scene_Cinema.sendCommand(OFF)
            logInfo("Cinema switch", "OFF")
        } else {
            Socket_TV.sendCommand(ON)
            logInfo("TV switch", "ON")
        }
        until = null
    type: script.ScriptAction

Unfortunately it does not behave as intended (during the LONG_PRESS, the switches a triggered several times ON, OFF, ON, …). I think it is because until = null is set every time the rule is triggered (on not when it is loaded as it was before in OH2.5). I can’t find a solution though.
Any ideas would be appreciated, even with a different logic.

Thanks!

That’s right, you specifically create it and set to null every time you run the rule.

In DSL rules, you can use ‘globals’ as you did before; declared outside of any rule, it survives between rule runs. You can still do exactly that when defining DSL rules in xxx.rules files.

You can’t do it when defining DSL rules with the UI, because you have no access to “outside of the rule”.

Other rule languages like javascript can pull off the trick, as one alternative.

Or use a completely different approach - make an Item as your “between runs survivor”. A Switch say - send it an ON every time you want to begin blocking, have expire feature auto-set it to OFF after a while. Test it in your rule before doing whatever.

That’s it! Thank you very much. My tv-switch.rules no looks like this:

//import java.time.format.DateTimeFormatter

var ZonedDateTime until = null
//var DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy - HH:mm:ss Z")

rule "TV switch"
when
    Channel "homematic:HmIP-BSM:ccupi:000858A99D1234:1#BUTTON" triggered LONG_PRESSED
then
        //logInfo("TV switch", "triggered")
        //logInfo("TV switch", "now" + now.format(formatter))
        if(until !== null && until.isAfter(now)) return;
        until = now.plusSeconds(5)
        //logInfo("TV switch", "plus5: " + until.format(formatter))

        if(Socket_TV.state == ON) {
            //Socket_TV.sendCommand(OFF)
            Scene_Cinema.sendCommand(OFF)
            logInfo("Cinema switch", "OFF")
        } else {
            Socket_TV.sendCommand(ON)
            logInfo("TV switch", "ON")
        }
end

The automatically migrated version did not work, because of the use of DateTime (instead of ZonedDateTime), but now I am back to the file-based rule.

Additional question: I was setting up file based things, items etc. in OH2.5 because I versioned them with git. Is this also possible for the UI-generated rules, things etc.?

One other minor behavior change in rules in OH 3 that might be relevant in a use case like this is that in OH 2, you could have more than one instance of a given rule running at the same time. In OH 3 that is no longer the case. Each rule can only have one instance running at a given time. So if your rule is running and get’s triggered again, the second trigger will queue up and wait for the rule to exit. So if you have a bunch of triggers and a slow running rule you might start to see a growing latency in the processing of the events. But at least you won’t run out of threads causing all your rules to stop running.

First of all, all that configuration stuff done through the UI is in $OH_USERDATA/jsondb and they are stored as JSON formatted text files. So the answer is “yes” but with a few caveats.

  • In practice this usually doesn’t happen, but the order of the records is not guaranteed. So it’s possible that you can make a minor change (e.g. remove a rule or an Item) and it results in what appears to git as a massive change because the records were saved in the wrong order. I’ve only seen this actually occur once.

  • JSONDB files are kind of monolithic, meaning that doing advanced stuff like merging changes between branches is challenging (but not impossible). But that isn’t an action that many individual programmers tend to need to do so that likely won’t be a hardship.

  • .items files tend to include a whole bunch of stuff that are actually stored and used by OH internally separately. For example, in a .items file you’ll include sitemap display information (label, icon), and metadata all in the one definition but in JSONDB these are all stored separately.