Thanks. With this approach I was able to identify the problem. It seems that one of my KNX switches didn’t return a proper status update. Very strange, since these KNX switches have been set up at least 5 years ago and I never noticed the problem. It seems my presence simulation is working now.
Another question: the cron job is scheduled every 5 minutes (in the example code). Would you consider that as the recommended setting? I’m thinking of setting this to every minute. With the job set every five minutes, it might become obvious that lights are always turned on/off at 18h00, 18h05, 18h10… Or would it put too much of a burden on the OH system (I have approx. 20 switches in my presence simulation group)?
A minute is an eternity for a computer. I wouldn’t worry about any performance problems.
You could add a bit of noise to when they start by adding a random number to the timer so nothing starts exactly on any minute and the lights don’t go on all at the same time.
Job runs every minute instead of every five minutes;
I have changed the delay from “50” to “1000”. I realize the initial purpose of “delay” was to avoid flooding OH with many commands at the same time. But with a delay of 1000 also the lights are turned on slightly more spread in time. If you have 20 lights, the last light will be switched 20 seconds after the rule has started. I know it’s not random, but someone trying to break in needs to be pretty smart to see a pattern.
// ***************************
// 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 * ? *"
then
if (Virtual_PresenceSimulation.state == ON) {
gPresenceSimulation.members.forEach(light,i |
if(light.historicState(now.minusDays(presence_days), persistence).state != light.state) {
createTimer(now.plusMillis(i*presence_delay)) [|
logInfo("Pres_Sim",light.name + " schakelt " + light.historicState(now.minusDays(presence_days), persistence).state)
light.sendCommand(light.historicState(now.minusDays(presence_days), persistence).state.toString)
]
}
)
}
end
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…
// **************************
// 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!
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.