Design concept: Google Home timed devices

Ever since I got some Google Home’s, I felt the urge to ask Google to turn on a specific lamp for a certain amount of time, like “OK Google, Turn on the shed light for 10 minutes”, which would give me plenty of time to walk to the shed in the back of the garden, get my bike, get out of the garden and take off, without having to do that in complete darkness of while leaving on the lights until I got back home or remembered to turn off the lights again via the app upon arriving at my destination. Although this example might also be solved by other methods, I figured there might be a general use for this, and as the Google Home does not support this behaviour, I figured I would make a way around that.

Now lets assume that I have a light that is called “shed lamp”, with the main switch item called “Shedlamp_Switch”, which I have defined in for example Habmin or Paper UI. What I did next, is that I made the following items:

Switch ShedScene5 "Shed lamp for 5 minutes" [ "Switchable" ]
Switch ShedScene10 "Shed lamp for 10 minutes" [ "Switchable" ]
Switch ShedScene20 "Shed lamp for 20 minutes" [ "Switchable" ]

With this label exposed to the Google Home, and using the structure “Hey Google, Turn on/off X”, you could make Google flip the switches above, like “Hey Google, Turn on shed lamp for 10 minutes.”

These switches subsequently trigger the following rule:

var Timer ShedTimer = null

rule "Shed lamp timer activated"
    when 
        Item ShedScene5 received command or
        Item ShedScene10 received command or
        Item ShedScene20 received command
    then
		logInfo("Shedlamp.Timers", "Shedlamp timer activated by " + triggeringItem.name + ", is set to " + receivedCommand + " for " + triggeringItem.name.substring("ShedScene".length, triggeringItem.name.length) + " minutes")

        Shedlamp_Switch.sendCommand(receivedCommand)

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

        ShedTimer = createTimer(now.plusMinutes(Integer::parseInt(triggeringItem.name.substring("ShedScene".length,  triggeringItem.name.length))), [|
            logInfo("Shedlamp.Timers", "Shedlamp timer expired, now turning " + if(receivedCommand==ON) "OFF" else "ON")
            Shedlamp_Switch.sendCommand(if(receivedCommand==ON) OFF else ON)
            triggeringItem.postUpdate(if(receivedCommand==ON) OFF else ON)
        ])
end

Similarly, you could make items that switch on/off the light in x minutes time with an item definition like so:

Switch ShedSceneIn10 "Shed lamp in 10 minutes" [ "Switchable" ]

And a rule definition like so:

rule "Shedlamp timer activated 2"
    when 
        Item ShedSceneIn10 received command
    then
		logInfo("Shedlamp.Timers", "Shedlamptimer activated by " + triggeringItem.name + ", is set to " + receivedCommand + " in " + triggeringItem.name.substring("ShedSceneIn".length, triggeringItem.name.length) + " minutes")

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

        ShedTimer = createTimer(now.plusMinutes(Integer::parseInt(triggeringItem.name.substring("ShedSceneIn".length,  triggeringItem.name.length))), [|
            logInfo("Shedlamp.Timers", "Shedlamp timer expired, now turning " + receivedCommand.toString)
            Shedlamp_Switch.sendCommand(receivedCommand)
        ])
end

Personally I also like to be able to cancel the timer without adding extra items, for that I added this rule, so that I can just say “Turn off shed lamp”, and regardless of whether the lamp is on or off, this will cancel a timer that would change the state of the lamp:

rule "Shedlamp timer overrule"
    when
        Item Shedlamp_Switch received command
    then
        if(ShedTimer !== null){
            ShedTimer.cancel()
        }
end

Of course it is essential for this to work, to make it work with whatever language you are speaking, in my own language, Dutch, a grammatically more sensible way would be to say “Turn lamp x in y minutes off” or “Turn lamp x y minutes on” to turn the lamp off in a few minutes or to turn the lamp on for a few minutes, respectively.

I hope this helps some people to add some functionality to their Google Home or comparable systems, and any feedback is always appreciated.

4 Likes

very cool trick!
copying the setup now :slight_smile:
added a link to this from HowTo: Listen & Talk to your Home

1 Like

I did something similar using IFTTT and my irrigation

I have the following items

Switch SprinklerSystemZone1 "Front Grass Sprinklers"     	(gIrrigation)      	[ "Switchable" ] 	{ mqtt=">[broker:SprinklerSystem:command:ON:Z1ON],>[broker:SprinklerSystem:command:OFF:Z1OFF]" }
Switch SprinklerSystemZone2 "Front Garden Sprinklers" 	   	(gIrrigation)	 	[ "Switchable" ] 	{ mqtt=">[broker:SprinklerSystem:command:ON:Z2ON],>[broker:SprinklerSystem:command:OFF:Z2OFF]" }
Switch SprinklerSystemZone3 "Back Grass Sprinklers" 		(gIrrigation)		[ "Switchable" ] 	{ mqtt=">[broker:SprinklerSystem:command:ON:Z3ON],>[broker:SprinklerSystem:command:OFF:Z3OFF]" }
Switch SprinklerSystemZone4 "Back Garden Sprinklers" 		(gIrrigation)		[ "Switchable" ] 	{ mqtt=">[broker:SprinklerSystem:command:ON:Z4ON],>[broker:SprinklerSystem:command:OFF:Z4OFF]" }


Number onHours1 "Front Grass Sprinkler Minutes" 	(gIrrigationTimes)
Number onHours2 "Front Garden Sprinkler Minutes"	(gIrrigationTimes)
Number onHours3 "Back Grass Sprinkler Minutes"		(gIrrigationTimes)
Number onHours4 "Back Garden Sprinkler Minutes"		(gIrrigationTimes)

String IFTTString "If this then that string" (All)

This rules file


//***************************************************************************


rule "IFTT rule"
when
    Item IFTTString received update
then
var item=IFTTString.state.toString.split(";").get(0)
val time = Integer::parseInt(IFTTString.state.toString.split(";").get(1))

if (item.contains("back garden"))
{
postUpdate(onHours4, time)
SprinklerSystemZone4.sendCommand(ON)
}

if (item.contains("back grass"))
{
postUpdate(onHours3, time)
SprinklerSystemZone3.sendCommand(ON)
}

if (item.contains("front garden"))
{
postUpdate(onHours2, time)
SprinklerSystemZone2.sendCommand(ON)
}

if (item.contains("front grass"))
{
postUpdate(onHours1, time)
SprinklerSystemZone1.sendCommand(ON)
}
end

and an example of a sprinkler zone rule


//**************************************************************************************
//Zone 1 Watering	


rule "Zone 1 Watering"
when
    Item SprinklerSystemZone1 changed to ON
then

if (onHours1.state !== NULL)
	{
	
	
		var Number timeout = onHours1.state as DecimalType
		var int lawnTime = (timeout).intValue
		postUpdate(Irrigation_StartTime1, new DateTimeType())
		Irrigation_Zone1.postUpdate("Active")

		if (lawnTime > 0)
		{
		sendBroadcastNotification("Watering Zone 1 for " +  timeout.toString + " minutes")
		Irrigation_Zone1.postUpdate("Active " + timeout.toString + " minutes remaining")
		Countdown_Zone1.postUpdate(lawnTime)

		}
	}
else
	{
	SprinklerSystemZone1.sendCommand(OFF)
	onHours1.postUpdate(30)
	sendBroadcastNotification("Zone 1 does not have a timer set, this zone has been set to 30 minutes, please try again")

	}
end

and a countdown timer rule


//***************************************************************************

rule "Countdown Zone 1 Timer"
when
        Item Countdown_Zone1 received update
then	
if (Countdown_Zone1.state as DecimalType >= 1 && SprinklerSystemZone1.state == ON)
		{
			Irrigation_Zone1.postUpdate("Active " + (Countdown_Zone1.state as DecimalType) + " minutes remaining")
	    	timer1 = createTimer(now.plusMinutes(1)) [|
			Countdown_Zone1.postUpdate(Countdown_Zone1.state as DecimalType - 1)
			]
		}
			
if (Countdown_Zone1.state as DecimalType == 0 && SprinklerSystemZone1.state == ON)
				{
				SprinklerSystemZone1.sendCommand(OFF)
				sendBroadcastNotification("Finished Watering Zone 1")
				}
end

so what happens is the IFTTT string receives a string with the following

back garden; 20

My rule then splits that and sends the time to my timer (which is onHours), which i have other rules to show time remaining and have an ‘active for n minutes’ on my sitemap.

My IFTTT is setup to listen to a command "Turn on the X for # minutes.

you could do the same with Lights.

Have an item switch light setup. and a timer for that light.
then a rule that when the timer gets an updated time, create a timer countdown for the number received, and after that turn the light off.

IF the light is turned off before the timer expires, cancel the timer.

1 Like