HowTo: Use Philips Hue sensors (Motion Sensor / Dimmer Switch)

Fair warning The Hue binding now supports sensor integration. This tutorial is deprecated.

In the last couple of days a lot of questions about the usage and handling of Philips Hue sensors in OH2 popped up in the community. I started a separate thread for collecting every information in one place as I need to reference them later.

Problem statement

Currently it’s not possible to retrieve data from Hue Motion Sensors or Hue Dimmer Switches from the Philips Hue binding (see https://github.com/eclipse/smarthome/issues/2603). We have to do it by creating our own solution. That is possible with the help of the HTTP binding and the JavaScript transformation (JsonPath transformation is possible too but imho not flexible enough because it is not possible to modify the data immediately if we have/want to).

Preparation

You need an authorized username for the requests to the Hue Bridge. Philips has a great tutorial for that https://developers.meethue.com/documentation/getting-started.

Each sensor has its own id. If you don’t know them navigate to http://<bridge ip address>/api/<username>/sensors in your browser to find them. Look for occurrence of the following types:

  • ZLLSwitch - dimmer switch
  • ZLLTemperature - temperature sensor (included in the Hue Motion Sensor)
  • ZLLPresence - motion sensor
  • ZLLLightLevel - ambient light sensor (included in the Hue Motion Sensor)

General setup

I recommend to use HTTP cache items for each sensor to reduce the number of requests for polling the Hue API.

services/http.cfg

hueDimmerSwitch.url=http://<bridge ip address>/api/<username>/sensors/<id>
hueDimmerSwitch.updateInterval=5000

hueMotionSensorTemperature.url=http://<bridge ip address>/api/<username>/sensors/<id>
hueMotionSensorTemperature.updateInterval=60000

hueMotionSensorPresence.url=http://<bridge ip address>/api/<username>/sensors/<id>
hueMotionSensorPresence.updateInterval=5000

hueMotionSensorIlluminance.url=http://<bridge ip address>/api/<username>/sensors/<id>
hueMotionSensorIlluminance.updateInterval=15000

items/http.items

// Hue Dimmer Switch - switch
Number hueDimmerSwitchButton "button [%d]" <wallswitch> { http="<[hueDimmerSwitch:5000:JS(getHueButton.js)]" }
DateTime hueDimmerSwitchButtonLastChange "last change [%1$tY-%1$tm-%1$tdT%1$tH:%1$tM:%1$tS]" <time> { http="<[hueDimmerSwitch:5000:JS(getHueLastChange.js)]" }

// Hue Dimmer Switch - device
Switch hueDimmerSwitchBattery "battery low" <lowbattery> { http="<[hueDimmerSwitch:5000:JS(getHueBattery.js)]" }
Number hueDimmerSwitchBatteryLevel "battery level [%d %%]" <battery> { http="<[hueDimmerSwitch:5000:JS(getHueBatteryLevel.js)]" }
String hueDimmerSwitchThingStatus "connection [%s]" <link> { http="<[hueDimmerSwitch:5000:JS(getHueThingStatus.js)]" }

// Hue Motion Senssor - temperature sensor
Number hueMotionSensorTemperature "temperature [%.1f °C]" <temperature> { http="<[hueMotionSensorTemperature:60000:JS(getHueTemperature.js)]" }
DateTime hueMotionSensorTemperatureLastChange "Letzte Änderung [%1$tY-%1$tm-%1$tdT%1$tH:%1$tM:%1$tS]" <time> { http="<[hueMotionSensorTemperature:60000:JS(getHueLastChange.js)]" }

// Hue Motion Sensor - motion sensor
Switch hueMotionSensorPresence "presence [%s]" <motion> { http="<[hueMotionSensorPresence:5000:JS(getHuePresence.js)]" }
DateTime hueMotionSensorPresentLastChange "last change [%1$tY-%1$tm-%1$tdT%1$tH:%1$tM:%1$tS]" <time> { http="<[hueMotionSensorPresence:5000:JS(getHueLastChange.js)]" }

// Hue Motion Sensor - ambient light sensor
Number hueMotionSensorIlluminance "illuminance [%.1f Lux]" <light> { http="<[hueMotionSensorIlluminance:15000:JS(getHueIlluminance.js)]" }
DateTime hueMotionSensorIlluminanceLastChange "last change [%1$tY-%1$tm-%1$tdT%1$tH:%1$tM:%1$tS]" <time> { http="<[hueMotionSensorIlluminance:15000:JS(getHueLastChange.js)]" }
Switch hueMotionSensorDarkness "darkness" <moon> { http="<[hueMotionSensorIlluminance:15000:JS(getHueDark.js)]" }
Switch hueMotionSensorDaylight "daylight" <sun> { http="<[hueMotionSensorIlluminance:15000:JS(getHueDaylight.js)]" }

// Hue Motion Sensor - device
Switch hueMotionSensorBattery "battery low" <lowbattery> { http="<[hueMotionSensorTemperature:60000:JS(getHueBattery.js)]" }
Number hueMotionSensorBatteryLevel "battery level [%d %%]" <battery> { http="<[hueMotionSensorTemperature:60000:JS(getHueBatteryLevel.js)]" }
String hueMotionSensorThingStatus "connection [%s]" <link> { http="<[hueMotionSensorPresence:5000:JS(getHueThingStatus.js)]" }

transform/

getHueButton.js

(function(i) {
    var json = JSON.parse(i);
    return parseInt(json["state"]["buttonevent"]);
})(input)

buttonevent returns up to 16 different values for the buttons from top to down:

BUTTON STATE CODE
Button 1 (ON) INITIAL_PRESSED 1000
HOLD 1001
SHORT RELEASED 1002
LONG RELEASED 1003
Button 2 (DIM UP) INITIAL_PRESSED 2000
HOLD 2001
SHORT RELEASED 2002
LONG RELEASED 2003
Button 3 (DIM DOWN) INITIAL_PRESSED 3000
HOLD 3001
SHORT RELEASED 3002
LONG RELEASED 3003
Button 4 (OFF) INITIAL_PRESSED 4000
HOLD 4001
SHORT RELEASED 4002
LONG RELEASED 4003

getHueTemperature.js

(function(i) {
    var json = JSON.parse(i);
    return parseFloat(json["state"]["temperature"]) / 100;
})(input)

getHuePresence.js

(function(i) {
    var json = JSON.parse(i);
    return (json["state"]["presence"]) == true ? "ON" : "OFF";
})(input)

getHueIlluminance.js

(function(i) {
    var json = JSON.parse(i);
    return Math.pow(10, (parseInt(json["state"]["lightlevel"]) - 1) / 10000);
})(input)

According to the Hue API: lightlevel = 10000 * log10(lux) + 1.

getHueDark.js

(function(i) {
    var json = JSON.parse(i);
    return (json["state"]["dark"]) == true ? "ON" : "OFF";
})(input)

getHueDaylight.js

(function(i) {
    var json = JSON.parse(i);
    return (json["state"]["daylight"]) == true ? "ON" : "OFF";
})(input)

getHueLastChange.js

(function(i) {
    var json = JSON.parse(i);
    return (json["state"]["lastupdated"]);
})(input)

lastupdated returns timestamps in UTC.

getHueBattery.js

(function(i) {
    var json = JSON.parse(i);
    return parseInt(json["config"]["battery"]) <= 10 ? "ON" : "OFF";
})(input)

Define your own threshold when the switch item should indicate a low battery.

getHueBatteryLevel.js

(function(i) {
    var json = JSON.parse(i);
    return parseInt(json["config"]["battery"]);
})(input)

battey returns a percentage value (0 - 100).

getHueThingStatus.js

(function(i) {
    var json = JSON.parse(i);
    return (json["config"]["reachable"]) == true ? "ONLINE" : "OFFLINE";
})(input)

Known issues

  • Some of the transformation fails when you disable the sensor in the Philips Hue App
17 Likes

Tips & Tricks

Deal with transformation failures

(function(i) {
    var json = JSON.parse(i);
    // Philip Hue sensors API returns "none"
    if( json["state"]["lastupdated"] !== "none" ) {
        // your code goes here
    } else {
        return "UNDEF";
    }
})(input)

Deal with timezones for last change timestamps

(function(i) {
    var json = JSON.parse(i);
    var timestamp = new Date(json["state"]["lastupdated"]);
    var timezoneOffset = new Date().getTimezoneOffset() * 60000;
    return new Date(timestamp.getTime() - timezoneOffset).toISOString();
})(input)

Convert to different temperature units (e.g. Fahrenheit)

There are two possible solutions.

  1. First calculate in transformation:
(function(i) {
    var json = JSON.parse(i);
    // convert Celsius to Fahrenheit
    return (parseFloat(json["state"]["temperature"]) / 100) * 1.8 + 32;
})(input)
  1. Second define a Number:Temperature item. Notice: I didn’t test this, yet:
Number:Temperature hueMotionSensorTemperature "temperature [%.1f °F]" <temperature> { http="<[hueMotionSensorTemperature:60000:JS(getHueTemperatureInCelsius.js)]" 

getHueTemperatureInCelsius.js

function(i) {
    var json = JSON.parse(i);
    return parseFloat(json["state"]["temperature"]) / 100 + " °C";
})(input)

Rounding values (e.g. temperature)

There are several ways to archieve a solution.

  1. First use Math.round(). Notice: Math.round() returns the nearest integer:
return Math.round(parseFloat(json["state"]["temperature"]) / 10) / 10;
  1. Second use toFixed():
return (parseFloat(json["state"]["temperature"]) / 100).toFixed(1);
  1. Third do not round in the transform script, round the item / display value. This is recommended:
Number hueMotionSensorTemperature "temperature [%.1f °C]" <temperature> { http="..." }
1 Like

Hi Christoph,

great tutorial :+1:, most of it i did in the past, but i don’t used HTTP cache items to reduce the number of requests.

Do you know how to convert the Hue-LightLevel to Lux?

I think it’s “10^(lightlevel -1/ 10000)” - but i’dont know how to calculate the value with openHAB-Transformations.

Regards
Heiko

Thanks.

According to the Hue API: “Light level in 10000 log10 (lux) + 1 measured by sensor”. The inverted formula should be lux = 10 ^ ((lightlevel - 1) / 10000) - like you said. I am going to adopt it to JavaScript syntax and add it to the tutorial later this day.

Here you are. I will add it above.

getHueIlluminance.js

(function(i) {
    var json = JSON.parse(i);
    return Math.pow(10, (parseInt(json["state"]["lightlevel"]) - 1) / 10000);
})(input)

could you maby do a write up on how to do this thanks for this guide it helped me alot

Hi Aaron,

The complete HowTo is based an those cached items.

Oh maby I already set that up then I assumed it was something else I had too do aswell thanks for your help

do you know of a way that OH can enable and disable these sensors or is it limited to only reading from them?

Yes, I do. You can send a command in a rule or use a Switch item for it.

demo.items

Switch hueMotionSensorStatus

demo.rules

rule "Switch Hue Motion Sensor ON / OFF"
when
    Item hueMotionSensorStatus changed
then
    val url = "http://<bridge ip address>/api/<username>/sensors/<id>/config"
    var String body = ""
    if( hueMotionSensorStatus.state != ON ) {
        body = '{"on":false}'
    } else {
        body = '{"on":true}'
    }
    logInfo("demo", "Send command '{}' to {}", body, url)
    sendHttpPutRequest(url, "application/json", body)
end

I’ve made a german tutorial on Youtube. Hope I’m going to finde some time to make also an english one. Stay tuned. :smiley:

3 Likes

Interesting Tutorial in my native language.

As mentioned before this JS-Script transforms the value of the Hue Sensor to Lux:

(function(i) {
    var json = JSON.parse(i);
    return Math.pow(10, (parseInt(json["state"]["lightlevel"]) - 1) / 10000);
})(input)

Awesome, thanks for the hint. :smiley:

Nice Tutorial but you missed a round bracket at the start of getHueButton.js, getHuePresence.js and getHueBattery.js.

Should be (function(i) { instead of function(i) {.

Thanks for the hint. I changed it in my first post. :+1:

I guess the item names get pulled from items/http.items

And a single hue motion detector gets an item called presence - but I would like to call that thing - kitchen_presence and what about the next motion detector, how do I know which is which?

NICE tutorial

Hi mbechc,

You can use any name you like for the items. The names above are only an example. E.g. you can replace hueMotionSensor with hueKitchenMotionSensor and the code will work as good as before. The JavaScript files for the transformation are reusable and you need them only once in your setup.

Sorry I wasn’t clear enough. How do I get personalized names fx KitchenPresence and BedroomPresence If I have 2 sensors - all items names discovered are readonly - at least through Paper UI

My tutorial is a completely text based configuration. It is not possible to change anything using an UI (e.g. PaperUI).

Please read my above post again. You can create a copy of all items for your kitchen and another copy of all items for your bedroom. Just change the names of those copies to whatever name you like. But you have to identify the correct ids for each of your motion sensor device first.

Hi

Thanks for the in-depth information - it kinda saved my sanity :wink:

Anyway, the button function does not work here - instead of “1002” or “1004” I get “1002.0” or “1004.0” - any idea why I get those strange numbers?