Delay Alarm

Hi guys,
I implemented a version of the alarm example (n.2) explained in the wiki page. Instead of one Timer, in the rule, I’m creating 4 timers, the first timer (timer0) uses the alarm time set by sitemap and the other 3 timers are created adding offset values (editable by sitemap) to the alarm time. Everything is working fine but sometimes the first timers is triggered with a delay until 15 minutes, but the others are triggered in time.

The second and the fourth timers (timer2, timer4) have been always triggered so far, but he third one (timer1) sometimes is not triggered.

Here’s my rule:

/************** Alarm ***********/

import org.openhab.core.library.types.*
import org.openhab.core.persistence.*
import org.openhab.model.script.actions.*
import org.openhab.action.squeezebox.*

import java.util.concurrent.locks.ReentrantLock

var Timer timer0
var Timer timer1
var Timer timer2
var Timer timer3

var java.util.concurrent.locks.ReentrantLock lock1 = new java.util.concurrent.locks.ReentrantLock()

rule "Alarm"
when
    Item alarmTimeHour changed or
    Item alarmTimeMinutes changed or
    Item alarmOffset1Minutes changed or
    Item alarmOffset2Minutes changed or
    Item alarmOffset3Minutes changed or
then
	if(alarmEnabled.state != Uninitialized && alarmTimeHour.state != Uninitialized && alarmTimeMinutes.state != Uninitialized && alarmOffset1Minutes.state != Uninitialized && alarmOffset2Minutes.state != Uninitialized && alarmOffset3Minutes.state != Uninitialized && alarmTuesday.state != Uninitialized && alarmWensday.state != Uninitialized && alarmThursday.state != Uninitialized && alarmFriday.state != Uninitialized && alarmSaturday.state != Uninitialized && alarmSunday.state != Uninitialized)
	{
	  // If the UI to change the Alarm time is clicked several times the code below
	  // is subject to race conditions. Therefore we make sure that all events 
	  // are processed one after the other.
	  lock1.lock()
	  try {
		var String msg = ""
		
		logInfo("rules","Alarm has been changed.")

		// Copy the Alarm-Time from the UI to local variables
		var hour = alarmTimeHour.state as DecimalType
		var minute = alarmTimeMinutes.state as DecimalType

		// Combine the hour and minutes to one string to be displayed in the 
		// user interface
		if (hour < 10) { msg = "0" } 
		msg = msg + alarmTimeHour.state.format("%d") + ":"

		if (minute < 10) { msg = msg + "0" }
		msg = msg + alarmTimeMinutes.state.format("%d")
		postUpdate(alarmTimeMessage,msg)
		logInfo("rules","New alarm time: "+msg)

		// calculate the alarm time [min]
		var int alarm1
		alarm1 = (alarmTimeHour.state as DecimalType).intValue * 60 + 
					(alarmTimeMinutes.state as DecimalType).intValue
		alarm1 = alarm1.intValue

		// calculate current time [min]
		var int hour1
		hour1 = now.getMinuteOfDay
		hour1 = hour1.intValue

		// calculate the difference between the requested alarm time and 
		// current time (again in minutes)  
		var int delta1
		delta1 = (alarm1 - hour1)
		delta1 = delta1.intValue

		// add one day (1440 minutes) if alarm time for today already passed
		if (hour1 > alarm1) { delta1 = delta1 + 1440 }
		
		// set the others timer based on the offsets
		var int delta2
		delta2 = delta1 + (alarmOffset1Minutes.state as DecimalType).intValue
		
		var int delta3
		delta3 = delta1 + (alarmOffset2Minutes.state as DecimalType).intValue
		
		var int delta4
		delta4 = delta1 + (alarmOffset3Minutes.state as DecimalType).intValue

		// check if there is already an alarm timer0; cancel it if present
		if (timer0 != null) {
		   timer0.cancel
		   timer0 = null
		}

		// create a new timer using the calculated delta [min]
		timer0 = createTimer(now.plusMinutes(delta1)) [|
			// This code will be executed if the timer triggers
			// ************************************************
			// check if alarm clock is enabled and armed for this weekday
			if(alarmEnabled.state == ON)
			{
				var Number day = now.getDayOfWeek
				if (((day == 1) && (alarmMonday.state == ON))	||
					((day == 2) && (alarmTuesday.state == ON))	||
					((day == 3) && (alarmWensday.state == ON))	||
					((day == 4) && (alarmThursday.state == ON))	||
					((day == 5) && (alarmFriday.state == ON))	||
					((day == 6) && (alarmSaturday.state == ON))	||
					((day == 7) && (alarmSunday.state == ON))) {
						// The things to do if the alarm clock is enabled for this day of week: 
						callScript("alarm1")
				}//if
			}//if enabled
			
			// Re-Arm the timer to trigger again tomorrow (same time) 
			timer0.reschedule(now.plusHours(24))
			]
		logInfo("rules","Alarm, timer0 set.")
		// check if there is already an alarm timer1; cancel it if present
		if (timer1 != null) {
		   timer1.cancel
		   timer1 = null
		}
		
		// create a new timer using the calculated delta [min]
		timer1 = createTimer(now.plusMinutes(delta2)) [|
			// This code will be executed if the timer triggers
			// ************************************************
			// check if alarm clock is enabled and armed for this weekday
			if(alarmEnabled.state == ON)
			{
				var Number day = now.getDayOfWeek
				if (((day == 1) && (alarmMonday.state == ON))	||
					((day == 2) && (alarmTuesday.state == ON))	||
					((day == 3) && (alarmWensday.state == ON))	||
					((day == 4) && (alarmThursday.state == ON))	||
					((day == 5) && (alarmFriday.state == ON))	||
					((day == 6) && (alarmSaturday.state == ON))	||
					((day == 7) && (alarmSunday.state == ON))) {
						// The things to do if the alarm clock is enabled for this day of week: 
						callScript("alarm2")
				   }
			}
			// Re-Arm the timer to trigger again tomorrow (same time) 
			timer1.reschedule(now.plusHours(24))
			]
		logInfo("rules","Alarm, timer1 set.")
		// check if there is already an alarm timer2; cancel it if present
		if (timer2 != null) {
		   timer2.cancel
		   timer2 = null
		}
		
		// create a new timer using the calculated delta [min]
		timer2 = createTimer(now.plusMinutes(delta3)) [|
			// This code will be executed if the timer triggers
			// ************************************************
			// check if alarm clock is enabled and armed for this weekday
			if(alarmEnabled.state == ON)
			{
				var Number day = now.getDayOfWeek
				if (((day == 1) && (alarmMonday.state == ON))	||
					((day == 2) && (alarmTuesday.state == ON))	||
					((day == 3) && (alarmWensday.state == ON))	||
					((day == 4) && (alarmThursday.state == ON))	||
					((day == 5) && (alarmFriday.state == ON))	||
					((day == 6) && (alarmSaturday.state == ON))	||
					((day == 7) && (alarmSunday.state == ON))) {
						// The things to do if the alarm clock is enabled for this day of week: 
						callScript("alarm3")
				   }
			}
			// Re-Arm the timer to trigger again tomorrow (same time) 
			timer2.reschedule(now.plusHours(24))
			]
		logInfo("rules","Alarm, timer2 set.")
		// check if there is already an alarm timer3; cancel it if present
		if (timer3 != null) {
		   timer3.cancel
		   timer3 = null
		}
		
		// create a new timer using the calculated delta [min]
		timer3 = createTimer(now.plusMinutes(delta4)) [|
			// This code will be executed if the timer triggers
			// ************************************************
			// check if alarm clock is enabled and armed for this weekday
			if(alarmEnabled.state == ON)
			{
				var Number day = now.getDayOfWeek
				if (((day == 1) && (alarmMonday.state == ON))	||
					((day == 2) && (alarmTuesday.state == ON))	||
					((day == 3) && (alarmWensday.state == ON))	||
					((day == 4) && (alarmThursday.state == ON))	||
					((day == 5) && (alarmFriday.state == ON))	||
					((day == 6) && (alarmSaturday.state == ON))	||
					((day == 7) && (alarmSunday.state == ON))) {
					// The things to do if the alarm clock is enabled for this day of week: 
					callScript("alarm4")
			   }
			}
			// Re-Arm the timer to trigger again tomorrow (same time) 
			timer3.reschedule(now.plusHours(24))
			]
		logInfo("rules","Alarm, timer3 set.")
	  } finally  {
		 // release the lock - we are ready to process the next event
		 lock1.unlock()
		 }
	 end
  }//IF
end

Do you have any suggestion to solve the issues?

Thank you.

P.S. I’m running openhab 1.8.1 on ubuntu.

I don’t have any specific recommendations for your specific problem, but I do have some debuggin recommendations.

Add logging statements to your code and log out the result of all of your calculations and make sure they are correct.

Make sure that the rule is not executing multiple instances at the same time.For example, if you change alarmTimerHour and then change alarmTimeMinutes before the rule finishes processing alarmTimeHour you will have two instances of the rule running at the same time and they could be overwriting each other. You logs will show this.

Hi Rich,
ok, I’ll add more debugging logs. Regarding the multiple instances, should the lock logic prevent that kind of issue?

Thank you.

Yes, I missed it when I first scanned through the code.

Hi Tommaso,

Can you share your final code rule, sitemap and item?

Thank you.

Hi @Faris_RAG,
are you interested in the issue or you’d like to see the entire code as example?

Hi Tommaso,

I do like to see the entire code for example.
It is because my project use timer to trigger the sensor.

I updated the example page with a new one.

I am experimenting with the initial alarm example as stock code, no errors just the sub frame is not visible, i guess i am missing something

i’ve added a switch to " set the master alarm " so it has a state therefore can be evaluated and the menus can now appear, would this system need a presence to maintain the initial states , alarm setting and value ?

See Generic Presence Detection for an example using Design Pattern: Expire Binding Based Timers. Additional examples can be found in Design Pattern: Motion Sensor Timer.