About This File
VD YEELIGHT MANAGER
Originally released on domotique-fibaro.fr
v. 1.3.0 - 14/01/2018
I present the VD Yeelight Manager which, as its name suggests, allows you to integrate Yeelight products with the HC2. To be very precise, I only have a Bedside Lamp and I have not tested this VD with other products. However, since the API is generic, there are no reasons that it does not work too. The only limit, I did not integrate in the DV management of the background light since the Bedside Lamp does not have such a light.
To use it, simply enter the IP of the Yeelight in the IP field of the DV, and the port in the Port field of the DV (the port used by the Yeelights is 55443). You can add or change elements of the virtual device according to your needs (the white light bulb does not need, for example, anything related to color management), as long as the TCP Connection and Transmission buttons keep their respective names (btnTCPConnection and btnTransmission). Yeelight Manager will find them himself by these names.
In order to be able to manage a Yeelight 'almost' like a module, simply insert in the scene or the code of the button or Main Loop the following code:
_y={credits='Yeelight Controller v. 1.3.0 - Copyright 2018 Olivier Meyer - GNU GPLv3',global='y_yeelight_global',item='y_yeelight_',props={power=true,bright=true,ct=true,rgb=true,hue=true,sat=true,color_mode=true,flowing=true,delayoff=true,flow_params=true,music_on=true,name=true,bg_power=true,bg_flowing=true,bg_flow_params=true,bg_ct=true,bg_lmode=true,bg_bright=true,bg_rgb=true,bg_hue=true,bg_sat=true,nl_br=true},f=fibaro,debug=function(s,m,c)s.f:debug(string.format('<span style="color:%s;">%s</span>', c, m))end,here=function(s)local h=type(s.f.getSelfId)=='nil' if h then return h,__fibaroSceneId else return h,s.f:getSelfId(),_elementID_ end end,log=function(s)local h=s:here()if h then local a=s.f:args()if a then if a[1].yeelight then s:debug(a[1].debug,a[1].color);s:debug(a[1].command,a[1].color);os.exit()end end end end,getBtn=function(s,i,n)local c,r=0,api.get('/devices/'..tostring(i))['properties']['rows'] local x=#r for a=1,x do local y=#r[a].elements for b=1,y do c=c+1 if n==r[a].elements[b].name then return c end end end s:debug('[Yeelight] Unable to locate button '..n..', check virtual device '..i,'Tomato');return nil end,build=function(s,m,p)local c='{"id":1, "method":"'..m..'", "params":['for i=1,#p do if type(p[i])=="number"then c=c..p[i]else c=c..'"'..p[i]..'"'end;if i~=#p then c=c..', 'end end;c=c..']}\r\n'return c end,load=function(s,v)local g=s.f:getGlobalValue(v)if string.len(g or '')>0 then local d=json.decode(g)if d and type(d)=='table'then return d else s:debug('[Yeelight] Unable to process data, check variable','Tomato')end else s:debug('[Yeelight] No data found!','Tomato')end return nil end,set=function(s,i,d)local g=s:load(s.global)if g[tostring(i)]then local a,b,c=s:here();g[tostring(i)].scene=a;g[tostring(i)].id=b;g[tostring(i)].button=c;g[tostring(i)].command=d;s.f:setGlobal(s.global,json.encode(g))end end,call=function(s,i,m,p)local b=s:getBtn(i,'btnTransmission')if b==nil then return nil end;local c=s:build(m,p)s:set(i,c)s.f:call(i,'pressButton',b)end,getValue=function(s,i,p,g)if s:checkP(p) then if type(g)~='table' then g=s:load(s.item..i)end if g.properties then if g.properties[p] then if g.properties[p].value then return g.properties[p].value end end end s:debug('[Yeelight] Unable to get value of '..tostring(p)..', please check variable.','Tomato');end return nil end,getModificationTime=function(s,i,p,g)if s:checkP(p) then if type(g)~='table' then g=s:load(s.item..i)end if g.properties then if g.properties[p] then if g.properties[p].modificationTime then return g.properties[p].modificationTime end end end s:debug('[Yeelight] Unable to get modification time of '..tostring(p)..', please check variable.','Tomato');end return nil end,get=function(s,i,p)local g=s:load(s.item..i);return s:getValue(i,p,g),s:getModificationTime(i,p,g)end,getStatus=function(s,i)local g=s:load(s.item..i)if g then if g.status then return g.status end end return nil end,getLastChange=function(s,i)local g=s:load(s.item..i)if g then if g.last then return g.last end end return nil end,checkP=function(s,p)if not s.props[p] then s:debug('[Yeelight] '..p..' is not an existing property!','Tomato') return false end return true end} _y:log()
This code above offers the following functions:
- _y:call(id, method, params) which allows to send a command to the lamp. The various buttons of the VD give examples. To go further, please have a look at the Yeelight API documentation : Yeelight_Inter-Operation_Spec.pdf
- _y:get(id, property) which does exactly the same thing as fibaro:get()
- _y:getValue(id, property) which does exactly the same thing as fibaro:getValue()
- _y:getModificationTime(id, property) which does exactly the same thing as fibaro:getModificationTime()
- _y:getStatus(id) which returns "online" if the lamp is connected to the wifi network, and "offline" otherwise
- _y:getLastChange(id) which returns a table containing the properties that have just been modified and their new value
The logs generated by the call () function are displayed in the debug zone of the scene (do not forget the _y: log () line and allow enough instances) or in the button or main loop of the virtual module from which the function was used.
To use these lamps as scene triggers, the VD automatically creates a global variable y_yeelight_XXX, where XXX is the ID of the VD. This global variable contains all the properties of the lamp and is updated in real time.
For example, to start a scene when a Yeelight is turned on:
--[[ %% globals y_yeelight_XXX --]] _y={credits='Yeelight Controller v. 1.3.0 - Copyright 2018 Olivier Meyer - GNU GPLv3',global='y_yeelight_global',item='y_yeelight_',props={power=true,bright=true,ct=true,rgb=true,hue=true,sat=true,color_mode=true,flowing=true,delayoff=true,flow_params=true,music_on=true,name=true,bg_power=true,bg_flowing=true,bg_flow_params=true,bg_ct=true,bg_lmode=true,bg_bright=true,bg_rgb=true,bg_hue=true,bg_sat=true,nl_br=true},f=fibaro,debug=function(s,m,c)s.f:debug(string.format('<span style="color:%s;">%s</span>', c, m))end,here=function(s)local h=type(s.f.getSelfId)=='nil' if h then return h,__fibaroSceneId else return h,s.f:getSelfId(),_elementID_ end end,log=function(s)local h=s:here()if h then local a=s.f:args()if a then if a[1].yeelight then s:debug(a[1].debug,a[1].color);s:debug(a[1].command,a[1].color);os.exit()end end end end,getBtn=function(s,i,n)local c,r=0,api.get('/devices/'..tostring(i))['properties']['rows'] local x=#r for a=1,x do local y=#r[a].elements for b=1,y do c=c+1 if n==r[a].elements[b].name then return c end end end s:debug('[Yeelight] Unable to locate button '..n..', check virtual device '..i,'Tomato');return nil end,build=function(s,m,p)local c='{"id":1, "method":"'..m..'", "params":['for i=1,#p do if type(p[i])=="number"then c=c..p[i]else c=c..'"'..p[i]..'"'end;if i~=#p then c=c..', 'end end;c=c..']}\r\n'return c end,load=function(s,v)local g=s.f:getGlobalValue(v)if string.len(g or '')>0 then local d=json.decode(g)if d and type(d)=='table'then return d else s:debug('[Yeelight] Unable to process data, check variable','Tomato')end else s:debug('[Yeelight] No data found!','Tomato')end return nil end,set=function(s,i,d)local g=s:load(s.global)if g[tostring(i)]then local a,b,c=s:here();g[tostring(i)].scene=a;g[tostring(i)].id=b;g[tostring(i)].button=c;g[tostring(i)].command=d;s.f:setGlobal(s.global,json.encode(g))end end,call=function(s,i,m,p)local b=s:getBtn(i,'btnTransmission')if b==nil then return nil end;local c=s:build(m,p)s:set(i,c)s.f:call(i,'pressButton',b)end,getValue=function(s,i,p,g)if s:checkP(p) then if type(g)~='table' then g=s:load(s.item..i)end if g.properties then if g.properties[p] then if g.properties[p].value then return g.properties[p].value end end end s:debug('[Yeelight] Unable to get value of '..tostring(p)..', please check variable.','Tomato');end return nil end,getModificationTime=function(s,i,p,g)if s:checkP(p) then if type(g)~='table' then g=s:load(s.item..i)end if g.properties then if g.properties[p] then if g.properties[p].modificationTime then return g.properties[p].modificationTime end end end s:debug('[Yeelight] Unable to get modification time of '..tostring(p)..', please check variable.','Tomato');end return nil end,get=function(s,i,p)local g=s:load(s.item..i);return s:getValue(i,p,g),s:getModificationTime(i,p,g)end,getStatus=function(s,i)local g=s:load(s.item..i)if g then if g.status then return g.status end end return nil end,getLastChange=function(s,i)local g=s:load(s.item..i)if g then if g.last then return g.last end end return nil end,checkP=function(s,p)if not s.props[p] then s:debug('[Yeelight] '..p..' is not an existing property!','Tomato') return false end return true end} _y:log() local function run() --executed on light on end local trigger = fibaro:getSourceTrigger() if trigger.type == "global" then if trigger.name == "y_yeelight_XXX" then if _y:getLastChange(XXX)["power"] == "on" then run() end end end
What's New in Version 1.3.1 See changelog
Released
Fixed a bug concerning the creation of global variables.