3 different methods to use scenes with Google Home & openHAB

scene
googlehome
googleassistant
Tags: #<Tag:0x00007f014b7ac238> #<Tag:0x00007f014b7b3c40> #<Tag:0x00007f014b7b3a10>

(B K) #1

In this post (and the associated video), I will show you 3 ways to set up scenes in openHAB and connect them with Google Home/Assistant for voice control.

The three methods vary in flexibility (from simple set of on/off commands, to a fully dynamic and customizable scene with setpoint storage), but increase in complexity (from pressing a few buttons in the Google Home app, to creating a set of duplicate items and multiple rules to store the configurable scene settings). Each method should satisfy a need depending on the level of functionality you require.

I’m making an assumption that you already have Google Home and your openHAB connected and items tagged. If not, please read this article and how-to video: Google Home & openHAB connection How-To

I’ve divided the post into three sections, one for each method.

Method 1 - Google Home Routines

This method is very simple, made available by the recently released Google Assistant routines. Simply go to your Google Home app, click on More Settings, Routines, select the routine you want to use, check the “Adjust Lights, plugs, and more” option and click the settings icon next to it. From here, you can select every item you want to change as part of the routine, by selecting “Turn On” or “Turn Off”. Back out of the settings page and hit Save - that’s it!

As you may have guessed, the routines don’t allow fine tuning of light brigthness or changing colors, etc…But, you can get a nice scene set up in minutes!

Method 2 - Use switch item in openHAB with rule to set items

The next method requires a bit more work, but allows fine settings, and any number of actions to happen as part of your scene. Simply create a Scene switch item:

Switch Scene_Wakeup "Wake Up" (LightingScenes) [ "Switchable" ]

The LightingScenes group is not required, but you can add the whole group to your main sitemap, for example, and make all scenes available from that screen. The “Switchable” tag allows you to use the switch in a Google Home routine to select the scene.

You’ll also need a rule to execute when the scene is selected:

rule "Lighting Scene Wakeup"
when
	Item Scene_Wakeup received command ON
then
	Light_FF_Kitchen_Sink.sendCommand(25)
	FF_Kitchen_Island.sendCommand(25)	
	Light_SF_Landing_Lamp.sendCommand(50)

    Scene_Wakeup.postUpdate(OFF)
end

The rule executes when the Scene_Wakeup switch receives an ON command (this can be either via voice to Google Home, or from the UI by turning on the scene switch). In the rule body, I send commands to several lights around the house (notice I’m using dimmer values, something that can’t be done with Method 1), and then turn the Scene switch item OFF again (so it acts as a momentary pushbutton in the UI).

This method allows you to execute any number of actions when the scene is enabled, even those that aren’t currently natively available via Google Home (HVAC, audio control, etc…). But, if you need to change any setting (brightness level, color, etc.), you need to go back into the code and change the rule. If you think this could be a hassle over the long run, go on to method 3.

Method 3 - Full customization with setpoint storage

The third method is the most complex, but allows full dynamic customization of the scene via voice/openHAB UI, and stores the settings to be used for next time the scene is selected!

For this, you’ll need a complete duplicate set of items (basically, a storage item for every item you’re using in the scene). We’ll use rules to copy the setpoints to/from the storage items.

First, we need to define the additional items:

Group gSceneConfig_Evening "Evening Scene Config" (LightingScenes)
Switch Scene_Evening_Store "Evening Scene Store" (gSceneConfig_Evening) ["Switchable"]
Switch Scene_Evening_Kitchen_Strip_Power "Kitchen Strip Power" (gSceneConfig_Evening)
Color Scene_Evening_Kitchen_Strip_Color "Kitchen Strip Color [%d %%]" (gSceneConfig_Evening)
Dimmer Scene_Evening_Light_FF_Kitchen_Recessed "Kitchen Recessed Lights Level [%d %%]" (gSceneConfig_Evening)
Dimmer Scene_Evening_Light_FF_Kitchen_Sink "Kitchen Sink Light Level [%d %%]" (gSceneConfig_Evening)

The gSceneConfig_Evening group allows me to keep the setpoints in one group within the sitemap (and since it’s a part of the LightingScenes group, it’ll show up as a menu option in my LightingScenes selection menu). The “Scene_Evening_Store” switch is the only thing tagged for Google Assistant. I’ve prefixed every storage item with its Scene identifier, so it’s obvious these are the storage items and not the light/color values for the actual things.

Now, we need a rule to copy our setpoints from the storage values to the actual thing values when this scene is executed:

rule "Lighting Scene Evening"
when
	Item Scene_Evening received command ON
then
	EveningLights.sendCommand(ON)
	LEDStrip_Group2_Power.sendCommand(Scene_Evening_Kitchen_Strip_Power.state as OnOffType)
	LEDStrip_Group2_Color.sendCommand(Scene_Evening_Kitchen_Strip_Color.state as HSBType)
	FF_Kitchen_Recessed.sendCommand(Scene_Evening_Light_FF_Kitchen_Recessed.state as DecimalType)
	Light_FF_Kitchen_Sink.sendCommand(Scene_Evening_Light_FF_Kitchen_Sink.state as DecimalType)

    Scene_Evening.postUpdate(OFF)
end

You’ll notice that I’m no longer setting hardcoded values for each item. Instead, I’m copying the current state of the setpoint item and setting the actual thing value to its state.

Now, if I make changes to the lights, colors, etc, that I want to store/use the next time this scene is selected, we just need a rule to copy the current thing values into the associated storage items. This rule will fire when the “Scene_Evening_Store” switch is selected:

rule "Lighting Scene Evening Config Store"
when
	Item Scene_Evening_Store received command ON
then
	Scene_Evening_Kitchen_Strip_Power.sendCommand(LEDStrip_Group2_Power.state as OnOffType)
	Scene_Evening_Kitchen_Strip_Color.sendCommand(LEDStrip_Group2_Color.state as HSBType)
	Scene_Evening_Light_FF_Kitchen_Recessed.sendCommand(FF_Kitchen_Recessed.state as DecimalType)
	Scene_Evening_Light_FF_Kitchen_Sink.sendCommand(Light_FF_Kitchen_Sink.state as DecimalType)

    Scene_Evening_Store.postUpdate(OFF)
end

That’s it! This scene is now fully customizable!

Keep in mind, the storage value items need to be added to your persistence, if you want to maintain the scene settings through a power cycle.

Method 3.5 - Generic scene rule (based on @rlkoshak 's suggestions below)

This is a variation of Method 3 above, but uses a generic rule to execute each scene. First, the .items definition changes to group each Scene storage item (just add new “Scene_foo” groups and items to create your own scene)

//Put the Scene Groups in Scene_Items
Group Scene_Items
//Put all the Items that hold the state for a scene in Scene_States
Group Scene_States

/* Scene Proxy Switches (accessible from UI/Google Home)*/
/* Step 1 - Add new Scene switch here */
Switch Scene_Evening "Evening Scene" (LightingScenes) [ "Switchable" ]
Switch Scene_Night "Night Scene" (LightingScenes) [ "Switchable" ]

//Groups to hold all items conrolled by this scene
/* Step 2 - Add new group for scene items */
Group Scene_Evening_Items (Scene_Items)
Group Scene_Night_Items (Scene_Items)

/* Scene Config Proxy Switches (accessible from UI/Google Home)*/
/* Step 3 - Add new proxy switch for storing current state of items into scene state items */
Switch Scene_Evening_Store "Evening Scene Store" (gSceneConfig_Evening) [ "Switchable" ]
Switch Scene_Night_Store "Night Scene Store" (gSceneConfig_Night) [ "Switchable" ]

//Evening Scene Configuration Settings
Group gSceneConfig_Evening "Evening Scene Config" (LightingScenes)
Switch Scene_Evening_LEDStrip_Kitchen_Cabinet_Power "Kitchen Cabinet Power" (gSceneConfig_Evening,Scene_States)
Color Scene_Evening_LEDStrip_Kitchen_Cabinet_Color "Kitchen Cabinet Color [%d %%]" (gSceneConfig_Evening,Scene_States)
Dimmer Scene_Evening_Light_FF_Kitchen_Recessed "Kitchen Recessed Lights Level [%d %%]" (gSceneConfig_Evening,Scene_States)

//Night Scene Configuration Settings
Group gSceneConfig_Night "Night Scene Config" (LightingScenes)
Switch Scene_Night_LEDStrip_Kitchen_Cabinet_Power "Kitchen Cabinet Power" (gSceneConfig_Night,Scene_States)
Color Scene_Night_LEDStrip_Kitchen_Cabinet_Color "Kitchen Cabinet Color [%d %%]" (gSceneConfig_Night,Scene_States)
Dimmer Scene_Night_Light_FF_Kitchen_Recessed "Kitchen Recessed Lights Level [%d %%]" (gSceneConfig_Night,Scene_States)

/* Step 4 - Add set of state items corresponding to items that are to be controlled (ensure anything past Scene_xxx_ matches the actual item name)
/* Step 5 - Add Scene_xxxx_Items as a group identifier to the items you want to control with the scene

Then, you just need a .rules file with the generic “set” rule, and individual “store” rules for each scene:

/* Step 6 - Add "or Item Scene_xxx received command ON" below the last item in the when clause below */

rule "Lighting Scene"
when
   
    //Use this block if you're on OpenHAB 2.2 or below

    /*Item Scene_Evening received command ON or
    Item Scene_Night received command ON*/

    Member of LightingScenes received command ON //Use this line if you're on OpenHAB 2.3 or later

then
    // Get the Group of Items that are controlled during this scene
    val items = Scene_Items.members.findFirst[ grp | grp.name == triggeringItem.name+"_Items" ] as GroupItem

    // Loop through all the Items controlled by this scene
    items.members.forEach[ GenericItem i |

        //logInfo("Lights", "Lighting Rule getting " + triggeringItem.name+"_"+i.name + " state")

        // Get the state for this Item and Scene
 
        val sceneState = Scene_States.members.findFirst[ GenericItem st | st.name == triggeringItem.name+"_"+i.name ]

        //logInfo("Lights", triggeringItem.name+"_"+i.name + " state: " + sceneState.state)
        //logInfo("Lights", "Item to change: " + i.name)

        // sendCommand the Scene state
        if(sceneState !== null)
        {i.sendCommand(sceneState.state.toString)}
    ]

    triggeringItem.sendCommand(OFF)
end

rule "Lighting Scene Evening Config Store"
when
	Item Scene_Evening_Store received command ON
then
	Scene_Evening_LEDStrip_Kitchen_Cabinet_Power.sendCommand(LEDStrip_Kitchen_Cabinet_Power.state as OnOffType)
	Scene_Evening_LEDStrip_Kitchen_Cabinet_Color.sendCommand(LEDStrip_Kitchen_Cabinet_Color.state as HSBType)
	Scene_Evening_Light_FF_Kitchen_Recessed.sendCommand(Light_FF_Kitchen_Recessed.state as DecimalType)

    Scene_Evening_Store.postUpdate(OFF)
end

rule "Lighting Scene Night Config Store"
when
	Item Scene_Night_Store received command ON
then
	Scene_Night_LEDStrip_Kitchen_Cabinet_Power.sendCommand(LEDStrip_Kitchen_Cabinet_Power.state as OnOffType)
	Scene_Night_LEDStrip_Kitchen_Cabinet_Color.sendCommand(LEDStrip_Kitchen_Cabinet_Color.state as HSBType)
	Scene_Night_Light_FF_Kitchen_Recessed.sendCommand(Light_FF_Kitchen_Recessed.state as DecimalType)

    Scene_Night_Store.postUpdate(OFF)
end

/* Step 7 - Add handler rule that will fire whenever Scene_XXX_Store receives ON command (add sendCommand statement for each item to copy the current item into the state item)

It should be possible to make the store rules generic, as well - but I couldn’t find an easy way to group the item/state values for each scene.

To add items to the scene, or add new scenes, follow the commented steps in the code above.

Conclusion

I hope this is useful for some of you - I’ve been using scenes in my setup for a while, and they definitely extend the functionality and improve the SAF (Spousal Acceptance Factor) of my home automation system :slight_smile:

Let me know if you have any questions or suggestions below!

-B.K.


Hue Binding: Groups and Scenes
A simple scene management: finally a good use of scripts
Creating a Scene
Official Google Assistant Integration for openHAB
Home Automation Switch Plate (HASP) - DIY touch controller
Anyone up for a challenge? Nuuubeee here
Official Google Assistant Integration for openHAB
Help..."Cannot reference the field 'OFF' before it is defined"
Changing gatway to openHAB - Couple of questions before i start
(Rich Koshak) #2

Great tutorial. Thanks for posting. The only differential I have is to add a title to you Method 3 section like you have for the other two.


(B K) #3

Thank you, Rich! You caught me, I was just fixing that :smiley:


(Rich Koshak) #4

It occurred to me that you could make the scene Rule generic using Design Pattern: Associated Items.

It is a little complex but I’ve implemented stuff like this before so know it will work:

  • create your proxy items as you have
  • also create a Group for each scene and add all the Items that are controlled by scene to that Group
  • create another Group to hold the Items that store the states for those controlled Items
  • put those Groups in a parent Group
  • all the Items and Groups are named such that we can generate their names based on another Items’ name, in this case the Groups are named such that we can generate their name from the Proxy Item and the scene value Items are named such that we can generate their name from the Proxy Item and the Item being controlled
// Put the Scene Groups in Scene_Items
Group Scenes_Items
// Put all the Items that hold the state for a scene in Scene_States
Group Scenes_States

Switch Evening // Proxy Item
Group Evening_Items (Scene_Items) // Group to hold the Items controlled in these scene

Switch Morning
Group Morning_Items (Scene_Items)

...

Switch LEDStrip_Group2_Power (Evening_Items,Morning_Items) ...
Switch Evening_LEDStrip_Group2_Power (Scene_States)
Switch Morning_LEDStrip_Group2_Power (Scene_States)
...

Color LEDStrip_Group2_Color (Evening_Items,Morning_Items)...
Color Evening_LEDStrip_Group2_Color (Scene_States)
Color Morning_LEDStrip_Group2_Color (Scene_States)

...
rule "Lighting Scene"
when
    Item Evening received command ON or
    Item Morning received command ON or
    ...
then
    // Get the Group if Items that are controlled during this scene
    val items = Scene_Items.members.findFirst[ grp | grp.name == triggeringItem.name+"_Items" ] as GroupItem

    // Loop through all the Items controlled by this scene
    items.members.forEach[ GenericItem i |

        // Get the state for this Item and Scene
        val sceneState = Scene_States.members.findFirst[ GenericItem st | st.name == triggeringItem.name+"_"+i.name ]

        // sendCommand the Scene state
        i.sendCommand(sceneState.state)
    ]
end

Everything is controlled by Group membership.

To add a scene:

  • add proxy Item
  • add trigger to the rule above
  • add a Group for the scene named the same as the proxy item with “_Items” appended to the name
  • add the Items controlled by the scene to the Group
  • add new Items named the same as the proxy item + “_” + Item name to hold the value that the device should be set to during this state and add these Items to Scene_States

To add/remove Items to an existing scene simply add/remove them from the Items Group.

You never have to touch the rules beyond adding the trigger (see below) which is nice and it saves having a lot of rules for each and every scene.

And once 2.3 is released (or for those on a recent snapshot) you can add all the scene proxy items to a Group and change the trigger to

Member of SceneProxies received command ON

and you won’t even have to add/remove the Rule trigger in when adding/removing a new scene.

On reflection, you could probably eliminate Scene_Items and just put everything into Scene_States but keeping the Groups separate from the new state Items makes the code a little clearer I think.

I just typed in the above, There is almost certainly some typos. Also, you will want to add some error checking and logging to use it in production.

Edit: It occurred to me after watching the video that you could also dynamicaly add/remove Items to a scene Group. There are ways to change group membership from within rules, but I don’t know how easy it is to persist the membership across OH restarts. You may need to store the names of the members of the Group to a String Item that is persisted and have a System started rule restore the membership settings. I’ll leave that as an exercise to the student. :slight_smile:


(B K) #5

Wow, RIch - this is some PhD level rule-ology :smiley:

I was thinking about using your group design patter for this (I hadn’t converted all my scenes to method 3, yet). I’ll definitely try that and update the main post with the generic rule code, thanks!


(B K) #6

Main post updated (added Method 3.5) - with the generic rule implementation you suggested, @rlkoshak . It works well, I just made a few minor changes (kept “Scene_” in front of all the items, for easier persistence definition (all “Scene_” items can be persisted by one statement).

I thought about making the “Store” rule set also use a generic rule, but that’s when things got a bit too confusing (the only way I could think of doing it would be to use the same idea of grouped items, only reverse the Scene_States and Scene_Items groups in the rule code. But, all the extra groups would get confusing quickly. It’s not too bad to just have one explicit rule for each scene, to store the item states.


(Rich Koshak) #7

I suspect you are misinterpreting the .persist file syntax. Scene_* means all members of the Scene_ group, not all Items that start with Scene_. Keeping the names with Scene_ in front will not help you with the .persist file.

The store side would be a lot more complicated for sure. I would do something like the following.

  • set the rule to process the voice command
  • parsed the command to determine the scene being saved
  • pull the same Scene_Items group you already have defined (e.g Evening_Items)
  • loop through the members of that Group
  • for each member use the Associated Items DP naming convention to grab the associated adjustment item and transfer the state to the scene item. Since everything has a unique name, you could do this all with just one Group.

(B K) #8

I suspect you’re right - bah, I know you are :smiley:

I was thinking of the rrd4j persistence config where you just list the items with wildcards (e.g. Light*…). I didn’t realize (until I just read) that rrd4j isn’t useful for Color items - so I’m moving to the mapdb persistence, now…


(B K) #9

On second thought - I may not be so wrong after all @rlkoshak - just switched to mapdb persistence, and used the following in my .persist file:

Items {
	* : strategy = everyChange, restoreOnStartup
	
	Light*,Scene*,LEDStrip* : strategy = everyMinute, restoreOnStartup

}

It appears to be working well, maintaining states for all lights, Scene_ storage items and now, also the color items.


(Rich Koshak) #10

It’s working because of the first line:

  • : strategy …

Which applies to all Items.

The second line does nothing because Scene* et Al means every member of the Scene group, not every Item whose name starts with Scene.

https://docs.openhab.org/configuration/persistence.html#items

<groupName>* - all members of this group will be persisted, but not the group itself.

The star is not a wild card in .persist files.


(B K) #11

You know, Rich - if everyone (including me) just RTFM’d, this forum would be a very boring/empty place :slight_smile:

Of course you’re right - I need to go relook at my persistence strategies so I’m not persisting every item in my system…


(Stefan Haupt) #12

Offtopic question, you wrote

how do you switch via voice? I for example use IFTTT and the REST web services to trigger the switch via voice. Is there a better way?

Stefan


(B K) #13

That’s actually a very much on-topic question :slight_smile: - I’m using the Google Home action to activate the proxy switch by voice. It’s very easy to set up, you just need to tag the switch with a Lighting tag and connect Google Home to your myopenhab cloud(you can also watch my video link posted in the introduction of the post above) and it’s much quicker than ifttt.


(Stefan Haupt) #14

thanks man! I didn’t know this was meanwhile available :wink: Do you know if it supports German language as well? Not sure if that even matters.


(B K) #15

English, German, French and Japanese, with more languages coming soon :slight_smile:


(Stefan Haupt) #16

:frowning:

even routines aren’t available out of the box in Google. We are always 6-12 months behind


(B K) #17

Ah but routines are just one of the methods I listed above- you don’t need them! Just follow my how to video for the action (make a switch for the scene - for example “Night Scene” - and configure it with the “Lighting” tag,) Connect it to Google Home and follow “Method 2” or “Method 3” in this post, to make changes to all your lights when the switch is turned on by Google.

Routines are just a way to make multiple things happen from within Google, but they limit what you can do to each item…


(Stefan Haupt) #18

understood. just wanted to whine about google not supporting German customers as fast as I wished :wink:


(Peppe) #19

thank you Bartus, I have been able to implement the method 3 straight forward!
I have a question, it seems to me that every time I must reboot the openhab server, I have to restore from scratch the wanted scene since there is no persistence of the scene status.
Did you find any smart solution to workaround?
thank you


(B K) #20

Great! I’m glad it worked for you :slight_smile:

To store the values between restarts, you’ll need to set up persistence. My preferred service is mapdb (because it can store color values, which the default service, rrd4j, cannot). See my post #9 above - I’m having no issues with scene item states restoring after startup BUT I am using the standard persistence strategy (i.e. I’m storing values for all my items in the system). I haven’t had issues with this, but if I find the time, I’ll probably put all my scene storage items in a single group, and persist that group between restarts.

Also, check out this great blog article on persistence in case you haven’t set one up already. It explains persistence topics very well!