Setting light themes in rules

Setting up scenes like this is one of the weaker areas of OH unfortunately. As with any programming environment, all things are possible, but not all things are easy.

I’m glad you found Groups because that is one of the better ways to manage this sort of setup in Rules.

A lot of people will use a single String or Number Item and a selector to set the Theme from your sitemap or HABPanel using a selection. This really isn’t functionally any different from what you are doing and I would call it a personal preference choice.

You might find some inspiration from Design Pattern: Associated Items, Design Pattern: Encoding and Accessing Values in Rules, and Design Pattern: Working with Groups in Rules. For example, you can store the state of the lights in Items with associated item names. This would add flexibility for you to adjust the settings for each light individually for each scene from your HABPanel and let you reduce your rules down to one generic rule. However it comes at the cost of greatly increasing the complexity of your Items.

For a simple example of what I mean, here are my lighting rules. I control my lights based on Design Pattern: Time Of Day. Each ToD (equivalent to your themes) has two Groups, an ON Group and an OFF Group. All members of the ON Group get turned ON at the start of that ToD and all members of the OFF Group get turned OFF at the start of that ToD.

Group:Switch:OR(ON,OFF) gLights_ALL "All Lights"
	<light>

Group:Switch:OR(ON, OFF) gLights_ON
Group:Switch:OR(ON, OFF) gLights_OFF
Group:Switch:OR(ON, OFF) gLights_ON_MORNING    (gLights_ON)
Group:Switch:OR(ON, OFF) gLights_OFF_MORNING   (gLights_OFF)
Group:Switch:OR(ON, OFF) gLights_ON_DAY        (gLights_ON)
Group:Switch:OR(ON, OFF) gLights_OFF_DAY       (gLights_OFF)
Group:Switch:OR(ON, OFF) gLights_ON_AFTERNOON  (gLights_ON)
Group:Switch:OR(ON, OFF) gLights_OFF_AFTERNOON (gLights_OFF)
Group:Switch:OR(ON, OFF) gLights_ON_EVENING    (gLights_ON)
Group:Switch:OR(ON, OFF) gLights_OFF_EVENING   (gLights_OFF)
Group:Switch:OR(ON, OFF) gLights_ON_NIGHT      (gLights_ON)
Group:Switch:OR(ON, OFF) gLights_OFF_NIGHT     (gLights_OFF)
Group:Switch:OR(ON, OFF) gLights_ON_BED        (gLights_ON)
Group:Switch:OR(ON, OFF) gLights_OFF_BED       (gLights_OFF)
Group:Switch:OR(ON, OFF) gLights_ON_WEATHER    
Group:Switch:OR(ON, OFF) gLights_WEATHER_OVERRIDE

Switch aFrontLamp "Front Room Lamp" 
  (gLights_ALL, gLights_ON_MORNING, gLights_OFF_DAY, gLights_ON_AFTERNOON, gLights_ON_EVENING, gLights_OFF_NIGHT, gLights_OFF_BED, gLights_ON_WEATHER)
  { channel="zwave:device:dongle:node26:switch_binary" }
  
Switch aFamilyLamp "Family Room Lamp"
  (gLights_ALL, gLights_ON_MORNING, gLights_OFF_DAY, gLights_ON_AFTERNOON, gLights_ON_EVENING, gLights_OFF_NIGHT, gLights_OFF_BED, gLights_ON_WEATHER)
  { channel="zwave:device:dongle:node25:switch_binary" }
    
Switch aPorchLight "Front Porch"
  (gLights_ALL, gLights_OFF_MORNING, gLights_OFF_DAY, gLights_ON_AFTERNOON, gLights_ON_EVENING, gLights_OFF_NIGHT, gLights_OFF_BED)
  { channel="zwave:device:dongle:node27:switch_binary" }
val logName = "lights"

rule "Set lights based on Time of Day"
when
  Item vTimeOfDay changed
then
  // reset overrides
  gLights_WEATHER_OVERRIDE.postUpdate(OFF)

  val offGroupName = "gLights_OFF_"+vTimeOfDay.state.toString
  val onGroupName = "gLights_ON_"+vTimeOfDay.state.toString

  logInfo(logName, "Turning off lights in " + offGroupName)
  val GroupItem offItems = gLights_OFF.members.filter[g|g.name == offGroupName].head as GroupItem
      offItems.members.filter[l|l.state != OFF].forEach[l | l.sendCommand(OFF)
  ]

  logInfo(logName, "Turning on lights for " + onGroupName)
  val GroupItem onItems = gLights_ON.members.filter[g|g.name == onGroupName].head as GroupItem
      onItems.members.filter[l|l.state != ON].forEach[l | l.sendCommand(ON)
  ]
  
end

This will get you halfway there. The next step would be to add Items for each theme and each light. Something like:

Group:Color ThemeValues
Group:Color LivingRoomLights

Color LivingRoom_1_1_Colour (LivingRoomLights) {channel="hue:0210:myhub:9:color"}
Color LivingRoom_1_1_Colour_WatchTV (ThemeValues)
Color LivingRoom_1_1_Colour_LivingRoom_Bright (ThemeValues)
...

Then your Rules would look something like:

// If using persistence with restoreOnStartup you can remove this rule after all your Items have a value
rule "Populate the initial value for the theme items"
when
    System started
then
    LivingRoom_1_1_Colour_WatchTV.postUpdate("82,55,69")
    LivingRoom_1_2_Colour_LivingRoom_Bright.postUpdate("82,55,100")
    ...
end

rule "Set Watch TV"
when
    Item Theme_WatchTV changed to ON
then
    Theme_LivingRoom_Bright.sendCommand("OFF")
    Theme_LivingRoom_Relax.sendCommand("OFF")
    Theme_LivingRoom_Nightlife.sendCommand("OFF")

    LivingRoomLights.members.forEach[light | 
        light.sendCommand(ThemeValues.members.findFirst[value | value.name == light.name+"_WatchTV"].state)
    ]
end

So, as you can see, vastly simplified Rule but a proliferation of Items. Personally, I’d rather move complexity to my Items than my Rules but that is a personal preference.

1 Like