Toggle light after turned on

I have a light switch in the bathroom that controls the light and fan, when you turn on the light switch the fan turns on “low” speed, when you turn off and on the light switch the fan goes into high speed. I want to run the light/fan for 2 hours at high speed and then shut off.

This code works fine for keeping the light & fan on for 2 hours but I cannot seem to come up with the code to perform a off/on (only once) when the switch is turn on.

rule "MasterBathroom Light/Fan Timer"
when
Item Light_GF_MasterBath changed
then
if (Light_GF_MasterBath.state==OFF) {
bathtimer.cancel
bathtimer = null
}
else if (Light_GF_MasterBath.state==ON){
bathtimer = createTimer(now.plusMinutes(120)) [|
sendCommand(Light_GF_MasterBath, OFF)
]
}
end

It’s not yet clear what you are trying to do in the rule. There are no clues about how to control fan speed, if that is what you intend?

Is that you want -
W to happen when switch turned on
X to happen if switched turned off
Y to happen if switch turned on again within a certain time
Z to happen if switch left on for more than some time, whether we are in state W or state Y ?

Putting your requirement in these kinds of terms might help to see how to make a rule.

When the switch is changed I want the light to turn on, then after 2 seconds turn light off and then immediately turn back on for 2 hours. If the switch is turned off at any point then turn off the light and leave it off.

Seeing as the first bit all happens in about 3 seconds, I think I would do it with simple delays. And implement some kind of lockout so that fiddling with the switch during those three seconds is ignored.

var bathlockout = 0
var Timer bathtimer = null

when
  some_item changed
then
  if (bathtimer != null) {    // cancel before 2 hours 
         bathtimer.cancel
         bathtimer = null
         some_light.sendCommand(OFF)
  } else if (bathlockout == 0) {   // first time startup
         bathlockout = 1
         some_light.sendCommand(ON)
         Thread::sleep(2000)
         some_light.sendCommand(OFF)
         Thread::sleep(500)
         some_light.sendCommand(ON)
         bathtimer = createTimer(now.plusMinutes(120)) [|    // off in two hours
              some_light.sendCommand(OFF) 
              bathtimer = null
         ]
         bathlockout = 0
  }
end

This rule was working flawlessly under OH1.8 and now I’ve recently upgraded to OpenHab2 and it’s not working as it was before. What happens now is that after the 2 hours the light turns off and we log that the timer has expired, and then the light turns back on and the timer starts again…

Here’s my current code:

rule "MasterBathroom Light/Fan Timer"
when
	Item Light_MasterBath changed
then
	if (bathtimer !== null) { // cancel before 2 hours
		bathtimer.cancel
		bathtimer = null
		logInfo("rules", "Bathroom Off")
		sendCommand(Light_MasterBath, OFF)
	} else if (bathlockout == 0 ) { // first time startup
		logInfo("rules", "Starting toggle sequence")
		bathlockout = 1
		sendCommand(Light_MasterBath, ON)
		Thread::sleep(2000)
		sendCommand(Light_MasterBath, OFF)
		Thread::sleep(500)
		sendCommand(Light_MasterBath, ON)
		logInfo("rules", "Starting Timer for bathroom light")
		bathtimer = createTimer(now.plusMinutes(120)) [| // off in 2 hours
			sendCommand(Light_MasterBath, OFF)
			logInfo("rules", "Timer Expired turning off bathroom light")
			bathtimer = null
		]
		bathlockout = 0
	}
end

Here’s my logs

2017-12-28 15:36:33.813 [ome.event.ItemCommandEvent] - Item 'Light_MasterBath' received command ON
2017-12-28 15:36:33.846 [vent.ItemStateChangedEvent] - Light_MasterBath changed from OFF to ON
2017-12-28 15:36:39.746 [INFO ] [eclipse.smarthome.model.script.rules] - Starting Timer for bathroom light
2017-12-28 15:36:39.755 [ome.event.ItemCommandEvent] - Item 'Light_MasterBath' received command ON
2017-12-28 15:36:41.773 [ome.event.ItemCommandEvent] - Item 'Light_MasterBath' received command OFF
2017-12-28 15:36:41.808 [vent.ItemStateChangedEvent] - Light_MasterBath changed from ON to OFF
2017-12-28 15:36:42.280 [ome.event.ItemCommandEvent] - Item 'Light_MasterBath' received command ON
2017-12-28 15:36:42.304 [vent.ItemStateChangedEvent] - Light_MasterBath changed from OFF to ON
2017-12-28 17:36:42.288 [ome.event.ItemCommandEvent] - Item 'Light_MasterBath' received command OFF
2017-12-28 17:36:42.289 [INFO ] [eclipse.smarthome.model.script.rules] - Timer Expired turning off bathroom light
2017-12-28 17:36:42.326 [vent.ItemStateChangedEvent] - Light_MasterBath changed from ON to OFF
2017-12-28 17:36:42.352 [INFO ] [eclipse.smarthome.model.script.rules] - Starting Timer for bathroom light
2017-12-28 17:36:42.362 [ome.event.ItemCommandEvent] - Item 'Light_MasterBath' received command ON
2017-12-28 17:36:42.375 [vent.ItemStateChangedEvent] - Light_MasterBath changed from OFF to ON
2017-12-28 17:36:44.379 [ome.event.ItemCommandEvent] - Item 'Light_MasterBath' received command OFF
2017-12-28 17:36:44.401 [vent.ItemStateChangedEvent] - Light_MasterBath changed from ON to OFF
2017-12-28 17:36:44.895 [ome.event.ItemCommandEvent] - Item 'Light_MasterBath' received command ON
2017-12-28 17:36:44.913 [vent.ItemStateChangedEvent] - Light_MasterBath changed from OFF to ON
2017-12-28 17:36:44.925 [INFO ] [eclipse.smarthome.model.script.rules] - Bathroom Off
2017-12-28 17:36:44.935 [ome.event.ItemCommandEvent] - Item 'Light_MasterBath' received command OFF
2017-12-28 17:36:44.952 [vent.ItemStateChangedEvent] - Light_MasterBath changed from ON to OFF
2017-12-28 17:36:44.965 [INFO ] [eclipse.smarthome.model.script.rules] - Starting Timer for bathroom light
2017-12-28 17:36:44.979 [ome.event.ItemCommandEvent] - Item 'Light_MasterBath' received command ON
2017-12-28 17:36:44.989 [vent.ItemStateChangedEvent] - Light_MasterBath changed from OFF to ON
2017-12-28 17:36:46.985 [ome.event.ItemCommandEvent] - Item 'Light_MasterBath' received command OFF
2017-12-28 17:36:47.000 [vent.ItemStateChangedEvent] - Light_MasterBath changed from ON to OFF
2017-12-28 17:36:47.491 [ome.event.ItemCommandEvent] - Item 'Light_MasterBath' received command ON
2017-12-28 17:36:47.519 [vent.ItemStateChangedEvent] - Light_MasterBath changed from OFF to ON
2017-12-28 17:36:47.535 [INFO ] [eclipse.smarthome.model.script.rules] - Bathroom Off
2017-12-28 17:36:47.542 [ome.event.ItemCommandEvent] - Item 'Light_MasterBath' received command OFF
2017-12-28 17:36:47.552 [vent.ItemStateChangedEvent] - Light_MasterBath changed from ON to OFF
2017-12-28 17:36:47.562 [INFO ] [eclipse.smarthome.model.script.rules] - Starting Timer for bathroom light
2017-12-28 17:36:47.573 [ome.event.ItemCommandEvent] - Item 'Light_MasterBath' received command ON
2017-12-28 17:36:47.579 [vent.ItemStateChangedEvent] - Light_MasterBath changed from OFF to ON
2017-12-28 17:36:49.578 [ome.event.ItemCommandEvent] - Item 'Light_MasterBath' received command OFF
2017-12-28 17:36:49.602 [vent.ItemStateChangedEvent] - Light_MasterBath changed from ON to OFF
2017-12-28 17:36:50.090 [ome.event.ItemCommandEvent] - Item 'Light_MasterBath' received command ON
2017-12-28 17:36:50.103 [vent.ItemStateChangedEvent] - Light_MasterBath changed from OFF to ON
2017-12-28 17:36:50.116 [INFO ] [eclipse.smarthome.model.script.rules] - Bathroom Off
2017-12-28 17:36:50.122 [ome.event.ItemCommandEvent] - Item 'Light_MasterBath' received command OFF
2017-12-28 17:36:50.135 [vent.ItemStateChangedEvent] - Light_MasterBath changed from ON to OFF
2017-12-28 17:36:50.143 [INFO ] [eclipse.smarthome.model.script.rules] - Starting Timer for bathroom light
2017-12-28 17:36:50.151 [ome.event.ItemCommandEvent] - Item 'Light_MasterBath' received command ON
2017-12-28 17:36:50.162 [vent.ItemStateChangedEvent] - Light_MasterBath changed from OFF to ON
2017-12-28 17:36:52.155 [ome.event.ItemCommandEvent] - Item 'Light_MasterBath' received command OFF
2017-12-28 17:36:52.162 [vent.ItemStateChangedEvent] - Light_MasterBath changed from ON to OFF
2017-12-28 17:36:52.668 [ome.event.ItemCommandEvent] - Item 'Light_MasterBath' received command ON
2017-12-28 17:36:52.688 [vent.ItemStateChangedEvent] - Light_MasterBath changed from OFF to ON
2017-12-28 17:36:52.704 [INFO ] [eclipse.smarthome.model.script.rules] - Starting Timer for bathroom light
2017-12-28 17:36:52.713 [ome.event.ItemCommandEvent] - Item 'Light_MasterBath' received command ON
2017-12-28 17:36:54.722 [ome.event.ItemCommandEvent] - Item 'Light_MasterBath' received command OFF
2017-12-28 17:36:54.754 [vent.ItemStateChangedEvent] - Light_MasterBath changed from ON to OFF
2017-12-28 17:36:54.758 [INFO ] [eclipse.smarthome.model.script.rules] - Bathroom Off
2017-12-28 17:36:54.769 [ome.event.ItemCommandEvent] - Item 'Light_MasterBath' received command OFF
2017-12-28 17:36:55.230 [ome.event.ItemCommandEvent] - Item 'Light_MasterBath' received command ON
2017-12-28 17:36:55.252 [vent.ItemStateChangedEvent] - Light_MasterBath changed from OFF to ON
2017-12-28 17:36:55.264 [INFO ] [eclipse.smarthome.model.script.rules] - Starting Timer for bathroom light
2017-12-28 17:36:55.273 [ome.event.ItemCommandEvent] - Item 'Light_MasterBath' received command ON
2017-12-28 17:36:57.281 [ome.event.ItemCommandEvent] - Item 'Light_MasterBath' received command OFF
2017-12-28 17:36:57.295 [vent.ItemStateChangedEvent] - Light_MasterBath changed from ON to OFF
2017-12-28 17:36:57.315 [INFO ] [eclipse.smarthome.model.script.rules] - Bathroom Off
2017-12-28 17:36:57.323 [ome.event.ItemCommandEvent] - Item 'Light_MasterBath' received command OFF
2017-12-28 17:36:57.799 [ome.event.ItemCommandEvent] - Item 'Light_MasterBath' received command ON
2017-12-28 17:36:57.812 [vent.ItemStateChangedEvent] - Light_MasterBath changed from OFF to ON

This is my refactored rule for OH2, it seems to be working. I’ll do more testing and post results here.

rule "MasterBathroom Light/Fan Timer"
when
    Item Light_MasterBath changed
then
    if (Light_MasterBath.state == ON) {
        if (bathtimer === null) {
			logInfo("rules", "Starting Timer for bathroom light")
            // first ON command, so create a timer to turn the light off again
			sendCommand(Light_MasterBath, OFF)
			Thread::sleep(500)
			sendCommand(Light_MasterBath, ON)
            bathtimer = createTimer(now.plusMinutes(120)) [|
                sendCommand(Light_MasterBath, OFF)
				logInfo("rules", "Timer Expired turning off bathroom light")
            ]
        } else {
	     logInfo("rules", "Resetting Timer for bathroom light")
            // subsequent ON command, so reschedule the existing timer
            bathtimer.reschedule(now.plusMinutes(120))
        }
    } else if (Light_MasterBath.state == OFF) {
	logInfo("rules", "turning bathroom light off")
        // remove any previously scheduled timer
        if (bathtimer !== null) {
            bathtimer.cancel
            bathtimer = null
        }
    }
end