Timers and cancel 2 doorlocks

I have searched all forum for what I’m trying to do.
But I have a hard time grasping what is written here on the forum and converting it to my own rules.

Basically this is the idea.
I have 2 locks, when both locks are open more than 5 minutes I want to turn on my xiaomi gateway light to color red.
If one lock is locked within those 5 minutes I want to cancel the above timer.
However, if the timer has fired because the locks are open more than 5 minutes and I lock one lock.
I want to fire a timer that turns the color red to green and hold the green for 1 minute before turning off.
And sub sequentially, if one lock is locked and I lock the other lock, I want nothing to happen.

I have two ITEM switches AR5xReedSwitch_Timer1 and AR5xReedSwitch_Timer2.

This is my rule file

var Timer AR5xReedSwitch_Timer1 = null
var Timer AR5xReedSwitch_Timer2 = null

rule "door lock warn after 5 min open"
when
	Item AR50ReedSwitch received update or
	Item AR51ReedSwitch received update
then
	if (AR50ReedSwitch.state==OPEN && AR51ReedSwitch.state==OPEN) {
		logInfo("Demo","rule 1 started")
		if (AR5xReedSwitch_Timer2 !== null) {
			logInfo("Demo","rule 1 started and a timer 2 was found SETTING RED")
			AR5xReedSwitch_Timer2.cancel()
			AR5xReedSwitch_Timer1=createTimer(now.plusMinutes(1)) [|
			logInfo("Demo","timer 1 ran, and 2 was cancelled before")
			Xiaomi1GatewayBrightness.sendCommand(100)
			Xiaomi1GatewayColor.sendCommand(new HSBType(new DecimalType(1), new PercentType(100), new PercentType(100))) ]
			}
		else
			logInfo("Demo","timer 2 was null and setting RED")
			AR5xReedSwitch_Timer1=createTimer(now.plusMinutes(1)) [|
			logInfo("Demo","timer 1 ran")
			Xiaomi1GatewayBrightness.sendCommand(100)
			Xiaomi1GatewayColor.sendCommand(new HSBType(new DecimalType(1), new PercentType(100), new PercentType(100))) ]
		}
end

 rule "cancel timers if one or two locks are closed"
 when
	Item AR50ReedSwitch changed to CLOSED or
	Item AR51ReedSwitch changed to CLOSED
then

	if (AR5xReedSwitch_Timer1 === null) {
		if (AR5xReedSwitch_Timer2 !== null) {
			logInfo("Demo","there was no timer 1 but there is a timer 2")
		}
		else
			logInfo("Demo","there was no timer 1 but there is NO timer 2")
		}
	else if (AR5xReedSwitch_Timer1 !== null) {
		logInfo("Demo","timer 1 is active but cancels now. Setting GREEN")
		AR5xReedSwitch_Timer1.cancel()
		Xiaomi1GatewayColor.sendCommand(new HSBType(new DecimalType(100), new PercentType(100), new PercentType(1)))
		AR5xReedSwitch_Timer2=createTimer(now.plusMinutes(1)) [|
		logInfo("Demo","timer 2 is ran and timer 1 was cancelled")
		Xiaomi1GatewayBrightness.sendCommand(0) ]
		}
end

I get errors like these.
I do not understand why some timers seems to be running even if they are not running etc.

20:38:22.541 [ERROR] [untime.internal.engine.RuleEngineImpl] - Rule ‘door lock w
arn after 5 min open’: An error occurred during the script execution: Could not
invoke method: org.eclipse.smarthome.model.script.actions.Timer.cancel() on inst
ance: AR5xReedSwitch_Timer2 (Type=SwitchItem, State=NULL, Label=null, Category=n
ull)

@rlkoshak, sorry to disturb you, but in all the similar threads, you’ve been the solution to almost every answer :slight_smile:

It looks to me as if OH “thinks” AR5xReedSwitch_Timer2 is a SwitchItem! Can’t say why, but that should be the reason for the error.

Hmm, I have fiddled so much with this :frowning:
Could it be that I use a MAP file to my AR50ReedSwitches ?
They actually are sent a 0 or 1 and transformed with MAP to OPEN/CLOSED

Contact		AR50ReedSwitch			"AR50ReedSwitch [%s]"								<lock>			{ mqtt=">[broker1:xxx:state:CLOSED:0], >[broker1:xxxxx:state:OPEN:1], <[broker1:xxxx:state:MAP(lock.map)" }

Also, why does Openhab insist of informing to use !== (double =) instead of != ?

21:18:57.139 [WARN ] [del.core.internal.ModelRepositoryImpl] - Configuration mod
el 'Doorlocktimer.rules' is either empty or cannot be parsed correctly!
21:18:57.418 [INFO ] [del.core.internal.ModelRepositoryImpl] - Validation issues
 found in configuration model 'Doorlocktimer.rules', using it anyway:
The operator '==' should be replaced by '===' when null is one of the arguments.

The operator '!=' should be replaced by '!==' when null is one of the arguments.

21:18:57.425 [INFO ] [del.core.internal.ModelRepositoryImpl] - Loading model 'Do
orlocktimer.rules'
21:18:57.666 [INFO ] [del.core.internal.ModelRepositoryImpl] - Validation issues
 found in configuration model 'Doorlocktimer.rules', using it anyway:
The operator '==' should be replaced by '===' when null is one of the arguments.

The operator '!=' should be replaced by '!==' when null is one of the arguments.

21:18:57.677 [INFO ] [del.core.internal.ModelRepositoryImpl] - Refreshing model
'Doorlocktimer.rules'

You cannot assign a Timer to an Item. You can make an Item behave like a Timer using the Expire Binding but that isn’t what you are doing here. You have defined two global variables at the top of your Rules file but if you have also defined those two as Items then that is the source of your error.

If I were to implement this I would:

  1. put the two lock switches into a Group Group:Switch:AND(ON,OFF) Locks. Locks will then be ON if both locks are ON and OFF if any one of them is OFF

  2. Trigger your Rule using changes to Locks.

  3. Use Design Pattern: Expire Binding Based Timers

Switch Unlocked_Timer {expire="5m,command=OFF"}
Switch Locked_Timer {expire="1m,command=OFF"}
  1. The rule becomes:
rule "door locks state changed"
when
    Item Locks changed
then
    // Both locks are unlocked, set the unlocked timer
    if(Locks.state == ON)  Unlocked_Timer.sendCommand(ON)

    // One lock was locked
    else {
        // The timer has gone off, set the locked timer
        if(Unlocked_Timer.state == OFF) {
            // Turn xiaomi gateway light to green

            // Set Locked timer
            Locked_Timer.sendCommand(ON)
        }
        else {
            // cancell the unlocked timer
            Unlocked_Timer.postUpdate(OFF)
        }
    }
end

rule "doors have been unlocked too long"
when
    Item Unlocked_Timer received command OFF
then
    // set the Xiaomi gateway light to red
end

rule "door was locked"
when
    Item Locked_Timer received command OFF
then
    // turn off the Xiaomi gateway light
end
3 Likes

Sometimes you are set on certain ways and you need someone to open your eyes.
Such a simple and elegant solution!
Had to change some things because the locks are contacts not switches etc.
But it is working now and I have learnt something more :slight_smile:
Thanks!

(to anyone concerned and wants to see the full solution)

rule "door locks state changed"
when
	Item gLocks changed
then
	// Both locks are unlocked, set the unlocked timer
	if (gLocks.state == OPEN) {
		gLocksUnlocked_Timer.sendCommand(ON)
		}
	// One lock was locked
	else {
		// The timer has gone off, set the locked timer
		if(gLocksUnlocked_Timer.state == OFF) {
			Xiaomi1GatewayColor.sendCommand(new HSBType(new DecimalType(100), new PercentType(100), new PercentType(1)))
		// Set Locked timer
			gLocksLocked_Timer.sendCommand(ON)
		}
		else {
			// cancell the unlocked timer
			gLocksUnlocked_Timer.postUpdate(OFF)
		}
	}
end

rule "doors have been unlocked too long"
when
	Item gLocksUnlocked_Timer received command OFF
then
	Xiaomi1GatewayBrightness.sendCommand(100)
	Xiaomi1GatewayColor.sendCommand(new HSBType(new DecimalType(1), new PercentType(100), new PercentType(100)))
end

rule "door was locked"
when
	Item gLocksLocked_Timer received command OFF
then
	Xiaomi1GatewayBrightness.sendCommand(0)
end

And 2 items:

//Groups
Group:Contact:AND(OPEN, CLOSED) gLocks
//Timers
Switch gLocksUnlocked_Timer {expire="5m,command=OFF"}
Switch gLocksLocked_Timer {expire="1m,command=OFF"}

Thanks a lot for posting your full solution. I’m completely Noob to that and it helped me a lot understand the logic. But… I have tried to adapt if for my need, and the timer seems to never receive the OFF command.

My kids always forget some light opened in the basement when the go get something and come back, and I want to trigger something to notify on my googlehomes when the lights where on for too long.

My setup is a SonoffPOW+Tasmota installed on the main line for the basement lighting, from which I get the power consumption of the basement lights.

I have created the items:

Switch gLumieresCave_Timer {expire="1m,command=OFF"}
Number LumiereLavage_Power      "Lumieres Lavage (W)"               <line>       {channel="mqtt:topic:RELAI_LAVAGE_LUMIERES:powerLoad"}
Switch LumiereLavage_Status	    "Lumieres Lavage (Status)"			<switch>

And 3 rules:

rule "Power Lumieres Cave Modifie"
when
	Item LumiereLavage_Power changed
then
	// La lumière est allumee
	if (LumiereLavage_Power.state > 3) {
		LumiereLavage_Status.sendCommand(ON)
		}
	// La lumiere est eteinte
	else {
        LumiereLavage_Status.sendCommand(OFF)
		}
end



rule "Lumieres Cave Allumees"
when
	Item LumiereLavage_Status changed
then
	// Si la lumière est allumee, démarrer le timer
	if (LumiereLavage_Status.state == ON) {
		gLumieresCave_Timer.sendCommand(ON)
		}
	// La lumiere est eteinte, annuler le timer
	else {
        gLumieresCave_Timer.postUpdate(OFF)
		}
end

rule "Lumieres Allumees trop longtemps"
when
	Item gLumieresCave_Timer received command OFF
then
    say("Les lumieres de la cave sont ouvertes", "voicerss:frCA", "chromecast:chromecast:38da03a12fcaac011de23bc1869853da")
end

And, I have added the Expire Binding (which I had forgotten atthe begining).

In a nutshell, when the power consumption is changed for above 3W, lights are open and it changes the “_Status” item to ON, otherwise to OFF. I’m then watching for the state change of that item to trigger the timer.

I know the “Say” part is working because I am using it in another simpler rule, but I must be missing something because it’s not working. It seems that when the command OFF is received, the rule doesnt trigger. look at the log:

2020-10-23 22:24:35.791 [vent.ItemStateChangedEvent] - LumiereLavage_Power changed from 0 to 38

2020-10-23 22:24:35.800 [ome.event.ItemCommandEvent] - Item 'LumiereLavage_Status' received command ON

2020-10-23 22:24:35.808 [vent.ItemStateChangedEvent] - LumiereLavage_Status changed from OFF to ON

2020-10-23 22:24:35.824 [ome.event.ItemCommandEvent] - Item 'gLumieresCave_Timer' received command ON

2020-10-23 22:24:35.831 [vent.ItemStateChangedEvent] - gLumieresCave_Timer changed from OFF to ON

2020-10-23 22:24:45.758 [vent.ItemStateChangedEvent] - LumiereLavage_Power changed from 38 to 39

2020-10-23 22:24:45.774 [ome.event.ItemCommandEvent] - Item 'LumiereLavage_Status' received command ON

2020-10-23 22:24:55.804 [vent.ItemStateChangedEvent] - LumiereLavage_Power changed from 39 to 38

2020-10-23 22:24:55.826 [ome.event.ItemCommandEvent] - Item 'LumiereLavage_Status' received command ON

2020-10-23 22:25:35.751 [vent.ItemStateChangedEvent] - LumiereLavage_Power changed from 38 to 39

2020-10-23 22:25:35.769 [ome.event.ItemCommandEvent] - Item 'LumiereLavage_Status' received command ON

2020-10-23 22:25:35.964 [ome.event.ItemCommandEvent] - Item 'gLumieresCave_Timer' received command OFF

2020-10-23 22:25:35.970 [vent.ItemStateChangedEvent] - gLumieresCave_Timer changed from ON to OFF

2020-10-23 22:25:45.777 [vent.ItemStateChangedEvent] - LumiereLavage_Power changed from 39 to 38

2020-10-23 22:25:45.794 [ome.event.ItemCommandEvent] - Item 'LumiereLavage_Status' received command ON

2020-10-23 22:26:15.780 [vent.ItemStateChangedEvent] - LumiereLavage_Power changed from 38 to 39

2020-10-23 22:26:15.797 [ome.event.ItemCommandEvent] - Item 'LumiereLavage_Status' received command ON

2020-10-23 22:26:25.783 [vent.ItemStateChangedEvent] - LumiereLavage_Power changed from 39 to 38

2020-10-23 22:26:25.802 [ome.event.ItemCommandEvent] - Item 'LumiereLavage_Status' received command ON

Any idea on something I have done wrong?

Thanks for your help

Change

gLumieresCave_Timer.postUpdate(OFF)

To

gLumieresCave_Timer.sendCommand(OFF)

Thans, I’ll try that. But I’m curious… isn’t that part triggered when the lights are closed, and wouldn’t that trigger the brodcast of the message?

same result… the timer gets the OFF command, but nothing happens

2020-10-24 19:29:25.263 [vent.ItemStateChangedEvent] - LumiereLavage_Power changed from 0 to 37

2020-10-24 19:29:26.271 [ome.event.ItemCommandEvent] - Item 'LumiereLavage_Status' received command ON

2020-10-24 19:29:26.288 [vent.ItemStateChangedEvent] - LumiereLavage_Status changed from NULL to ON

2020-10-24 19:29:26.298 [ome.event.ItemCommandEvent] - Item 'gLumieresCave_Timer' received command ON

2020-10-24 19:29:26.308 [vent.ItemStateChangedEvent] - gLumieresCave_Timer changed from NULL to ON

2020-10-24 19:29:45.319 [vent.ItemStateChangedEvent] - LumiereLavage_Power changed from 37 to 38

2020-10-24 19:29:45.331 [ome.event.ItemCommandEvent] - Item 'LumiereLavage_Status' received command ON

2020-10-24 19:29:55.470 [vent.ItemStateChangedEvent] - LumiereLavage_Power changed from 38 to 24

2020-10-24 19:29:55.482 [ome.event.ItemCommandEvent] - Item 'LumiereLavage_Status' received command ON

2020-10-24 19:30:26.409 [ome.event.ItemCommandEvent] - Item 'gLumieresCave_Timer' received command OFF

2020-10-24 19:30:26.420 [vent.ItemStateChangedEvent] - gLumieresCave_Timer changed from ON to OFF

I managed to make it work by adding a constraint in the if to prevent reupdate when the power varied and Status was already on:

rule "Power Lumieres Cave Modifie"
when
	Item LumiereLavage_Power changed
then
	// La lumière est allumee
	if ((LumiereLavage_Power.state > 3) && (LumiereLavage_Status.state == OFF)){
		LumiereLavage_Status.sendCommand(ON)
		}
	// La lumiere est eteinte
	else if (LumiereLavage_Power.state < 3){
        LumiereLavage_Status.sendCommand(OFF)
		}
end



rule "Lumieres Cave Allumees"
when
	Item LumiereLavage_Status changed
then
	// Si la lumière est allumee, démarrer le timer
	if (LumiereLavage_Status.state == ON) {
		gLumieresCave_Timer.sendCommand(ON)
		}
	// La lumiere est eteinte, annuler le timer
	else {
        gLumieresCave_Timer.postUpdate(OFF)
		}
end

rule "Lumieres Allumees trop longtemps"
when
	Item gLumieresCave_Timer received command OFF
then
    say("Les lumieres de la cave sont ouvertes", "voicerss:frCA", "chromecast:chromecast:38da03a12fcaac011de23bc1869853da")
end