Page 1 of 1

setRGB for Hue

Posted: Sunday 30 December 2018 21:15
by Maxx
I am struggling to get the actual status of my Hue lights in dzvents. I made a scripts based on a script of Waaren where I can store the actual value of the lights. I want to use this to detect if the lights are changed by an external source (like the philips app).

Somehow the value as stored in the "device.color table" does not seem reliable

this is the script:

Code: Select all

-- Develop

return {
    on =       {
        
        timer = {'every minute'},

	},	
		
    data    =   {   Color                   = { initial = {} },
                    RGBColors               = { initial = {} },

},
    
    logging =   {   level                   = domoticz.LOG_DEBUG,
                    marker                  = "Licht develop" },
                        
    execute = function(dz, item)

        local AllLights = {37, 38}

        local function colorTable2RGB(colorTable)
            for k,v in pairs(colorTable) do 
                if k == "r" then
                    red = v
                end
                if k == "g" then
                    green = v
                end
                if k == "b" then
                    blue = v
                end
            end
            return red, green, blue
        end

        local function checkAll()
            for i, p in pairs(AllLights) do
                    dz.data.RGBColors = dz.utils.fromJSON(dz.devices(p).color)
                    local name = dz.devices(p).name
                    local Rood, Groen, Blauw = colorTable2RGB(dz.data.RGBColors)
                    dz.log(name)
                    dz.log('IDX is: ' .. p)       
                    dz.log(dz.data.RGBColors)                    
                    dz.log('Rood is: ' .. Rood)
                    dz.log('Groen is: ' .. Groen)
                    dz.log('Blauw is: ' .. Blauw)
            end
        end

        checkAll()
               

    end
}
The output is:

Code: Select all

 2018-12-30 21:07:00.417 Status: dzVents: Info: Licht develop: Eethoek_2
2018-12-30 21:07:00.417 Status: dzVents: Info: Licht develop: IDX is: 37
2018-12-30 21:07:00.417 Status: dzVents: Info: Licht develop: {["b"]=102, ["cw"]=0, ["g"]=202, ["ww"]=0, ["m"]=3, ["t"]=0, ["r"]=254}
2018-12-30 21:07:00.417 Status: dzVents: Info: Licht develop: Rood is: 254
2018-12-30 21:07:00.417 Status: dzVents: Info: Licht develop: Groen is: 202
2018-12-30 21:07:00.418 Status: dzVents: Info: Licht develop: Blauw is: 102
2018-12-30 21:07:00.418 Status: dzVents: Debug: Licht develop: Processing device-adapter for Eethoek_1: RGB(W) device adapter
2018-12-30 21:07:00.419 Status: dzVents: Debug: Licht develop: Processing device-adapter for Eethoek_1: Switch device adapter
2018-12-30 21:07:00.419 Status: dzVents: Info: Licht develop: Eethoek_1
2018-12-30 21:07:00.419 Status: dzVents: Info: Licht develop: IDX is: 38
2018-12-30 21:07:00.419 Status: dzVents: Info: Licht develop: {["b"]=102, ["cw"]=0, ["g"]=202, ["ww"]=0, ["m"]=3, ["t"]=0, ["r"]=254}
2018-12-30 21:07:00.419 Status: dzVents: Info: Licht develop: Rood is: 254
2018-12-30 21:07:00.419 Status: dzVents: Info: Licht develop: Groen is: 202
2018-12-30 21:07:00.419 Status: dzVents: Info: Licht develop: Blauw is: 102
2018-12-30 21:07:00.420 Status: dzVents: Info: Licht develop: ------ Finished Licht develop v0 
it shows both lights with the same rgb values, the problem is that the colors are different in reality. Is something wrong with my script?

I am not sure when the values are updated in the device.

Re: setRGB for Hue

Posted: Sunday 30 December 2018 23:27
by waaren
Maxx wrote: Sunday 30 December 2018 21:15 I am struggling to get the actual status of my Hue lights in dzvents. I made a scripts based on a script of Waaren where I can store the actual value of the lights. I want to use this to detect if the lights are changed by an external source (like the philips app).
I am not sure when the values are updated in the device.
Please check output of script below. It shows that the results from the API call returns up to date values for rgb and that the result of dz.devices(id).color can be outdated. dzVents is only a passtrough for the .color from domoticz data so I don't think much can be done about that.

Code: Select all

local callBack    = "getColorFromDevice"
local allLights = {37, 38}
--local allLights = {156,157}
    

return {
    on =       {
                    timer           = {'every minute'},
                    devices         = allLights, 
                    httpResponses   = { callBack    },
                },

    logging =   {   level                   = domoticz.LOG_DEBUG,
                    marker                  = "Licht develop" },
                        
    execute = function(dz, item)

        local function logWrite(str,level)
            dz.log(tostring(str),level or dz.LOG_DEBUG)
        end

        
        local function getDeviceStatus()
            local dzAPI = dz.settings['Domoticz url'] .. "/json.htm?type=devices&rid=" 
            for i,v in ipairs(allLights) do
                url = dzAPI .. v
                dz.openURL  ({ url = url, method = "GET", callback = callBack })
            end
        end
        
        if not item.isHTTPResponse then 
            getDeviceStatus() 
        else  
            -- logWrite(item.data)
            local colorJSON     = dz.utils.fromJSON(item.json.result[1].Color)
            local device        = dz.devices(tonumber(item.json.result[1].idx))
            local colorDevice   = dz.utils.fromJSON(device.color)
            
            for k,v in pairs({Red="r",Blue="b",Green="g"}) do
                logWrite(   string.format("%-6s", k ) .. 
                            " from JSON ==>> " .. 
                            string.format("%03d", colorJSON[v]) .. 
                            " ; from dz.devices(" .. device.name .. ").color ==>> " .. 
                            string.format("%03d",colorDevice[v])
                        )
            end
        end
    end
}              

Re: setRGB for Hue

Posted: Monday 31 December 2018 13:20
by Maxx
Hi Waaren,

Thanks for you quick response. You are right the, data is often outdated sometimes not even close to what has been send to the lights.

Currently I am using OpenURL to get the Hue status directly from the Hue json and I use curl commands to set the lights. (Send the Hue native HSB and read it)
I rather not send RGB values and then read the HSB to get the real status

Because I want to move away from the curl commands I started trying the more "dzvent native" commands like setRGB. (send RGB and read RGB).

There is another way to move away from curl and still use the HSB values: Currently openURL only supports the POST method, the Hue API needs the PUT method.

I tried modifying the domoticz.lua to accept the PUT method but this is not as easy as I hoped. Maybe this is a nice update for the next version of dzvents?

Re: setRGB for Hue

Posted: Monday 31 December 2018 15:26
by waaren
Maxx wrote: Monday 31 December 2018 13:20 I tried modifying the domoticz.lua to accept the PUT method but this is not as easy as I hoped. Maybe this is a nice update for the next version of dzvents?
Would indeed be nice but not very rewarding if we would have to call curl behind the scenes to get this. I know @Dannybloe and others looked at it but seems complicated.
I started a couple of weeks ago on something similar with Hue colors in dzVents for one of the forum-members but stopped somewhere halfway because I got no feedback anymore on an updated version.
Hopefully you or someone else can cherryPick from it and get this whole color stuff a step forward. For me the different type of calls to Hue and the use of transitiontime was new.

Code: Select all

--[[  Hue transition.lua  (dzVents version must be > 2.4) 

    prerequisites:  Hue bridge with at least one Philips Hue bulb. (not tested for other brands)
                    curl installed om the OS and accessible by domoticz user
                    dzVents version 2.4 or newer installed as described in the wiki
                
    at      civiltwilightend the Hue bulbs are switched on with daylight color  
    until   sunset gradually the warmth of the lights will become warmer and the brightness will drop
    after   sunset the brightness will drop very smoothly to about 20% 

    Change the light names at line 110 to your lightnames within quotes or IDX without 
    ensure that the domoticz user can execute curl and check the location of your curl executable at line 111
        Line 112 and 113 are to be used for deActivation of the script using the state of a switch.     
    script will start at civiltwilightend, gradually dropping brightness and Kelvin until sunset 
    and gradually dropping brightness further from sunset to 1:45 hour after sunset 
   
   http://192.168.192.72/debug/clip.html

    URL:
    /api/apistring/lights/5/state
start
   {"on":true,"bri":254,"ct":153 ,"sat":0}              
drop 
{
		"on": true,
		"bri": 100,
		"sat": 252,
		"xy": [
			0.58,
			0.31
		],
		"ct": 250,
		"transitiontime":100 
	}
    
dim    
 {
		"on": true,
		"bri": 40,
		"sat": 252,
		"xy": [
            0.58,
			0.31
		],
		"ct": 500,
		"transitiontime":100 
	}
    
]]--

local hueResponse       = "hueFutureCommand_"
local hardwareCallback  = "getDomoticzHardware"
local hueDeviceCallback = "getHueDeviceStatus"           
        
local stage1            = "initial"
local stage2            = "hardwareInfo retrieved"
local stage3            = "hueInfo retrieved"            

local hueTriggerIDX     = 18
local refreshTrigger    = "at 05:01"
local twilightTrigger   = "every 5 minutes between 60 minutes before sunset and sunset"
local sunsetTrigger     = "2 minutes after sunset"                                  

return {

    on          =   {   timer           =   {   
                                                twilightTrigger,                       
                                                refreshTrigger,
                                                sunsetTrigger,                         
                                            },
                    
                        httpResponses   =   {   
                                                (hueResponse .."*"),
                                                 hardwareCallback,
                                                 hueDeviceCallback,
                                            },
                                            
                        devices         =   {  
                                                [hueTriggerIDX] = { 'between sunset and 23:00' }
                                            },
                    },                                            

    data        =   {   refreshState        =   { initial = stage1    },
                        refreshTime         =   { initial = "never"   },
                        Activated           =   { initial = false     },
                        HueIP               =   { initial = ""        },
                        HueDevices          =   { initial = {}        },
                        HueAPI              =   { initial = ""        },
                        manualActivation    =   { initial = "notset"  },
                    },

    logging     =   {   
                        level           =   domoticz.LOG_DEBUG,
                        marker          =   "Hue transition" 
                    },

    execute = function(dz, item, info)
        
        _G.logMarker            = info.scriptName     -- sets the logmarker for dz.log
         
        local function logWrite(str,level)
            dz.log(tostring(str),level or dz.LOG_DEBUG)
        end

        local hueLights         = {}
--      ********************************************************************* Your changes below this line *************
        local luxDeviceIDX          = 100
        local luxFence              = 1200
        local dimTransitionSeconds  = 6500                     -- Max 6500
        hueLights                   = {"LM46 tafel rechts",156 }    -- Change to name(s) with surrounding Quotes or domoticz IDX without      
        local curlExecutable        = "/usr/bin/curl"               -- Check if you have curl on your system
        local deActivationDevice    = 18   -- IDX, "name" or nil    -- deviceName within "" or IDX number without to deActivate script execution 
        local ActivationState       = "Off"                         -- State of the deactivation device that cause the script to be active
        local keepOnAfterDim        = false
--      ********************************************************************** No changes below this line **************    
        
        if deActivationDevice and dz.devices(deActivationDevice).state ~= ActivationState and 
            item.trigger ~= refreshTrigger and not item.isHTTPResponse then                                     -- Changed  
            logWrite("No action needed; Alarm is on ")
            return
        end

        local twilight                  =  dz.devices(luxDeviceIDX).lux < luxFence 
        local brightLight               = '{"on":true,"bri":254,"ct":153 ,"sat":0,"hue":9735}'  -- 254 = 100%, 153 = 6500 K (max),  9735 = Sunlight
        local dropColorAndBrightness    = '{"on": true,"bri": 100,"sat": 252,"xy": [ 0.58, 0.31 ],"ct": 250,"transitiontime":XXXX }'
        local dimTransitionTicks        = math.min(65500,dimTransitionSeconds * 10)  
        local dropBrightness            = '{"on": true,"bri": 15,"sat": 252,"hue":9735,"ct": 500,"transitiontime": ' .. 
                                            dimTransitionTicks .. '}'                                              -- changed
                                            -- 65500, about 1 hour and 45 minutes)   -- 40  = about 17%
        local transitionTime            = {} 
        
        local function osExecute(cmd)
            logWrite(cmd) 
            local fileHandle     = assert(io.popen(cmd, 'r'))
            local commandOutput  = assert(fileHandle:read('*a'))
            local returnTable    = {fileHandle:close()}
            logWrite("\n\nreturnCode: " .. returnTable[3] .. "\ncommandOutput: ".. commandOutput .. "\n")
            return commandOutput,returnTable[3]            -- rc[3] contains returnCode
        end
            
        local function callURL(url,callBack,seconds)
            local seconds     = seconds or 0
            local callBack    = callBack or "noCallbackRequired"  
            local url         = url or dz.settings['Domoticz url'] .. "/json.htm?type=command&param=addlogmessage&message=" ..
                                       dz.utils.urlEncode(info.scriptName) ..  "%20Scheduled%20this%20callback%20" .. seconds .. "%20seconds%20ago"
            dz.openURL  ({ url = url, method = "GET", callback = callBack }).afterSec(seconds)
        end

        local function hueHTTP()
            return "http://" .. dz.data.HueIP .. "/api/" ..  dz.data.HueAPI ..  "/lights"    
        end
        
        local function light2HueNumber(light)
            return tonumber(light.deviceId)
        end
        
        local function curl(light, body)
            return curlExecutable .. " -H 'Content-Type: application/json' -X PUT -d " ..
                    "'" .. body .. "' " ..hueHTTP() .. "/" .. light2HueNumber(light) .."/state"
        end
        
        local function getHueStatus() -- this function calls the Phillips hue hub and ask for all lights   
           callURL(hueHTTP(), hueDeviceCallback)
        end

        local function insertDelay(str,rep)
            return str:gsub("XXXX",rep)
        end
        
        local function dimSequence()
            for i=1,#hueLights do    
                osExecute(curl(dz.devices(hueLights[i]),dropBrightness))
            end
        end
        
        local function brightLight()                                             -- new function
            for i=1,#hueLights do    
                osExecute(curl(dz.devices(hueLights[i]),brightLight))
            end
        end
        
        local function startSequence()
           dz.data.manualActivation = "notset"
            transitionTime.seconds = dz.time.secondsSinceMidnight - ( _G.timeofday.CivTwilightEndInMinutes * 60 )
            transitionTime.hueTicks = math.max( 6000, math.min(65534,  transitionTime.seconds * 10 )) -- Min 10 minutes. Hue uses 0.1 second Ticks 
            dz.data.Activated = true
            for i=1,#hueLights do    
                osExecute(curl(dz.devices(hueLights[i]),brightLight))
                osExecute(curl(dz.devices(hueLights[i]),insertDelay(dropColorAndBrightness,transitionTime.hueTicks)))
            end
        end
       
        local function getDomoticzHardware()  -- this function calls local domoticz process and ask for all defined Hardware  
           local url  = dz.settings["Domoticz url"] .. "/json.htm?type=hardware"    
           callURL(url, hardwareCallback)
           dz.data.HueDevices = {}   -- (re) init Hue devices when new hardware is retrieved
        end
          
        local function getHueStatus() -- this function calls the Phillips hue hub and ask for all lights   
           local url = "http://" .. dz.data.HueIP .. "/api/" ..  dz.data.HueAPI ..  "/lights"    
            callURL(url,hueDeviceCallback)
        end

        local function handleHueDeviceStatus()
           local lights = item.json -- convert to table
           
            for i, light in pairs(lights) do
                logWrite("Light in Hue: [" .. i .. "] type: " .. light.type)
                logWrite("Light in Hue: [" .. i .. "] name: " .. light.name)
                t                               = {}
                t.number                        = i
                t.type                          = light.type
                for j=1,#hueLights do                                      -- Just store the lights involved and ignore rest
                    if tonumber(dz.devices(hueLights[j]).deviceId) == tonumber(t.number) then
                        dz.data.HueDevices[light.name]  = t
                    end  
                end  
            end
            dz.data.refreshTime =  os.date("%x %X")
        end
        
        local function  handleDomoticzHardware()        -- this function extracts hueIP from json string from getDomoticzHardware call and 
           
           rt  = item.json.result                   -- put these in persistent vars for future use   
            for i = 1,#rt do
                if rt[i].Type == 38 then                -- Hardware type Hue is 38
                    dz.data.HueIP  = rt[i].Address      -- Fill with IP number
                    dz.data.HueAPI = rt[i].Username     -- Fill with API key
                    return false
                end
            end    
        end
        
        local function initializePersistentData(callType)
           
            dz.data.Activated = true
            if dz.data.manualActivation == "notset" then
                dz.data.manualActivation = item.isDevice and item.state == "Off" and dz.time.matchesRule("between 15 minutes before sunset and 22:00") 
            end
            
            if (dz.data.manualActivation and not(next(dz.data.HueDevices))) or ( callType ~= nil and callType == "time" ) then
                dz.data.Activated = false
           
                if dz.data.refreshState == stage1 then 
                 -- Get API key and hue IP to refresh persistent data
                    getDomoticzHardware() 
                    dz.data.refreshState = stage2
                elseif dz.data.refreshState == stage2 then 
                 -- get Lights info to refresh persistent data
                    handleDomoticzHardware()
                    getHueStatus() 
                    dz.data.refreshState = stage3
                elseif dz.data.refreshState == stage3 then
                    handleHueDeviceStatus()
                    dz.data.refreshState = stage1
                    if dz.data.manualActivation then 
                        dz.devices(hueTriggerIDX).switchOff().afterSec(1)
                    end
                    dz.data.manualActivation = "notset"
                end 
            elseif item.trigger == hueDeviceCallback  then
                handleHueDeviceStatus()         -- get hue light info directly from Hue hub
                dz.data.refreshState = stage1
            elseif dz.data.HueIP ~= "" and dz.data.HueAPI ~= ""  then
                if next(dz.data.HueDevices) == nil then
                    getHueStatus()                  -- We already have the API key and hue IP but HueDevices table is empty
                end    
            elseif (dz.data.HueIP == "" or dz.data.HueAPI == "")  and dz.data.refreshState == stage1 then
                getDomoticzHardware()           -- Get API key and hue IP
                dz.data.refreshState = stage2
            elseif item.trigger == hardwareCallback then
                handleDomoticzHardware()        -- get API key and hue IP from JSON into persistent vars    
                getHueStatus()                  -- We already have the API key and hue IP
                dz.data.refreshState = stage3
            end 
        end
        
        -- Main 
        if item.trigger == refreshTrigger or not(next(dz.data.HueDevices)) then 
             initializePersistentData("time")                         -- refresh persistent data
        elseif item.trigger == hueResponse .. "setInactive" then
            dz.data.Activated = false
        
        elseif item.trigger == hueResponse .. "dimDelayed" then
            dimSequence()

        elseif dz.time.matchesRule(sunsetTrigger) or
               dz.data.manualActivation then
           
            if dz.data.Activated then
               logWrite("Sequence already activated")
               return
            end    
            initializePersistentData()       -- Check if initializing persistent Data is necessary 
            if next(dz.data.HueDevices) then -- we have the devices in persistent data
                startSequence()
                local delay = math.abs(transitionTime.seconds)
                callURL(nil,hueResponse .. "dimDelayed",delay )          -- trigger script again after transitionTime.minutes
                callURL(nil,hueResponse .. "setInactive", delay + dimTransitionSeconds )    
            end
        
        elseif twilight then                                                  -- new
            if next(dz.data.HueDevices) then -- we have the devices in persistent data
                brightLight()
            end    
        end 
    end
}

Re: setRGB for Hue

Posted: Monday 31 December 2018 15:36
by Maxx
Thanks, I will have a look at this but first I have to bake some oilballs today

Happy 2019