Timers firing behaviour

Hi all, I have the following rule for my irrigation system:

    rule "Irrigation run"
    when
        Time cron "0 0 0 * * ?" or
		Item IrrigationTimeHour changed	or
		Item IrrigationTimeMinutes changed	
    then
					
		lock1.lock()			
			
		try {			
				var String msg = ""
				logInfo("rules","Watering start hour has been changed.")

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

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

				if ((minute as Number) < 10) { msg = msg + "0" }
				msg = msg + IrrigationTimeMinutes.state.format("%d")
				postUpdate(Irrigation_StartTime, msg)
				logInfo("rules","New watering time: "+msg)
				
				// get the scale factor - used to reduce the run times across the board
				var Number scaleFactor = Irrigation_ScaleFactor.state as DecimalType
		
				// convert our start time to a joda.time.DateTime for today
				var DateTime startTime = parse(now.getYear() + "-" + now.getMonthOfYear() + "-" + now.getDayOfMonth() + "T" + Irrigation_StartTime.state + ":00")
				var DateTime endTime
			
				// get the raw run times for each zone (in mins)
				var Number Z1Mins = Irrigation_Z1Mins.state as DecimalType
				var Number Z2Mins = Irrigation_Z2Mins.state as DecimalType
				var Number Z3Mins = Irrigation_Z3Mins.state as DecimalType
				var Number Z4Mins = Irrigation_Z4Mins.state as DecimalType
				var Number Z5Mins = Irrigation_Z5Mins.state as DecimalType
				var Number Z6Mins = Irrigation_Z6Mins.state as DecimalType
				
				// convert to the actual run times (by applying the scale factor)
				var int Z1Time = ((Z1Mins * scaleFactor) / 100).intValue
				var int Z2Time = ((Z2Mins * scaleFactor) / 100).intValue
				var int Z3Time = ((Z3Mins * scaleFactor) / 100).intValue
				var int Z4Time = ((Z4Mins * scaleFactor) / 100).intValue
				var int Z5Time = ((Z5Mins * scaleFactor) / 100).intValue
				var int Z6Time = ((Z6Mins * scaleFactor) / 100).intValue
				
				logInfo("rules","New watering time scheduled")				
				
				// turn on each zone in turn (with a minute gap between each zone activation)
				if (Z1Time > 0) {
					if(Timer1start!=null) 
					{
						Timer1start.cancel()	
						Timer1start = null
					}
					if(Timer1end!=null)
					{
						Timer1end.cancel()
						Timer1end = null	
					}					
					endTime = startTime.plusMinutes(Z1Time)
					Timer1start = createTimer(startTime) [|
					day = now.getDayOfWeek()
					if ((Irrigation_Master.state == ON) &&
						(((day == 1) && (IrrigationMonday.state == ON))	||
						((day == 2) && (IrrigationTuesday.state == ON))	||
						((day == 3) && (IrrigationWensday.state == ON))	||
						((day == 4) && (IrrigationThursday.state == ON))	||
						((day == 5) && (IrrigationFriday.state == ON))	||
						((day == 6) && (IrrigationSaturday.state == ON))	||
						((day == 7) && (IrrigationSunday.state == ON)))) {					
							sendCommand(Irrigazione_Z1, ON)
							//callScript("startWatering")
						}
					]
					Timer1end = createTimer(endTime) [| sendCommand(Irrigazione_Z1, OFF) ]
					startTime = endTime.plusMinutes(1)
				}
				
				if (Z2Time > 0) {
					if(Timer2start!=null) 
					{
						Timer2start.cancel()	
						Timer2start = null
					}
					if(Timer2end!=null)
					{
						Timer2end.cancel()
						Timer2end = null	
					}
					endTime = startTime.plusMinutes(Z2Time)
					Timer2start = createTimer(startTime) [| 
						day = now.getDayOfWeek()
						if ((Irrigation_Master.state == ON) &&
						(((day == 1) && (IrrigationMonday.state == ON))	||
						((day == 2) && (IrrigationTuesday.state == ON))	||
						((day == 3) && (IrrigationWensday.state == ON))	||
						((day == 4) && (IrrigationThursday.state == ON))	||
						((day == 5) && (IrrigationFriday.state == ON))	||
						((day == 6) && (IrrigationSaturday.state == ON))	||
						((day == 7) && (IrrigationSunday.state == ON)))) {					
							sendCommand(Irrigazione_Z2, ON)
						}	
					]
					
					Timer2end = createTimer(endTime) [| sendCommand(Irrigazione_Z2, OFF) ]
					startTime = endTime.plusMinutes(1)
				}
				
				if (Z3Time > 0) {
					if(Timer3start!=null) 
					{
						Timer3start.cancel()	
						Timer3start = null
					}
					if(Timer3end!=null)
					{
						Timer3end.cancel()
						Timer3end = null	
					}					
					endTime = startTime.plusMinutes(Z3Time)
					Timer3start = createTimer(startTime) [| 
						day = now.getDayOfWeek()
						if ((Irrigation_Master.state == ON) &&
						(((day == 1) && (IrrigationMonday.state == ON))	||
						((day == 2) && (IrrigationTuesday.state == ON))	||
						((day == 3) && (IrrigationWensday.state == ON))	||
						((day == 4) && (IrrigationThursday.state == ON))	||
						((day == 5) && (IrrigationFriday.state == ON))	||
						((day == 6) && (IrrigationSaturday.state == ON))	||
						((day == 7) && (IrrigationSunday.state == ON)))) {					
							sendCommand(Irrigazione_Z3, ON)
						}
					]
					
					Timer3end = createTimer(endTime) [| sendCommand(Irrigazione_Z3, OFF) ]
					startTime = endTime.plusMinutes(1)
				}
				
				if (Z4Time > 0) {
					if(Timer4start!=null) 
					{
						Timer4start.cancel()	
						Timer4start = null
					}
					if(Timer4end!=null)
					{
						Timer4end.cancel()
						Timer4end = null	
					}
					
					endTime = startTime.plusMinutes(Z4Time)
					Timer4start = createTimer(startTime) [| 
						day = now.getDayOfWeek()
						if ((Irrigation_Master.state == ON) &&
						(((day == 1) && (IrrigationMonday.state == ON))	||
						((day == 2) && (IrrigationTuesday.state == ON))	||
						((day == 3) && (IrrigationWensday.state == ON))	||
						((day == 4) && (IrrigationThursday.state == ON))	||
						((day == 5) && (IrrigationFriday.state == ON))	||
						((day == 6) && (IrrigationSaturday.state == ON))	||
						((day == 7) && (IrrigationSunday.state == ON)))) {					
							sendCommand(Irrigazione_Z4, ON)
						}
					]
					Timer4end = createTimer(endTime) [| sendCommand(Irrigazione_Z4, OFF) ]
					startTime = endTime.plusMinutes(1)
				}
				if (Z5Time > 0) {
					if(Timer5start!=null) 
					{
						Timer5start.cancel()	
						Timer5start = null
					}
					if(Timer5end!=null)
					{
						Timer5end.cancel()
						Timer5end = null	
					}
										
					endTime = startTime.plusMinutes(Z5Time)
					Timer5start = createTimer(startTime) [| 
						day = now.getDayOfWeek()
						if ((Irrigation_Master.state == ON) &&
						(((day == 1) && (IrrigationMonday.state == ON))	||
						((day == 2) && (IrrigationTuesday.state == ON))	||
						((day == 3) && (IrrigationWensday.state == ON))	||
						((day == 4) && (IrrigationThursday.state == ON))	||
						((day == 5) && (IrrigationFriday.state == ON))	||
						((day == 6) && (IrrigationSaturday.state == ON))	||
						((day == 7) && (IrrigationSunday.state == ON)))) {					
							sendCommand(Irrigazione_Z5, ON)
						}
					]
					Timer5end = createTimer(endTime) [| 
						sendCommand(Irrigazione_Z5, OFF)
					]
					startTime = endTime.plusMinutes(1)
				}
				if (Z6Time > 0) {
					if(Timer6start!=null) 
					{
						Timer6start.cancel()	
						Timer6start = null
					}
					if(Timer6end!=null)
					{
						Timer6end.cancel()
						Timer6end = null	
					}
										
					endTime = startTime.plusMinutes(Z6Time)
					Timer6start = createTimer(startTime) [| 
						day = now.getDayOfWeek()
						if ((Irrigation_Master.state == ON) &&
						(((day == 1) && (IrrigationMonday.state == ON))	||
						((day == 2) && (IrrigationTuesday.state == ON))	||
						((day == 3) && (IrrigationWensday.state == ON))	||
						((day == 4) && (IrrigationThursday.state == ON))	||
						((day == 5) && (IrrigationFriday.state == ON))	||
						((day == 6) && (IrrigationSaturday.state == ON))	||
						((day == 7) && (IrrigationSunday.state == ON)))) {					
							sendCommand(Irrigazione_Z6, ON)
						}
					]
					Timer6end = createTimer(endTime) [| 
						sendCommand(Irrigazione_Z6, OFF)
						//callScript("endWatering")
					]
					startTime = endTime.plusMinutes(1)
				}
	}finally{
		lock1.unlock()
	}	
    end

I found that the timers I have fire either when they’re created and when they expire. I just want that they fire when they expire. Can you help me? Thanks in advance and merry Christmas to all!!!

I did not get into the problem, but I caught my eye:

if(Timer1start!==null)

if(Timer1start!==null)

Never seen that beefore…

Did it help you?

Not tried yet, but previously had not that statements with the same result… I’ll give it a try…

Tried it, but always the same result…

As a matter of fact, a timer can’t fire twice, but it’s likely that a timer maybe would fire immediately if set to a datetime which has passed right now. (as you calculate the time always with 00 as seconds…)

The difference between != and !== is explained here by @rlkoshak : Trrying to turn a device off after a certain amount of time
You do not need to use this, as it should only create a warn in your logs for now, and you should only use it when comparing to null (yes, there is a difference, but it should not interfere here).

I think you should try to simplify the rule. For example:

if(Timer1start!=null)
    {
        Timer1start.cancel()	
        Timer1start = null
    }

As you set Timer1start (and every other timer) right after killing an old one, there is no need to set the var to null, so you can just use

if (Timer1start !== null) Timer1start.cancel

In question of this part:

if ((Irrigation_Master.state == ON) &&
  (((day == 1) && (IrrigationMonday.state == ON)) ||
   ((day == 2) && (IrrigationTuesday.state == ON)) ||
   ((day == 3) && (IrrigationWensday.state == ON)) ||
   ((day == 4) && (IrrigationThursday.state == ON)) ||
   ((day == 5) && (IrrigationFriday.state == ON)) ||
   ((day == 6) && (IrrigationSaturday.state == ON)) ||
   ((day == 7) && (IrrigationSunday.state == ON))))

I would use another rule and an additional item:

Switch IrrigationDo
rule "set IrrigationDo"
when
    Time cron "1 0 0 * * ?" or
    Item Irrigation_Master changed or
    Item IrrigationMonday changed or
    Item IrrigationTuesday changed or
    Item IrrigationWednesday changed or
    Item IrrigationThursday changed or
    Item IrrigationFriday changed or
    Item IrrigationSaturday changed or
    Item IrrigationSunday changed
then
    val day = now.getDayOfWeek()
    IrrigationDo.postUpdate(
    if (Irrigation_Master.state == ON && (
      (day == 1 && IrrigationMonday.state == ON) ||
      (day == 2 && IrrigationTuesday.state == ON) ||
      (day == 3 && IrrigationWensday.state == ON) ||
      (day == 4 && IrrigationThursday.state == ON) ||
      (day == 5 && IrrigationFriday.state == ON) ||
      (day == 6 && IrrigationSaturday.state == ON) ||
      (day == 7 && IrrigationSunday.state == ON) ) )
        ON else OFF)
end

Keep in mind that you could use a way more elegant way to solve this if using a group and other names for the Irrigation items (Irrigation_1 to Irrigation_7, IrrigationDays would be a group with all Irrigation_n Items as members):

if (Irrigation_Master.state == ON)
    IrrigationDays.filter(Day|
        Day.name.contains(now.getDayOfWeek.toString)
    ).first(today|
        IrrigationDo.postUpdate(today.state)
    )
else
    IrrigationDo.postUpdate(OFF)

then you only have to use

if (IrrigationDo.state == ON) 

in all timers. Of course you should ensure this rule is executed before the other one (set the Seconds a bit higher)

Thank you Udo, my fault. I was not understanding that I was setting a timer (at 02.00 am) that had to fire the next day, but also was expired in the same day (i was setting it after 02.00 am). I modified the rules in the following way:

import org.joda.time.DateTime

var java.util.concurrent.locks.ReentrantLock lock1 = new java.util.concurrent.locks.ReentrantLock()	
var java.util.concurrent.locks.ReentrantLock lock2 = new java.util.concurrent.locks.ReentrantLock()
	
var Timer Timer1start
var Timer Timer2start
var Timer Timer3start
var Timer Timer4start    
var Timer Timer5start
var Timer Timer6start
var Timer Timer1end
var Timer Timer2end
var Timer Timer3end
var Timer Timer4end    
var Timer Timer5end
var Timer Timer6end
var Number day    
            
rule "Irrigation startup"
when
	System started
then
	postUpdate(Irrigation_StartTime, "02:00")
	postUpdate(Irrigation_ScaleFactor, 100)
	postUpdate(IrrigationTimeHour, 2)
	postUpdate(IrrigationTimeMinutes, 0)
	postUpdate(Irrigation_Z1Mins, 10)   		
	postUpdate(Irrigation_Z2Mins, 10)
	postUpdate(Irrigation_Z3Mins, 10)
	postUpdate(Irrigation_Z4Mins, 10)
	postUpdate(Irrigation_Z5Mins, 10)
	postUpdate(Irrigation_Z6Mins, 10)   		   		   		   		   		
	sendCommand(Irrigazione_Z1, OFF)
	sendCommand(Irrigazione_Z2, OFF)
	sendCommand(Irrigazione_Z3, OFF)
	sendCommand(Irrigazione_Z4, OFF)
	sendCommand(Irrigazione_Z5, OFF)
	sendCommand(Irrigazione_Z6, OFF)
	postUpdate(Irrigation_Master, OFF);
	postUpdate(Irrigation_1, OFF)
	postUpdate(Irrigation_2, OFF)
	postUpdate(Irrigation_3, OFF)
	postUpdate(Irrigation_4, OFF)
	postUpdate(Irrigation_5, OFF)
	postUpdate(Irrigation_6, OFF)
	postUpdate(Irrigation_7, OFF)
end

rule "Irrigation change start hour"
when
	Item IrrigationTimeHour changed	or
	Item IrrigationTimeMinutes changed
then

	lock1.lock()	
	
	try
	{
			var String msg = ""
			logInfo("rules","Watering start hour has been changed.")

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

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

			if ((minute as Number) < 10) { msg = msg + "0" }
			msg = msg + IrrigationTimeMinutes.state.format("%d")
			postUpdate(Irrigation_StartTime, msg)
			logInfo("rules","New watering time: "+msg)
						
	}finally{
		lock1.unlock()			
	}
			
end

rule "Irrigation run"
when
    Time cron "5 0 0 * * ?"

then
				
	lock2.lock()			
		
	try {			
			
			// get the scale factor - used to reduce the run times across the board
			var Number scaleFactor = Irrigation_ScaleFactor.state as DecimalType
	
			// convert our start time to a joda.time.DateTime for today
			var DateTime startTime = parse(now.getYear() + "-" + now.getMonthOfYear() + "-" + now.getDayOfMonth() + "T" + Irrigation_StartTime.state + ":00")
			var DateTime endTime
		
			// get the raw run times for each zone (in mins)
			var Number Z1Mins = Irrigation_Z1Mins.state as DecimalType
			var Number Z2Mins = Irrigation_Z2Mins.state as DecimalType
			var Number Z3Mins = Irrigation_Z3Mins.state as DecimalType
			var Number Z4Mins = Irrigation_Z4Mins.state as DecimalType
			var Number Z5Mins = Irrigation_Z5Mins.state as DecimalType
			var Number Z6Mins = Irrigation_Z6Mins.state as DecimalType
			
			// convert to the actual run times (by applying the scale factor)
			var int Z1Time = ((Z1Mins * scaleFactor) / 100).intValue
			var int Z2Time = ((Z2Mins * scaleFactor) / 100).intValue
			var int Z3Time = ((Z3Mins * scaleFactor) / 100).intValue
			var int Z4Time = ((Z4Mins * scaleFactor) / 100).intValue
			var int Z5Time = ((Z5Mins * scaleFactor) / 100).intValue
			var int Z6Time = ((Z6Mins * scaleFactor) / 100).intValue
			
			logInfo("rules","New watering time scheduled")				
			
			// turn on each zone in turn (with a minute gap between each zone activation)
			if (Z1Time > 0) {
				if(Timer1start!=null) 
				{
					Timer1start.cancel()	
					//Timer1start = null
				}
				if(Timer1end!=null)
				{
					Timer1end.cancel()
					//Timer1end = null	
				}					
				endTime = startTime.plusMinutes(Z1Time)
				Timer1start = createTimer(startTime) [|
				if (IrrigationDo.state == ON) {					
						sendCommand(Irrigazione_Z1, ON)
						//callScript("startWatering")
					}
				]
				Timer1end = createTimer(endTime) [| sendCommand(Irrigazione_Z1, OFF) ]
				startTime = endTime.plusMinutes(1)
			}
			
			if (Z2Time > 0) {
				if(Timer2start!=null) 
				{
					Timer2start.cancel()	
					//Timer2start = null
				}
				if(Timer2end!=null)
				{
					Timer2end.cancel()
					//Timer2end = null	
				}
				endTime = startTime.plusMinutes(Z2Time)
				Timer2start = createTimer(startTime) [| 
					if (IrrigationDo.state == ON) {					
						sendCommand(Irrigazione_Z2, ON)
					}	
				]
				
				Timer2end = createTimer(endTime) [| sendCommand(Irrigazione_Z2, OFF) ]
				startTime = endTime.plusMinutes(1)
			}
			
			if (Z3Time > 0) {
				if(Timer3start!=null) 
				{
					Timer3start.cancel()	
					//Timer3start = null
				}
				if(Timer3end!=null)
				{
					Timer3end.cancel()
					//Timer3end = null	
				}					
				endTime = startTime.plusMinutes(Z3Time)
				Timer3start = createTimer(startTime) [| 
					if (IrrigationDo.state == ON) {					
						sendCommand(Irrigazione_Z3, ON)
					}
				]
				
				Timer3end = createTimer(endTime) [| sendCommand(Irrigazione_Z3, OFF) ]
				startTime = endTime.plusMinutes(1)
			}
			
			if (Z4Time > 0) {
				if(Timer4start!=null) 
				{
					Timer4start.cancel()	
					//Timer4start = null
				}
				if(Timer4end!=null)
				{
					Timer4end.cancel()
					//Timer4end = null	
				}
				
				endTime = startTime.plusMinutes(Z4Time)
				Timer4start = createTimer(startTime) [| 
					if (IrrigationDo.state == ON) {					
						sendCommand(Irrigazione_Z4, ON)
					}
				]
				Timer4end = createTimer(endTime) [| sendCommand(Irrigazione_Z4, OFF) ]
				startTime = endTime.plusMinutes(1)
			}
			if (Z5Time > 0) {
				if(Timer5start!=null) 
				{
					Timer5start.cancel()	
					//Timer5start = null
				}
				if(Timer5end!=null)
				{
					Timer5end.cancel()
					//Timer5end = null	
				}
									
				endTime = startTime.plusMinutes(Z5Time)
				Timer5start = createTimer(startTime) [| 
					day = now.getDayOfWeek()
					if (IrrigationDo.state == ON) {					
						sendCommand(Irrigazione_Z5, ON)
					}
				]
				Timer5end = createTimer(endTime) [| 
					sendCommand(Irrigazione_Z5, OFF)
				]
				startTime = endTime.plusMinutes(1)
			}
			if (Z6Time > 0) {
				if(Timer6start!=null) 
				{
					Timer6start.cancel()	
					//Timer6start = null
				}
				if(Timer6end!=null)
				{
					Timer6end.cancel()
					//Timer6end = null	
				}
									
				endTime = startTime.plusMinutes(Z6Time)
				Timer6start = createTimer(startTime) [| 
					if (IrrigationDo.state == ON) {					
						sendCommand(Irrigazione_Z6, ON)
					}
				]
				Timer6end = createTimer(endTime) [| 
					sendCommand(Irrigazione_Z6, OFF)
					//callScript("endWatering")
				]
				startTime = endTime.plusMinutes(1)
			}
}finally{
	lock2.unlock()
}	
end

rule "Master State OFF"
when
	Item Irrigation_Master changed	
then

if(Irrigation_Master.state == OFF)
{
	logInfo("rules","Auto watering OFF.")
	//callScript("endWatering")    	
	
	sendCommand(Irrigazione_Z1, OFF)
	sendCommand(Irrigazione_Z2, OFF)
	sendCommand(Irrigazione_Z3, OFF)
	sendCommand(Irrigazione_Z4, OFF)
	sendCommand(Irrigazione_Z5, OFF)
	sendCommand(Irrigazione_Z6, OFF)
 }
end

rule "set IrrigationDo"
when
Time cron “1 0 0 * * ?” or
Item Irrigation_Master changed or
Item Irrigation_1 changed or
Item Irrigation_2 changed or
Item Irrigation_3 changed or
Item Irrigation_4 changed or
Item Irrigation_5 changed or
Item Irrigation_6 changed or
Item Irrigation_7 changed
then
val day = now.getDayOfWeek()
IrrigationDo.postUpdate(
if (Irrigation_Master.state == ON && (
(day == 1 && Irrigation_1.state == ON) ||
(day == 2 && Irrigation_2.state == ON) ||
(day == 3 && Irrigation_3.state == ON) ||
(day == 4 && Irrigation_4.state == ON) ||
(day == 5 && Irrigation_5.state == ON) ||
(day == 6 && Irrigation_6.state == ON) ||
(day == 7 && Irrigation_7.state == ON) ) )
ON else OFF)
end

Obviously. new watering hour will be available only after the midnight of the following day, but It’s ok for me. Thankyou very much.

I made some modifications with a check if watering time has passed or not:

import org.joda.time.DateTime

var java.util.concurrent.locks.ReentrantLock lock1 = new java.util.concurrent.locks.ReentrantLock()	
var java.util.concurrent.locks.ReentrantLock lock2 = new java.util.concurrent.locks.ReentrantLock()
	
var Timer Timer1start
var Timer Timer2start
var Timer Timer3start
var Timer Timer4start    
var Timer Timer5start
var Timer Timer6start
var Timer Timer1end
var Timer Timer2end
var Timer Timer3end
var Timer Timer4end    
var Timer Timer5end
var Timer Timer6end
var Number day    
            
rule "Irrigation startup"
when
	System started
then
	postUpdate(Irrigation_StartTime, "02:00")
	postUpdate(Irrigation_ScaleFactor, 100)
	postUpdate(IrrigationTimeHour, 2)
	postUpdate(IrrigationTimeMinutes, 0)
	postUpdate(Irrigation_Z1Mins, 10)   		
	postUpdate(Irrigation_Z2Mins, 10)
	postUpdate(Irrigation_Z3Mins, 10)
	postUpdate(Irrigation_Z4Mins, 10)
	postUpdate(Irrigation_Z5Mins, 10)
	postUpdate(Irrigation_Z6Mins, 10)   		   		   		   		   		
	sendCommand(Irrigazione_Z1, OFF)
	sendCommand(Irrigazione_Z2, OFF)
	sendCommand(Irrigazione_Z3, OFF)
	sendCommand(Irrigazione_Z4, OFF)
	sendCommand(Irrigazione_Z5, OFF)
	sendCommand(Irrigazione_Z6, OFF)
	postUpdate(Irrigation_Master, OFF);
	postUpdate(Irrigation_1, OFF)
	postUpdate(Irrigation_2, OFF)
	postUpdate(Irrigation_3, OFF)
	postUpdate(Irrigation_4, OFF)
	postUpdate(Irrigation_5, OFF)
	postUpdate(Irrigation_6, OFF)
	postUpdate(Irrigation_7, OFF)
end

rule "Irrigation change start hour"
when
	Item IrrigationTimeHour changed	or
	Item IrrigationTimeMinutes changed
then

	lock1.lock()	
	
	try
	{
			var String msg = ""
			logInfo("rules","Watering start hour has been changed.")

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

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

			if ((minute as Number) < 10) { msg = msg + "0" }
			msg = msg + IrrigationTimeMinutes.state.format("%d")
			postUpdate(Irrigation_StartTime, msg)
			logInfo("rules","New watering time: "+msg)
						
	}finally{
		lock1.unlock()			
	}
			
end

rule "Irrigation run"
when
    Time cron "5 0 0 * * ?" or
	Item Irrigation_StartTime changed
then
				
	lock2.lock()			
		
	try {			
			
			// get the scale factor - used to reduce the run times across the board
			var Number scaleFactor = Irrigation_ScaleFactor.state as DecimalType
	
			// convert our start time to a joda.time.DateTime for today
			var DateTime startTime = parse(now.getYear() + "-" + now.getMonthOfYear() + "-" + now.getDayOfMonth() + "T" + Irrigation_StartTime.state + ":00")
			var DateTime endTime
		
			// get the raw run times for each zone (in mins)
			var Number Z1Mins = Irrigation_Z1Mins.state as DecimalType
			var Number Z2Mins = Irrigation_Z2Mins.state as DecimalType
			var Number Z3Mins = Irrigation_Z3Mins.state as DecimalType
			var Number Z4Mins = Irrigation_Z4Mins.state as DecimalType
			var Number Z5Mins = Irrigation_Z5Mins.state as DecimalType
			var Number Z6Mins = Irrigation_Z6Mins.state as DecimalType
			
			// convert to the actual run times (by applying the scale factor)
			var int Z1Time = ((Z1Mins * scaleFactor) / 100).intValue
			var int Z2Time = ((Z2Mins * scaleFactor) / 100).intValue
			var int Z3Time = ((Z3Mins * scaleFactor) / 100).intValue
			var int Z4Time = ((Z4Mins * scaleFactor) / 100).intValue
			var int Z5Time = ((Z5Mins * scaleFactor) / 100).intValue
			var int Z6Time = ((Z6Mins * scaleFactor) / 100).intValue
			
			val checktime = startTime.millis
			
			if( now.isBefore(checktime))
			{
			logInfo("rules","New watering time scheduled")				
			
			// turn on each zone in turn (with a minute gap between each zone activation)
			if (Z1Time > 0) {
				if(Timer1start!=null) 
				{
					Timer1start.cancel()	
					//Timer1start = null
				}
				if(Timer1end!=null)
				{
					Timer1end.cancel()
					//Timer1end = null	
				}					
				endTime = startTime.plusMinutes(Z1Time)
				Timer1start = createTimer(startTime) [|
				if (IrrigationDo.state == ON) {					
						sendCommand(Irrigazione_Z1, ON)
						callScript("startWatering")
					}
				]
				Timer1end = createTimer(endTime) [| sendCommand(Irrigazione_Z1, OFF) ]
				startTime = endTime.plusMinutes(1)
			}
			
			if (Z2Time > 0) {
				if(Timer2start!=null) 
				{
					Timer2start.cancel()	
					//Timer2start = null
				}
				if(Timer2end!=null)
				{
					Timer2end.cancel()
					//Timer2end = null	
				}
				endTime = startTime.plusMinutes(Z2Time)
				Timer2start = createTimer(startTime) [| 
					if (IrrigationDo.state == ON) {					
						sendCommand(Irrigazione_Z2, ON)
					}	
				]
				
				Timer2end = createTimer(endTime) [| sendCommand(Irrigazione_Z2, OFF) ]
				startTime = endTime.plusMinutes(1)
			}
			
			if (Z3Time > 0) {
				if(Timer3start!=null) 
				{
					Timer3start.cancel()	
					//Timer3start = null
				}
				if(Timer3end!=null)
				{
					Timer3end.cancel()
					//Timer3end = null	
				}					
				endTime = startTime.plusMinutes(Z3Time)
				Timer3start = createTimer(startTime) [| 
					if (IrrigationDo.state == ON) {					
						sendCommand(Irrigazione_Z3, ON)
					}
				]
				
				Timer3end = createTimer(endTime) [| sendCommand(Irrigazione_Z3, OFF) ]
				startTime = endTime.plusMinutes(1)
			}
			
			if (Z4Time > 0) {
				if(Timer4start!=null) 
				{
					Timer4start.cancel()	
					//Timer4start = null
				}
				if(Timer4end!=null)
				{
					Timer4end.cancel()
					//Timer4end = null	
				}
				
				endTime = startTime.plusMinutes(Z4Time)
				Timer4start = createTimer(startTime) [| 
					if (IrrigationDo.state == ON) {					
						sendCommand(Irrigazione_Z4, ON)
					}
				]
				Timer4end = createTimer(endTime) [| sendCommand(Irrigazione_Z4, OFF) ]
				startTime = endTime.plusMinutes(1)
			}
			if (Z5Time > 0) {
				if(Timer5start!=null) 
				{
					Timer5start.cancel()	
					//Timer5start = null
				}
				if(Timer5end!=null)
				{
					Timer5end.cancel()
					//Timer5end = null	
				}
									
				endTime = startTime.plusMinutes(Z5Time)
				Timer5start = createTimer(startTime) [| 
					day = now.getDayOfWeek()
					if (IrrigationDo.state == ON) {					
						sendCommand(Irrigazione_Z5, ON)
					}
				]
				Timer5end = createTimer(endTime) [| 
					sendCommand(Irrigazione_Z5, OFF)
				]
				startTime = endTime.plusMinutes(1)
			}
			if (Z6Time > 0) {
				if(Timer6start!=null) 
				{
					Timer6start.cancel()	
					//Timer6start = null
				}
				if(Timer6end!=null)
				{
					Timer6end.cancel()
					//Timer6end = null	
				}
									
				endTime = startTime.plusMinutes(Z6Time)
				Timer6start = createTimer(startTime) [| 
					if (IrrigationDo.state == ON) {					
						sendCommand(Irrigazione_Z6, ON)
					}
				]
				Timer6end = createTimer(endTime) [| 
					sendCommand(Irrigazione_Z6, OFF)
					callScript("endWatering")
				]
				startTime = endTime.plusMinutes(1)
			}
		}
}finally{
	lock2.unlock()
}	
end

rule "Master State OFF"
when
	Item Irrigation_Master changed	
then

if(Irrigation_Master.state == OFF)
{
	logInfo("rules","Auto watering OFF.")
	//callScript("endWatering")    	
	
	sendCommand(Irrigazione_Z1, OFF)
	sendCommand(Irrigazione_Z2, OFF)
	sendCommand(Irrigazione_Z3, OFF)
	sendCommand(Irrigazione_Z4, OFF)
	sendCommand(Irrigazione_Z5, OFF)
	sendCommand(Irrigazione_Z6, OFF)
 }
end

rule "set IrrigationDo"
when
Time cron “1 0 0 * * ?” or
Item Irrigation_Master changed or
Item Irrigation_StartTime changed or
Item Irrigation_1 changed or
Item Irrigation_2 changed or
Item Irrigation_3 changed or
Item Irrigation_4 changed or
Item Irrigation_5 changed or
Item Irrigation_6 changed or
Item Irrigation_7 changed
then
val day = now.getDayOfWeek()
IrrigationDo.postUpdate(
if (Irrigation_Master.state == ON && (
(day == 1 && Irrigation_1.state == ON) ||
(day == 2 && Irrigation_2.state == ON) ||
(day == 3 && Irrigation_3.state == ON) ||
(day == 4 && Irrigation_4.state == ON) ||
(day == 5 && Irrigation_5.state == ON) ||
(day == 6 && Irrigation_6.state == ON) ||
(day == 7 && Irrigation_7.state == ON) ) )
ON else OFF)
end

Do you think, it’s ok?