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¶m=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
}