Let there be (dim) light!

There’s no fun in having sensors without being able to manipulate surrounding environment using their input. Like I explained in first post, my main motivation setting up home automation was to control lighting, preferably without minimal human intervention. Main illumination rules should be as follows:

    • Motion sensors should turn on lights automatically after person has entered a room. Lights should also be turned off after no presence has been detected after a while (5-10 minutes perhaps)
    • When on, lights should adjust to local time by dimming and if possible, changing color temperature. From early morning to 6 pm lights should be set to bright and neutral temperature (6000-7000 K), then declining towards the evening (around 2500-3000 K) and finally drop to 2000 K 1-2 hours before bedtime
    • If alarm is set to go off on mornings, bedroom lighting should be turned on automatically 30 minutes before, starting from very dim and slowly reaching full brightness wee bit before it’s time to get up.

Options, options…

I considered wireless dimmer modules (either off-the-shelf or even DIY Arduino hacks), but quickly scrapped the idea, since color temperature could not be then adjusted. Belkin has a family of WeMo┬« home automation appliances (using 2.4 GHzZigbee as wireless protocol), including their Smart LED Bulbs. Unfortunately their color temperature is fixed. There are however 3rd party bulbs available from OSRAM that are combatible with Wemo and have tunable color temperature. Osram manufactures also their own Zigbee compatible Lightway gateway. And finally there’s Philips Hue family of lights, that are both color temperature and color adjustable. Hue is also using Zigbee protocol and is the oldest of these three, having been around almost 2 years now already.

Since all three use Zigbee to communicate between hubs and light bulbs, I would assume there’s some interoperability between these products. It seems at least Osram Lightify bulbs can be paired with Philips Hue hub, but I didn’t found anyone mentioning compatibility between Belkin and Hue bulbs. However in the end it is the hub that the rest of the home automation framework is communicating with and not directly with the bulbs, so procurement was done mainly by comparing the existing support for the hubs in Openhab and other home automation systems. In the end I chose Philips Hue since Openhab supports it directly, its protocol is documented and there’s plethora of language bindings available.

philips-hue-blubs-and-station
There were also many success stories around using Philips Hue with DIY installations that encouraged me to shell out the 200 euros for the starter pack with the hub and 3 bulbs. I know, it’s a rip-off but then again, I have so many times found out that cheaping out on these things often cause major headaches later.

Philips Hue

philips hue app
There are many features on their mobile application (available for iOS and Android. Unofficial app also for Windows phones available). Not only can you control manually the lights with the application, but you can also set dimming functions based on timers and alarms which are saved into the hub, so the application doesn’t need to be left on. Then there are other lots of 3rd party apps available (Disco lights etc.) but those just feel utterly gimmicky. And besides, after one has been playing with a new toy such as this for awhile and the initial charm has worn off, who really wants to control his/her lights from a mobile phone?? Anyway, I won’t go into too much details with the features of Philips Hue itself since there are already many nicely done reviews around, such as this by Lester Chan.

Now, coming back to the initial objectives, using the timer feature I could fulfill some of the requirements above, but I still wanted to gather all the automation rules into one single hub (Openhab) to avoid conflicts later. In the end, Philips hub was converted into a dumb router. One last thing I did with the Hue application was to check the IP address of the hub after which I went on to configure Openhab.

Philips Hue hub, emitting exactly the light that would keep me awake at night should I spent too much time glancing it. Fortunately it can be put somewhere out of sight.

Philips Hue hub, emitting exactly the light that would keep me awake at night should I spent too much time glancing it. Fortunately it can be tossed somewhere out of sight.

Openhab coupling

Pairing Philips Hue hub with Openhab was quite straightforward (detailed instructions can be found here), but setting the lightning rules were little bit trickier. I’m not really a big fan of the XTend language that Openhab uses for its scripting, but that’s a topic for another post..

First one needs to define the light bulb items (e.g. in default.items)

// Simple ON/OFF toggles
Switch Kitchen_Light_Toggle    "left bulb"   (Switching) {hue="1"}
Switch Bathroom_Light_Toggle   "center bulb" (Switching) {hue="2"}
Switch Bedroom_Light_Toggle    "right bulb"  (Switching) {hue="3"}

// For setting color values
Color Kitchen_Light_Color    "left bulb"   (Colorize)  {hue="1"}
Color Bathroom_Light_Color    "center bulb" (Colorize)  {hue="2"}
Color Bedroom_Light_Color     "right bulb"  (Colorize)  {hue="3"}

// For setting dimmer values
Dimmer Kitchen_Light_Dimm     "left bulb"   (WhiteDimmer)   {hue="1;brightness;30"}
Dimmer Bathroom_Light_Dimm    "center bulb" (WhiteDimmer)   {hue="2;brightness;30"}
Dimmer Bedroom_Light_Dimm     "right bulb"  (WhiteDimmer)   {hue="3;brightness;30"}

// For setting color temperature values. Note that these accept values (0-100), where 0 is the coldest and 100 is warmest temperature
Dimmer Kitchen_Light_CT_Dimm      "left bulb"   (CTDimmer)  {hue="1;colorTemperature;30"}
Dimmer Bathroom_Light_CT_Dimm     "center bulb" (CTDimmer)  {hue="2;colorTemperature;30"}
Dimmer Bedroom_Light_CT_Dimm      "right bulb"  (CTDimmer)  {hue="3;colorTemperature;30"}

Lighting rules

Then we define a global color temperature setting (also in default.items) as well as target temperature for slow transition:

Number Color_Temperature "Light temperature [%.0f]"
Number Target_Color_Temperature

Next we define a function (I use light.rules files for this and the following rules) that gets called every time a light temperature is updated. It then controls each light bulb accordingly. Note that if a light is turned off, this setting is not propagated to the bulb itself so we must explicitly set the temperature each time when a light is turned on.

rule "Update color temperatures"
when 
    Item Color_Temperature received update  
then
    logInfo("Sensors","new color temperature: " + Color_Temperature.state)
    var Integer temp = Color_Temperature.state
    sendCommand(Kitchen_Light_CT_Dimm, temp)
    sendCommand(Bathroom_Light_CT_Dimm, temp)
    sendCommand(Bedroom_Light_CT_Dimm, temp) 
end

I also tried to address each dimmer in a group (set earlier in the items definition) like this…

//  CTDimmer?.members.forEach[dimmer|
//      Dimmer d = dimmer   // <-- Fails right here..
//      sendCommand(dimmer, Color_Temperature.state )
//      ]

... but it seems that Openhab doesn't store group items as real objects but as some kind of bastard string representation instead.. So, each light has to be addressed individually, which makes maintaining code cumbersome especially when one has many devices of same type in the setup.

Another annoyance has been with default item values. I haven't found a way to initialize values in items file, and when I modify the file and it gets reloaded, values are reset and left uninitialized. This can break many functions and adds overhead since there has to be more checkpoints all over the code to make sure no uninitialized value is addressed. I even wrote another rule to try to circumvent this:

rule "Startup"
    when 
        System started
    then
    if ( (Color_Temperature.state == Undefined) || (Color_Temperature.state == Uninitialized) )
    {
        postUpdate(Color_Temperature, 50)  // default value
    }
    end

, but this is called only during startup or when the rules file is reloaded, but NOT when items file is touched. This can be circumvented by saving first the .items file and then the .rules file. It is of course not a problem when running a stable system but when testing and building your rules, this can become quite a pain in the ass.

To implement a transition from current light temperature to target temperature slowly in 10 minutes, we implement a rule such as this:

rule "Temperature transition"
when
    Item Target_Color_Temperature received update
then
    var Number steps = 0
    logInfo("temp transition","temp:" + Color_Temperature.state + " -> " + Target_Color_Temperature.state )
    var Number delta = (Target_Color_Temperature.state as DecimalType).floatValue - (Color_Temperature.state as DecimalType).floatValue
    delta = delta / 60
    logInfo("temp transition","delta:" + delta)
    while(steps < 60) { 
            postUpdate(Color_Temperature, (Color_Temperature.state as DecimalType).floatValue + delta )
        steps = steps + 1 
            Thread::sleep(10000)
     }
end

Finally, we can add rules to start the transition at certain times (in this example at 8 pm and 7 am)

rule "Dusk"  
when
    Time cron "0 00 20 ? * MON-SUN "
then
    logInfo("Light rules","It's getting darker...")
    postUpdate(Target_Color_Temperature, 100)
end

rule "Dawn"
when 
    Time cron "0 00 07 ? * MON-SUN "  
then
    logInfo("Light rules","It's getting brighter...")
    postUpdate(Target_Color_Temperature, 10) 
end