Presence Simulation

Hi,
Assuming you are using influxdb as persistence, that’s the only thing you would need to adjust, indeed.

Good luck,
Dries

1 Like

Just a small question: does this work in OH3 as well? And where exactly do I enter this code?
If I do it via Rules --> Code, the code always “disappears” .
If i do it via Scripts --> the EXMAScript and the Rule DSL doesn’t do anything… :roll_eyes:

It should work in OH 3.

You need to save them to a .rules file in the conf/rules folder. The code above will not work in Ui created rule without changes.

Came here as the previous method I used (google calendar scheduler) is no longer supported in OH3.

Tried the great method in this thread but had a little difficulty at first but quickly found the answer here

In short, change this (from above code):
createTimer(now.plusMillis(i*presence_delay))

To this:
createTimer(now.toInstant().plusMillis(i*presence_delay).atZone(now.zone))

For completeness and for anyone else who is interested in this method here is what I have now which I can confirm works with OH3.

Make sure influxDB is setup, ether manually or via openhabian

Add following:

.items

Switch Swi_PreSim  // used in sitemap to turn simulation on/off

Group  gSim        // add this group to items you wish to be included

example light to be included:

Dimmer Dim_Lounge_Rear "Lounge Rear" <light> (gSim) { channel="xyz" }

.persist

Items {
gSim* : strategy = everyChange
}

.rules

// **************************
// Global variables
// ***************************
var int presence_days = 1
var int presence_delay = 1000
var String persistence = "influxdb"
// ***************************
// Presence Simulation
// ***************************
rule "Presence Simulation"

when

    //Time cron "0 0/1 * 1/1 * ? *" //every 60 sec
    Time cron "0/30 0/1 * 1/1 * ? *" //every 30 sec

then

    if (Swi_PreSim.state == ON) {
        gSim.members.forEach(light,i |
            if(light.historicState(now.minusDays(presence_days), persistence).state != light.state) {
                //createTimer(now.plusMillis(i*presence_delay)) [|  OH2
                createTimer(now.toInstant().plusMillis(i*presence_delay).atZone(now.zone)) [| //OH3
                    logInfo("Pres_Sim",light.name + " state " + light.historicState(now.minusDays(presence_days), persistence).state)
                    light.sendCommand(light.historicState(now.minusDays(presence_days), persistence).state.toString)
                ]
            }
        )
    }
end

Pleased I found this as it is so much simpler than the Google method, no messing about with their API and all done locally, wish I discovered this a while ago!

2 Likes

What would this rule look like if it was ported to javascript on OH3?

Let me share with you how far I got so far.
For timers some investigation is needed:

triggers:
  - id: "1"
    configuration:
      cronExpression: 0 * * * * ? *
    type: timer.GenericCronTrigger
conditions: []
actions:
  - inputs: {}
    id: "2"
    configuration:
      type: application/javascript
      script: >-
        var logger =
        Java.type("org.slf4j.LoggerFactory").getLogger("org.openhab.model.script.Rules.Experiments");

        var PersistenceExtensions = Java.type("org.openhab.core.persistence.extensions.PersistenceExtensions");

        var ZonedDateTime = Java.type("java.time.ZonedDateTime");


        logger.info("Running presence simulation");

        var presence = ir.getItem("PresenceSimulation").state

        var presenceOffset = 7


        if (presence == ON) {
          var group = ir.getItem("gPresenceSimulation");
          group.allMembers.forEach(function (item) {

            logger.info("processing gPresenceSimulation member {}", item.name);

            var historicState = PersistenceExtensions.historicState(item, ZonedDateTime.now().minusDays(presenceOffset),"rrd4j").state;
            if (historicState != item.state) {

              logger.info("Pres_Sim {} set to {}", item.name, historicState);
              events.sendCommand(item.name, historicState)
            }
          })
        };
    type: script.ScriptAction
1 Like

Move the check to see if PresenceSimulation is ON in a Script Condition instead of the Script Action. That will make the Action a lot simpler.

Beyond that everything looks as I would expect. Is there anything not working?

What do you need the timers for here? Or are you just needing to look into Timers in general?

Thank you for the feedback on script condition.

I included timers to avoid overflow of the binding interface with simultaneous "sendCommand"s
I had to do so on my old installation, but I am not sure whether I still need with OH3 on raspi4 and newer v2 bindings.

triggers:
  - id: "1"
    configuration:
      cronExpression: 0 * * * * ? *
    type: timer.GenericCronTrigger
conditions:
  - inputs: {}
    id: "3"
    configuration:
      itemName: PresenceSimulation
      state: ON
      operator: =
    type: core.ItemStateCondition
actions:
  - inputs: {}
    id: "2"
    configuration:
      type: application/javascript
      script: >-
        var logger =
        Java.type("org.slf4j.LoggerFactory").getLogger('org.openhab.rule.' +
        ctx.ruleUID);// "org.openhab.model.script.PresenceSimulation");

        var PersistenceExtensions = Java.type("org.openhab.core.persistence.extensions.PersistenceExtensions");

        var ZonedDateTime = Java.type("java.time.ZonedDateTime");

        var ScriptExecution = Java.type("org.openhab.core.model.script.actions.ScriptExecution");


        var presenceOffset = 7

        var presenceDelay = 100000000


        var group = ir.getItem("gPresenceSimulation");

        group.allMembers.forEach(function (item, index) {

          logger.info("processing gPresenceSimulation member {}", item.name);

          var historicState = PersistenceExtensions.historicState(item, ZonedDateTime.now().minusDays(presenceOffset),"rrd4j").state;
          if (historicState != item.state) {

            logger.debug("Pres_Sim {} set to {}", item.name, historicState);
            ScriptExecution.createTimer(ZonedDateTime.now().plusNanos(index*presenceDelay), function(){
              events.sendCommand(item.name, historicState)
            })                             
          }
        });
    type: script.ScriptAction

OK, if that’s the case it looks like your latest code looks reasonable. Another approach that could work, assuming that you don’t have too many Items that makes the rule run longer than an minute, is to use java.lang.Thread.sleep() to pause inline instead of scheduling a timer. The problems with long running rules is way less pronounced in OH 3. You can still cause problems if your one rule takes too long but the problems will be limited to that one rule and no longer starve out all your rules. So the recommendations against using Thread.sleep in rules is relaxed somewhat.

Have you tried to use this only for a certain time of the day? How would this rule look like then? Because the only-if function of the “new” rule engine doesn’t seem to work…: [Rules] Issues regarding only-if and Dimmer-value (new OH3 Rule-Engine) · Issue #2124 · openhab/openhab-core · GitHub

That issue is specific to Dimmers. It does not mean that conditions in general do not work. I’ve successfully used them in many of my rules.

But if that doesn’t work for you, add an if condition to exit in your Script Action if it’s not the right time.

1 Like

Okay great Thanks =)

what is “presence delay” for?

1 Like

presenceDelay is actually misnamed. Meant is the delay between commands to avoid flooding interface with too many simultaneous sendCommands.

2 Likes

Ohhhh okay that’s nice! Thanks for the explanation :slight_smile:

maybe could be renamed to smth lik ‘replayTimeShift’ or smth like that