Philips Hue Lights

From Domoticz
Jump to navigation Jump to search

This page talks about the PhilipsHue family of lights. It focusses on how to connect to them. For a full list of supported Hue devices, please have a look at the hardware page on this wiki.

general notes on hardware


As long as you can connect the light to the bridge, it will work.
The bridge supports up to 50 connected lights.
Both the old and the new 'Homekit ready' bridge are supported.

Remarks:
Because of limitations in the Hue API, Domoticz cannot 'see' the Hue Tap or the Hue dimmer switch.
LivingColors remote controls do not use the bridge but control the lights directly,
so Domoticz cannot 'see' these remotes.
Of course you can still use the Tap and LivingColors remotes, as the light status is polled by Domoticz.
External status changes to the Hue lights (via app, Tap, etc) will be reflected in Domoticz within 10 seconds.

Installing the Hue Hardware Device

Native Support

Setup
Go to the Setup / Hardware page and select Philips Hue Bridge as a hardware type.

Enter:
- the IP Address of the Philips Hue bridge (you can also find this in your network router),
- the Port of the Philips Hue bridge (normally 80, unless you share one over the internet)

First time:
Leave the username empty, and press the LINK button on the Philips Hue bridge, and press the 'Register' button.
If everything went correctly, a new username is filled in, and you can press the ADD button

Already registered before:
If you know the username, enter it, and press ADD.
If you forgot the username, then use the above procedure

Domoticz will then automatically add all your lamps to the device page (unused), where they can be selected named and transferred to the Switches page for use.

Adding additional lights:
Always check 'Allow new hardware devices' in Settings.
If new lights do not show up automatically, then go to Hardware and disable the Hue hardware.
(uncheck enable and click update). After a minute enable the hardware again and all new device will be on the device page (unused).

Groups:
You can create groups with a third party application like HueMote.
For example you could create a group 'Livingroom' with all your lights in that room.
Domoticz will detect all groups from the hue bridge, and add them as switches in the system
After this, it is very easy to control all colors/brightness/on/off of all lights in this group.
The behavior is the same as a normal switch.

Scenes:
You can create scenes with a third party application like Hue Pro that is able to store the scene on the bridge.
For example you could create a scene 'Romantic' with a nice color and with all the lights you want in this scene.
Domoticz will detect all scenes from the hue bridge, and add them as push-on switches in the system
After this, it is very easy to activate the scene or use the scene in timers.




Update Philips Hue Status

Although the native hardware works. It can lose the state of the lamp :-( This time based script wil use the HUE api to check the current status of your lights as reported by the HUE bridge the script starts with light #1 and checks if the status reported by your bridge corresponds with the status in Domoticz if HUE state is not equal to Domoticz state then the script will correct the status in Domoticz

This script is documented here[1]

-- you'll need to install socket library & dkjson, more info can be found here:
-- http://www.domoticz.com/wiki/Upload_energy_data_to_PVoutput#Install_socket_library
-- http://dkolf.de/src/dkjson-lua.fsl/home
-- both need to end up in /usr/local/lib/lua/5.2

-- this time based script wil use the HUE api to check the current status of your lights as reported by the HUE bridge (assuming hat unreachable lights are off when switched by wall switch)
-- the script starts with light #1 and checks if the status reported by your bridge corresponds with the status in Domoticz
-- if HUE state is not equal to Domoticz state then the script will correct the status in Domoticz
-- the script will keep looping until there are no more lights to check and will then stop
-- in order for the script to work it is important that the names of each light are exactly equal in both your bridge & domoticz
-- I suppose you know the names of the HUE switches in Domoticz, you can check the names in your bridge with the HUE app

-- more info on Philips HUE api and how to get/change your username can be found here: 
-- http://www.developers.meethue.com/documentation/getting-started

-- configure Hue Bridge
local hueBridgeIP = ''
local hueBridgeAPI = ''
 
 
-- do not change beyond this line
-- this part will get the Hue status
function getHueLight(id)
   local http = require('socket.http')
   local ltn12 = require('ltn12')
   local json = require('dkjson')
 
   t = {}
   local url = string.format("http://%s/api/%s/lights/%s", hueBridgeIP, hueBridgeAPI, id)
   b, c, h = http.request{url=url, sink = ltn12.sink.table(t), method='GET'}
   huestring = tostring(table.concat(t))
   local hue, pos, err = json.decode(huestring, 1, nil)
   if (hue.name) then 
      hue_name = (hue.name)
      hue_state = (hue.state.on)
      hue_reachable = (hue.state.reachable)
   else
      stop = true
   end 
   return hue_name, hue_state, hue_reachable, stop
end
 
 
-- now check Hue state & correct Domoticz if needed
commandArray = {}
 
i = 1
repeat
   local hue = getHueLight(i)
   if hue_state == true and otherdevices[hue_name] == 'Off' then
      commandArray[hue_name] = 'On'
      print(string.format("Status %s corrigeren", hue_name))
    elseif hue_state == false and otherdevices[hue_name] ~= 'Off' then
      commandArray[hue_name] = 'Off'
      print(string.format("Status %s corrigeren", hue_name))
    -- assume ligth is off when unreachable
    elseif hue_reachable == false and otherdevices[hue_name] ~= 'Off' then
      commandArray[hue_name] = 'Off'
      print(string.format("Status %s corrigeren (unreachable)", hue_name))
    end
    i = i + 1
until(stop)
 
return commandArray

Update if you remove a broken bulb this script will stop there... not updating the lamps after the broken bulb. Change until(stop) into until(i > 25) where 25 is the highest number of lamps found in your Philips HUE app, this will quick fix it...

Virtual Power & Energy meters

This an expansion of the update script. It add's virtual power and energy meters for HUE. It can be found Here

Remote Dimmer Switch

Another example of an expansion of the update script can be found here. It add some elementary aspects of the remote dimmer switch. So you not only can control your lights with it but also other devices in domoticz.

Controlling Hue Lights with Bash Scripts

There is a a detailed description on how to couple the Hue system with Domoticz using bash scripts, it's available here: Philips Hue Lights into Domoticz and IFTTT functionality

Scenes

Additionally you can create scripts which call scenes you have configured in your bridge. This even allows you to have the exact scenes provided by Philips, for example "Relax" or "Concentrate".

Just add a scene to Domotiz and link its "On Action" and optionally "Off Action" with bash scripts. For example:

The bash script which you could use would be:

On Action (relax_sala_on.sh)

#!/bin/bash
curl --request PUT --data "{\"scene\": \"<scene id>\"}" http://<bridge ip address>/api/<hue api-user>/groups/<group id>/action

Off Action (sala_off.sh)

#!/bin/bash
curl --request PUT --data "{\"on\": false}" http://<bridge ip address>/api/<hue api-user>/groups/<group id>/action

To get the scene id's of the Hue scenes stored on the bridge you can use the following command, or run it with a GET on the [Clip API Debugger] of your Hue hub.

curl http://<bridge ip address>/api/<hue api-user>/scenes

Do not forget to make your scripts executable. For example:

sudo chmod +x sala_off.sh

You can test your API calls using the [Clip API Debugger]:

http://<bridge ip address>/debug/clip.html

You can also learn more details on controlling hue scenes on the [Philips hue API documentation].

If you have multiple scenes you want to call, it may not be very efficient to create individual bash scripts for each of them. In that case you may want to consider using a script that anticipates an argument, in this case the HUE Scene ID, so make a bash script with $1 instead of the scene id:

curl --request PUT --data "{\"scene\": \"$1\"}" http://<bridge ip address>/api/<hue api-user>/groups/<group id>/action

You can call the Scene ID by adding it to the script, for example:

./scene_on <scene_id>

or in Domoticz as the On action of a Switch for example as:

script:///home/pi/domoticz/scripts/scene_on.sh <scene_id>

Simple Christmas Tree Script

I've two Philips Living Whites plugs each controlling one row of lights. I created a group for the lights and two bash scripts. The on action passes a time to turn off the tree lights to the script and sends it to the background (as it may run for many hours):

script:///home/pi/domoticz/scripts/bash/christmas_tree_on.sh 23:58 &
#!/bin/bash
while [ $(date +%H:%M) '<' "$1" ]; 
do
curl --request PUT --data "{\"on\": true}" http://192.168.1.xx/api/xxxx/lights/5/state
curl --request PUT --data "{\"on\": false}" http://192.168.1.xx/api/xxxx/lights/7/state
sleep 2
curl --request PUT --data "{\"on\": false}" http://192.168.1.xx/api/xxxx/lights/5/state
curl --request PUT --data "{\"on\": true}" http://192.168.1.xx/api/xxxx/lights/7/state
sleep 2
echo $(date +%H:%M)
echo $1
done
curl --request PUT --data "{\"on\": false}" http://192.168.1.xx/api/xxxx/lights/5/state
curl --request PUT --data "{\"on\": false}" http://192.168.1.xx/api/xxxx/lights/7/state

The off action script kills the script running in background and makes sure the lights are off:

script:///home/pi/domoticz/scripts/bash/christmas_tree_off.sh
#!/bin/bash
killall christmas_tree_on.sh
curl --request PUT --data "{\"on\": false}" http://192.168.1.xx/api/xxxx/lights/5/state
curl --request PUT --data "{\"on\": false}" http://192.168.1.xx/api/xxxx/lights/7/state

The group is also controlled by timers.

Controlling Hue Lights with Lua Scripts

To change the color of a light when for example a button is pressed then you can use the following device event script

commandArray = {}
if (devicechanged['Hue dimmer switch 2 Button Up'] == 'On') then
  brightness = 80
  iswhite = "false"
  hue = "0" -- red
  idx = otherdevices_idx["Bol Lamp"] -- name lamp
  url = 'http://10.0.0.1:8090/json.htm?type=command&param=setcolbrightnessvalue&idx=' .. idx .. '&hue=' .. hue .. '&brightness=' .. brightness ..'&iswhite=' .. iswhite
  commandArray['OpenURL']= url
end
return commandArray

Where the hue values range from (EDIT HERE) and of course fill in the ip and port of your own domoticz.

Switch Lights On / Off and Changing Colours

This is still a work in progress.

The short script will work with any number of Hue lights, is able to turn the light (dummy switch Hue1) on using colours set on dummy dimmers (rHue1, gHue1, bHue1) in Domoticz and turn the light off. Note colour changes only happen when the light is switched on by its own dummy switch not by the dimmer switches.

(Using 3 dimmers to control the rgb colours is overly complicated, and while I can see Domoticz has controllers for other colours lights I can't see who to create dummy versions, if you can please add details here, thanks.)

---EDIT--- You can now create an RGBW switch from the dummy hardware setup (9 jan 2016) ---EDIT---

Firstly, you need to connect your Domoticz computer to your Philips Hue bridge, follow the instructions on the link from the wiki above, here - Philips Hue Lights into Domoticz and IFTTT functionality

Secondly, you need to install the socket and luacolor libraries on your machine, I have attached gzipped tar files for the Raspberry Pi to this forum post, as there is no packaged versions available. Download the two attached files, placing usrlocalsharelua5p2.tar.gz in directory /usr/local/share/lua/5.2/ and extracting the file with sudo tar -xvf usrlocalsharelua5p2.tar.gz, then put usrlocalliblua5p2.tar.gz in /usr/local/lib/lua/5.2/ and extract all the files with sudo tar -xvf usrlocalliblua5p2.tar.gz.

Thirdly, create a dummy on/off switch Hue1, and three dummy dimmer switches rHue1, gHue2 and bHue3 the dimmer switch must not use X10 protocol as this does not support dimmer switches.

Foruthly, edit the script below, to put the ip address of your Philips Hue bridge and replace newdeveloper with the user you have registered on the Philips Hue bridge:

-- ~/domoticz/scripts/lua/script_device_hue.lua
-- Simple script to turn on and off Philips Hue lights with colour control

-- For each of your Philips Hue lights you need to create a dummy switch named: HueXanythingatall
-- and 3 dummy dimmer switch (not X10) named rHueXanythingatall, gHueXanythingatall, bHueXanythingatall
-- where x is the number of your light, e.g. Hue3Lounge would control Hue light 3, 
--  with rHue3Lounge, gHue3Lounge and bHue3Lounge dummy dimmers controlling the colour.

-- Ensure that you have registered the user with the Philips Hue bridge
-- N.B. one wrongly named Hue dummy switch may stop the script, check log for any issues

commandArray =  {}
base_url = 'http://192.168.89.170/api/newdeveloper/'

tc=next(devicechanged)
v=tostring(tc)
-- Check to see if the device changed is a Hue light
if (v:sub(1,3) == 'Hue') then
   -- Only load libaries if a Hue light
   io = require('io')
   http = require('socket.http')
   ltn12 = require('ltn12')
   colors = require('luacolors')

   function hueit(device, operation)
   -- Sends commands to Philips Hue bridge
   --  device is the device specific url i.e. /lights/1/state
   --  operation is the message body i.e. {"on":true, "sat":255, "bri":255,"hue":10000}
   --    for details see http://www.developers.meethue.com/documentation/getting-started
      local url = base_url .. device
      print(url)
      local req_body = operation
      local headers = {
        ["Content-Type"] = "application/x-www-form-urlencoded";
        ["Content-Length"] = #req_body;
      }
      client, code, headers, status = http.request{url=url, headers=headers, source=ltn12.source.string(req_body), method='PUT'}
      print(status)
      return
   end

   function huecolors(switch)
   -- Reads dummy dimmers from Domoticz with rgb values i.e. rHue1, gHue1, bHue1
   -- Converts the rgb values to x,y for Philips Hue
   -- Return command string ready to be sent to Philips Hue bridge
--      print('r'..switch)
      red = otherdevices_svalues['r'..switch]
      green = otherdevices_svalues['g'..switch]
      blue = otherdevices_svalues['b'..switch]
--      print('rgb = ' .. red ..','.. green ..','.. blue)
      X, Y, Z = colors.sRGBtoXYZ(red, green, blue)
--      print('XYZ = ' .. X ..','.. Y ..','.. Z)
      return ',"xy":[' .. (X / (X + Y + Z)) .. ',' .. (Y / (X + Y + Z)) .. ']'
   end

   print(v..' spotted')
   device = 'lights/' .. v:sub(4,4) .. '/state'
   if(devicechanged[v] =='On') then
      params = '{"on":true' .. huecolors(v) ..'}'
--      print(params)
      hueit(device, params)
   else
      hueit(device, '{"on":false}')
   end
end

return commandArray

Capturing, Storing and Displaying Hue Scenes

Trying to set the colours of lights is rather complicated in the Domoticz web UI as made possible from the script above, however there are a large number of apps which allow Hue lights colours to be set with ease on clever interfaces.

So the idea of these two scripts is to capture the current scene of your Hue lights, store them and then allow the scenes to be recalled in order.

The scripts use the socket library and so need to have the libraries mentioned in the previous section installed to function, plus a Json library, I used the Lua Json library found here - [2] - place the library in /usr/local/share/lua/5.2/.

These scripts use a number of Domoticz variables - create these before running the scripts:

DomoticzURL : http://192.168.1.15:8080
PhilipsHueBaseURL : http://192.168.1.17/api/username/
PhilipsHueMasterSwitch : I have single switch which turns all my Philips Hue lights on / off
PhilipsHueOnCaptureSwitch : A switch which when pressed activates this script
PhilipsHueIncrementSwitch : A switch which when pressed retrieves the next scene in the sequence of stored scenes
NoHue1Scenes : set to 0 to start with, this will increment each time the button is pressed
CurrentHue1Scene : set to 0 to start with, this is the no of the scene currently being used by Hue lights

The capture script creates a series of new Domoticz variables which store the different scenes - Hue1Scene1, Hue1Scene2 ..... - do not create these the script will do the creation of each variable.

-- ~/domoticz/scripts/lua/script_device_hue_scene_capture.lua
-- A script to capture the status of a series of Hue lights
-- The parameters are stored in a self-created Domotic variable
-- Multiple activations of the script results in multiple sets
-- of parameters being stored in a sequence of incremented variables.

-- N.B. one wrongly named Hue dummy switch may stop the script, check log for any issues

-- For background details see http://www.developers.meethue.com/documentation/getting-started

commandArray =  {}
base_url = uservariables['PhilipsHueBaseURL']
master_switch = uservariables['PhilipsHueMasterSwitch']
on_capture_switch = uservariables['PhilipsHueOnCaptureSwitch']
domoticz_url = uservariables['DomoticzURL']

if(devicechanged[on_capture_switch]) then
   -- Only store the pattern if the light is already on
   if(otherdevices[master_switch] == 'On') then
      -- Only load libaries now
      io = require('io')
      http = require('socket.http')
      ltn12 = require('ltn12')
      colors = require('luacolors')
      json = require('json')

      function hueit(device, operation, mode)
      -- Sends commands to Philips Hue bridge and returns JSON
      --     device is the device specific url i.e. /lights/1/state
      --     operation is the message body i.e. {"on":true, "sat":255, "bri":255,"hue":10000}
      --     mode is 'GET', 'PUT' or 'POST'
         local t = {}
         local url = base_url .. device
         local req_body = operation
         print(url)
         print(req_body)
         local headers = {
            ["Content-Type"] = "application/json";
            ["Content-Length"] = #req_body;
          }
          client, code, headers, status = http.request{url=url, headers=headers, source=ltn12.source.string(req_body), sink = ltn12.sink.table(t), method=mode}
         print(status)
         return t
      end

      function processJSON(t)
         print(table.concat(t))
         obj, pos, err = json:decode(table.concat(t),1,nil)
         if err then
            print ("Error:", err)
         else
            for i = 1,3 do
               if i == 1 then
                  stuff = ''
               else
                  stuff = stuff ..'|'
               end
               state=obj.lights[tostring(i)].state
               stuff = stuff .. state.bri ..'|'.. state.hue ..'|'.. state.sat ..'|'.. state.xy[1] ..'|'.. state.xy[2] ..'|'.. state.ct
            end
         end
         print('length of encode '..#stuff)
         noscenes = uservariables["NoHue1Scenes"]
         print('noscenes '..noscenes)
         noscenes = noscenes + 1
         commandArray['Variable:NoHue1Scenes'] = tostring(noscenes)
         t={}
         url = domoticz_url..'/json.htm?type=command&param=saveuservariable&vname=Hue1Scene'..noscenes..'&vtype=2&vvalue='..stuff
         commandArray['OpenURL'] = url
         return
      end

      device = ''
      mode = 'GET'
      params = ''
      t = hueit(device, params, mode)
      processJSON(t)
   end
end

return commandArray

The increment script, retrieves the next stored Philips Hue light scene each time the button is pressed and sends the scene to the Philips Hue lights.

-- ~/domoticz/scripts/lua/script_device_hue_scene_increment.lua
-- A script to use stored status of a series of Hue lights
-- The parameters are retrieved from the self-created Domoticz variables
-- Multiple activations of the script result in a sequence of prestored
-- parameters being used to change the colours of the Hue lamps in
-- sequence.

-- Ensure that you have registered the user with the Philips Hue bridge

-- For background details see http://www.developers.meethue.com/documentation/getting-started

commandArray =  {}
base_url = uservariables['PhilipsHueBaseURL']
master_switch = uservariables['PhilipsHueMasterSwitch']
on_capture_switch = uservariables['PhilipsHueOnCaptureSwitch']
increment_switch = uservariables['PhilipsHueIncrementSwitch']

if(devicechanged[increment_switch]) then
   -- Only increment the pattern if the light is already on
   if(otherdevices[master_switch] == 'On') then
      -- Only load libaries now
      io = require('io')
      http = require('socket.http')
      ltn12 = require('ltn12')
      colors = require('luacolors')
      json = require('json')
   
      function hueit(device, operation, mode)
      -- Sends commands to Philips Hue bridge and returns JSON
      --     device is the device specific url i.e. /lights/1/state
      --     operation is the message body i.e. {"on":true, "sat":255, "bri":255,"hue":10000}
      --     mode is 'GET', 'PUT' or 'POST'
         local t = {}
         local url = base_url .. device
         print(url)
         print(operation)
         local req_body = operation
         local headers = {
            ["Content-Type"] = "application/json";
            ["Content-Length"] = #req_body;
         }
         client, code, headers, status = http.request{url=url, headers=headers, source=ltn12.source.string(req_body), sink = ltn12.sink.table(t), method=mode}
         print(status)
         return t
      end

      function readin(t)
         noscenes = uservariables["NoHue1Scenes"]
         currentscene = uservariables["CurrentHue1Scene"]
         currentscene = currentscene + 1
         if(currentscene>noscenes) then
            currentscene = 1
         end
         commandArray['Variable:CurrentHue1Scene'] = tostring(currentscene)
         stuff = uservariables['Hue1Scene'..currentscene]
         setvalues = {}
         for setvalue in string.gmatch(stuff, "[^|]+") do
            setvalues[#setvalues + 1] = setvalue
         end
         print('No setvalues '..#setvalues / 6)
         for i = 1, #setvalues / 6 do
            j = 6 * (i - 1)
            state = {}
            state.bri = tonumber(setvalues[1+j])
            state.hue = tonumber(setvalues[2+j])
            state.sat = tonumber(setvalues[3+j])
            state.xy = {tonumber(setvalues[4+j]), tonumber(setvalues[5+j])}
            state.ct = tonumber(setvalues[6+j])
            storedjson = json:encode(state)
            print('lights '..i..' '..storedjson)
            device = '/lights/' .. i .. '/state'
            t = hueit(device, storedjson, 'PUT')
         end 
         return
      end
      t = readin("1")
   end
end

return commandArray