I’m trying to set up some simple alarm system rules. Unfortunatley I’m struggeling with - I think - the case part …
// ITEMS Alarmanlage
Group GreedALARM // Group for trigger purposes
Number alarmmodus // Alarm system mode: off/on/auto
Switch alarmstill // Silent Alarm
Switch alarmswitch // Switch to switch system off manually before siren starts
rule "Alarmanlage"
when
Member of GreedALARM changed to OPEN
then
switch (alarmmodus.state as DecimalType) {
case 0 : {
logInfo("RULE", "--> Alarmanlage [AUS]: Reed ausgelöst, aber Modus:AUS - "+ triggeringItem.name)
}
case 1 : {
logInfo("RULE", "--> Alarmanlage [AN]: Reed ausgelöst - "+ triggeringItem.name)
alarmswitch.sendCommand(ON)
sendCommand(out_xiao_gateway_soundvolume, 2)
sendCommand(out_xiao_gateway_sound, 11)
Thread::sleep(2000) /* wait for 2 seconds */
sendCommand(out_xiao_gateway_sound, 10000)
sendCommand(out_xiao_gateway_soundvolume, 0)
Thread::sleep(3000) /* wait for 3 seconds */
if(alarmswitch.state==ON) {
if(alarmstill.state=ON) {
logInfo("RULE", "--> Alarmanlage [AN]: stiller Alarm")
// sendPushoverMessage(pushoverBuilder("ALARMANLAGE [AN]: Reed-Kontakt ausgelöst - stiller Alarm").withPriority(1).withSound("spacealarm"))
postUpdate(EventLog, "Alarmanlage [AN]: stiller Alarm") // eventlog.rules
Thread::sleep(3000) /* wait for 3 seconds */
alarmswitch.sendCommand(OFF)
}
if(alarmstill.state=OFF) {
logInfo("RULE", "--> Alarmanlage [AN]: stiller Alarm")
// sendPushoverMessage(pushoverBuilder("ALARMANLAGE: Reed-Kontakt ausgelöst - lauter ALARM !!!").withPriority(1).withSound("spacealarm"))
postUpdate(EventLog, "Alarmanlage [AN]: lauter Alarm") // eventlog.rules
//
Thread::sleep(3000) /* wait for 3 seconds */
alarmswitch.sendCommand(OFF)
}
}
}
case 2 : {
logInfo("RULE", "--> Alarmanlage [AUTO]: Reed ausgelöst - "+ triggeringItem.name)
// code for auto-mode tbd
}
}
end
sitemap test label="Test" {
Frame label="Alarmanlage" {
Group item=GreedALARM
Switch item=alarmmodus mappings=[2="Auto", 1="An", 0="Aus"]
Switch item=alarmstill
Switch item=alarmswitch
}
}
For case 0 it works as expected.
For case1 it seems to stop after Thread::sleep(3000) /* wait for 3 seconds */
My question is: Is it possible to have a if-condition within the “case”-condition as it is in the code above?
I note that if your condition alarmswitch.state==ON is not satisfied, nothing else will happen. Not sure how you tell it’s “stopped” from it doing nothing before exiting.
Warning: a few lines earlier, you send the command ON to alarmswitch. That won’t change the state of alarmswitch immediately - although here you’re not testing it until some seconds later, so it should have caught up by then.
logInfo() is useful tool to follow what’s going on. Try some adding more
case 1 : {
logInfo("RULE", "--> Alarmanlage [AN]: Reed ausgelöst - "+ triggeringItem.name)
alarmswitch.sendCommand(ON)
...
logInfo("test". "switch state is " + alarmswitch.state.toString)
if(alarmswitch.state==ON) {
logInfo("test". "still state is " + alarmstill.state.toString)
if(alarmstill.state=ON) {
... etc
Another thing… It’s a bad idea to use Thread::sleep() for long sleep statements, as it would block a rule thread. I would consider to do it with a timer as a very simple state machine:
var Timer tAblauf = null // timer of state machine
var Number nSchritt // counter of state machine
rule "Alarmanlage"
when
Member of GreedALARM changed to OPEN
then
if(!(alarmmodus.state instanceof Number)) { // check null state
logInfo("Alarm","Alarmmodus not set!")
return;
}
val Number nAl = alarmmodus.state as Number
val String sModus = switch(nAl){case 0:"AUS" case 1:"AN" case 2:"AUTO"}
val String sMyLog = "Alarmanlage [" + sModus + "]: Reed ausgelöst" + if(nAl==0) ", aber Modus:AUS - " else " - "
logInfo("Alarm", sMyLog + triggeringItem.name)
switch (nAl) {
case 0 : {
// empty :)
}
case 1 : {
nSchritt = 1 // set counter of state machine
if(tAblauf !== null) tAblauf.cancel
tAblauf = createTimer(now, [ | // start state machine
switch (nSchritt) {
case 1 : { // 1st step
alarmswitch.sendCommand(ON)
out_xiao_gateway_soundvolume.sendCommand(2)
out_xiao_gateway_sound.sendCommand(11)
tAblauf.reschedule(now.plusSeconds(2)) // set timer for next step
}
case 2 : { // 2nd step
out_xiao_gateway_sound.sendCommand(10000)
out_xiao_gateway_soundvolume.sendCommand(0)
tAblauf.reschedule(now.plusSeconds(3)) // set timer for next step
}
case 3: { // 3rd step
if(alarmswitch.state != OFF) { // alarm stopped?
val String sAlarm = if(alarmstill.state == ON) "stiller" else "lauter"
logInfo("Alarm", "--> Alarmanlage [AN]: " + sAlarm + " Alarm")
// sendPushoverMessage(pushoverBuilder("ALARMANLAGE [AN]: Reed-Kontakt ausgelöst - " + sAlarm + " Alarm").withPriority(1).withSound("spacealarm"))
EventLog.postUpdate("Alarmanlage [AN]: " + sAlarm + " Alarm")
}
tAblauf.reschedule(now.plusSeconds(3)) // set timer for next step
}
case 4: { // last step
alarmswitch.sendCommand(OFF)
tAblauf = null
}
}
nSchritt += 1 // count up
])
}
case 2 : {
// code for auto-mode tbd
}
}
end
rule "Alarmanlage 2"
when
Item alarmswitch changed to OFF // alarm stopped
then
if(tAblauf !== null && nSchritt > 2) { // only stop state machine after the 2nd step!
tAblauf.cancel
tAblauf = null
}
end
Well, I wrote comments inline (you will have to scroll to the right - or just copy the whole code to an editor to read it)
The code should do exactly the same thing as yours (almost - one of the logInfos might be slightly different…)
I’m not sure what your intentions were, but do be aware that createTimer() does what it says on the tin - creates the timer (to be executed later) and immediately moves on.
In this case, there’s some sound action, then the alarmswitch OFF will fire after 10 seconds, and then more sound will fire after another 10 seconds.
The timers do their thing on time, not creation order.
Please be aware that you can simply create a timer without assigning it to a var, but you will never be able to get any information or control to this timer.
Your task is a really simple state machine (as said in my first posting) - imagine an old washing machine, which has a programming wheel in it, a dumb “do this - wait x seconds - do that - wait y seconds - start motor - wait z seconds - do another thing, wait…” - This is how the rule works, and it takes care of breaking points to stop the job.
Be aware that my rule does only use one timer, where you want to use 5 timers, which is bad design. Try to be efficient with the code.