Homeyscript to synch HUE lights with physical switches

I replaced almost all my lights with HUE and Tadfri bulbs and Osram/HUE plugs all connected to the HUE bridge. The people in the house hold also use the physical switches to turn of lights. As a consequence the lights in the HUE app and the physical state of the lights are no longer in sync.
( i do try to minimize this by automating as much as possible).

I created this Homeyscript (needs +/- 1 second run time) which is executed every 2 minutes. If a light is unreachable for a set amount of time, it is turned off.
It took quit some time combining, googling, asking people for help; now it working sharing it here . Maybe it can spark other ideas, maybe people see improvements in my code?

The trick is to get the HUE key and to give the HUE hub a fixed IP address (the key below was altered after copying). This is explained here in this post:

[Updated april 11, to include different tag values for reachable/unreachable]

// Performance indicator: calculate + report execution time @EOF
StartTime = _.now();

// Assume a execution frequency of every minute
// Frequecy is determined in the flow card.
// Alternative is calculating DeltaRun by uncommenting code below
DeltaRun = 60; // seconds

// Time limit after which a light is turned off
let TimeLimit = 600; // seconds

// Set uri for Homeyscript
let uri = 'homey:app:com.athom.homeyscript';

// set and build basis HUE API Url
let hueBridgeIP = ''
hueBridgeAPI = '2cHXcel6RJWnVuH5oHWaqASV28KKNlMAQu1wJQl0'
let urltext = "http://" + hueBridgeIP +"/api/" + hueBridgeAPI + "/lights"

// call and process the HUE light overview
let response = await fetch(urltext);
let json = await response.text();
var obj = JSON.parse(json);

//Determine how many seconds have passed since previous execution of this script
// If the tag does not yet exist (during first run / restart of Homey), start at 0
// this step increases execution time with +/- 200ms
//try {
//  let PreviousRun = await Homey.flowToken.getFlowToken({  uri: uri,   id: 'HUE run'});
//  DeltaRun = _.toInteger( (_.now() - PreviousRun.value)/1000);} 
//catch(err) { 
//      DeltaRun = 0};
// reset the HUE run tag with the current time, to be used next execution time
// run frequency is determined in the flow card  
//await tag('HUE run', _.now());

// Loop through all the lights in the HUE setup, pick up the lightname as it is used frequently in the script
for (const [i,light] of Object.entries(obj)) {
    LightName = light.name;

// If light can be reached, reset tag to 0
// If light cannot be reached, reset tag to -1
// Alternative is to only put those lights tags to 0 if existing tag <> 0. (Takes 3 seconds extra execution time.)
    if (light.state.reachable ) 
      {await tag(light.name, 0)};

  //Light cannot be reached, and light is on -> increase the light tag with the no of seconds between excution runs 
    if (!light.state.reachable && light.state.on){
        // Pull current tag value. if tag does not exist, create it. (first run / Homey restart / adding new light)
        try {
            let LightTag = await Homey.flowToken.getFlowToken({  uri: uri,   id: LightName});
            TimeLightNotReached = LightTag.value }
        catch(err) {
                TimeLightNotReached = 0 ;

        // increase timer with the time between runs
        TimeLightNotReached = TimeLightNotReached + DeltaRun;

        log(LightName + ' cannot be reached, but it is on in HUE app ' + ' Counter =' +  TimeLightNotReached);

        // if light is unreachable multiple executions and the time is up, switch it off, set tag to 0
        if (TimeLightNotReached > TimeLimit)  
            {log ('Switching off ' + LightName +' (' + TimeLightNotReached + '>' + TimeLimit + ")"  ); 
            a  = await fetch(urltext + '/' + i + '/state', { method : 'PUT',body : JSON.stringify({"on":false})})
            TimeLightNotReached = -1
        // write back the new timer value to the tag. -1 if it was just switched off and unreachable, 
        // else it will be the increased number 
        await tag(LightName, TimeLightNotReached);}
    } //loop back to next light

    // calculate and report the execution time (as part of performance )
    log(( _.now() - StartTime)/1000 + ' seconds')

Very nice, I certainly will give this a try. At this point i was replacing the fysical switches with gira senic friend of hue, but i have four fysical switches that combine two switches with a wall outlet. Tcs friends of hue has a solution, but i doubt if this what i am looking for

1 Like

I really appreciate your efforts because I was looking for such functionality! Works like a charm. I like the calculated time frame more than the default option. Thank you for implementing both options.

1 Like

I updated the script to have a tag value of 0 for a reachable light and -1 for aan unreachable bulb. This enables logic in flows to only turn on lights automatically that are actually available.

If have asked the HUE app owner (@johan_bendz) on Github to add reachability as a tag. Once implemented (fingers crossed) i will update (simplify) the script again.

Hi @BartOverdevest, you are aware my app is the one that does NOT use the Hue bridge? The Hue bridge app is Athoms app.