[DzVents] Animer des lumières (clignoter / transition ...)
Publié : 11 août 2021, 18:31
Salut,
Je partage avec vous un script DZVents de mon cru : une série de fonction pour animer vos ampoules, comme une transition, le clignotement, changement de couleurs etc...
Par exemple vous voulez être averti lorsque quelqu'un est de retour à la maison en ayant une ampoule qui clignote. (Attention, cet exemple utilise mon autre script de restauration d'état d'une ampoule)
Différentes animations sont possibles :
Clignotement
Transition vers une autre couleur
Echanger les couleurs des lampes d'un même groupe / scène : très utile pour créer des effets guirlande de Noël et des petites animations facile à réaliser dans l'éditeur de groupes / scènes domoticz
Alterner les scènes / groupes : Pour créer des animations plus complexes (en fait une scène / groupe = un temps de l'animation...)
Pour l'installer :
Vous avez besoin de l'utilitaire CURL, vous pouvez télécharger CURL ici s'il n'est pas déjà installé sur votre système. CURL est disponible pour de mulitples plateforme (windows / linux). C'est un utilitaire ligne de commande pour faire des requêtes HTTP (entre autres), mon script l'utilise pour faire des requêtes HTTP synchrones (DZVents propose seulement des requêtes asynchrones). Une fois téléchargé, placez CURL dans le dossier de votre choix et notez le chemin vers CURL, on va en avoir besoin.
Vous devez aussi avoir un script DZVents "global_data". Si vous n'avez pas ce "global_data", rendez vous dans Domoticz dans "Configuration" -> "Plus d'Options" -> "Evénements", cliquez sur "+" et sélectionnez "DZVENTS" -> "GLOBAL DATA". Au lieu de "Script #1" tapez "global_data" (sans les guillemets). Copiez le code ci-dessous et cliquez sur "SAUVEGARDER" (vérifiez les logs de Domoticz s'il n'y a pas d'erreur, il y a quelque fois des problèmes de permissions quand Domoticz sauvegarde les scripts)
Si vous avez un script "global_data", alors vous devez ajouter les fonctions et variables globales que vous trouvez dans le code ci-dessous.
Vous devez editer le code pour y remplacer le chemin vers CURL de votre domoticz, c'est à la ligne 30 dans l'éditeur qu'il faut faire le changement :
cmd='"C:\\Program Files (x86)\\Domoticz\\scripts\\lua\\curl.exe" '..domoticz.settings.url..'/json.htm?type=devices^&rid='..idx
Remplacez ce chemin par le vôtre.
Lorsque c'est fait il faut ensuite créer le script principal : dans l'éditeur de scripts, cliquez sur "+" puis sélectionnez "DZVENTS" -> "CUSTOM EVENTS", donnez lui le nom que vous voulez à la place de "Script #1", par exemple "Transition Etat" (attention pas d'accents etc.. sinon ça coince), copiez / collez le code ci-dessous et cliquez sur "SAUVEGARDER".
Désormais dans vos scripts vous pouvez utiliser les fonctions suivantes :
domoticz.helpers.transitionTo(domoticz, device, color, duration)
Change progressivement la couleur de l'ampoule vers la nouvelle couleur. Vous pouvez choisir la durée de l'effet (en secondes). La couleur est dans le format habituel { ['r']=0, ['g']=0, ['b']=0, ['br']=0, ['cw']=0, ['ww']=0, ['t']=0, ['m']=1/2/3/4 }.
Vous pouvez effectuer une transition vers l'état éteint simplement en utilisant la couleur noir ou la luminosité à 0.
domoticz.helpers.blink(domoticz, device, color1, color2, speed, duration)
Fait clignoter une lumière. On peut choisir deux couleurs à alterner ainsi que la vitesse de changement et la durée totale du clignotement. Si une des couleurs est noire ou que la luminosité est à 0 alors un clignotement allumé / éteint est effectué.
domoticz.helpers.animateGroup(domoticz, group, speed, duration)
Echange la couleur de chaque lampe au sein d'un groupe / scène. Vous pouvez choisir la vitesse et la durée de l'effet
domoticz.helpers.animateScenes(domoticz, scenes, speed, duration)
Alterne les scènes / groupes : Change de scène toutes les xx secondes. Vous choisissez xx (speed) et la durée totale de l'effet. C'est un tableau de scènes / groupes qu'il faut donner
domoticz.helpers.cancelTransition(domoticz, device)
Annule une animation en cours pour une ampoule. Ne fonctionne qu'avec blink et transitionTo.
Je partage avec vous un script DZVents de mon cru : une série de fonction pour animer vos ampoules, comme une transition, le clignotement, changement de couleurs etc...
Par exemple vous voulez être averti lorsque quelqu'un est de retour à la maison en ayant une ampoule qui clignote. (Attention, cet exemple utilise mon autre script de restauration d'état d'une ampoule)
Code : Tout sélectionner
return {
on = {
devices = { 'Présence Membre Famille' }
},
logging = {
level = domoticz.LOG_INFO,
marker = 'BLINKING TEST',
},
execute = function(domoticz, device)
if(device.isDevice) then
domoticz.log('XXXX est rentré, on fait clignoter une ampoule du salon', domoticz.LOG_INFO)
-- Stocke l'état actuel de l'ampoule et programme sa restauration dans 35 sec.
domoticz.helpers.restoreStateAfter(domoticz, 'Ampoule Salon', 35)
-- Fais clignoter l'ampoule du salon pendant 30 secondes (clignote rouge / off, toutes les 0.5 sec
-- de cette manière : rouge / off / rouge / off / rouge ....)
domoticz.helpers.blink(domoticz, 'Ampoule Salon',
{ ['r']=0,['g']=0,['b']=0,['br']=100,['cw']=0,['ww']=0,['t']=0,['m']=3 },
{ ['r']=255,['g']=0,['b']=0,['br']=100,['cw']=0,['ww']=0,['t']=0,['m']=3 },
0.5, 30)
end
end
}
Clignotement
Transition vers une autre couleur
Echanger les couleurs des lampes d'un même groupe / scène : très utile pour créer des effets guirlande de Noël et des petites animations facile à réaliser dans l'éditeur de groupes / scènes domoticz
Alterner les scènes / groupes : Pour créer des animations plus complexes (en fait une scène / groupe = un temps de l'animation...)
Pour l'installer :
Vous avez besoin de l'utilitaire CURL, vous pouvez télécharger CURL ici s'il n'est pas déjà installé sur votre système. CURL est disponible pour de mulitples plateforme (windows / linux). C'est un utilitaire ligne de commande pour faire des requêtes HTTP (entre autres), mon script l'utilise pour faire des requêtes HTTP synchrones (DZVents propose seulement des requêtes asynchrones). Une fois téléchargé, placez CURL dans le dossier de votre choix et notez le chemin vers CURL, on va en avoir besoin.
Vous devez aussi avoir un script DZVents "global_data". Si vous n'avez pas ce "global_data", rendez vous dans Domoticz dans "Configuration" -> "Plus d'Options" -> "Evénements", cliquez sur "+" et sélectionnez "DZVENTS" -> "GLOBAL DATA". Au lieu de "Script #1" tapez "global_data" (sans les guillemets). Copiez le code ci-dessous et cliquez sur "SAUVEGARDER" (vérifiez les logs de Domoticz s'il n'y a pas d'erreur, il y a quelque fois des problèmes de permissions quand Domoticz sauvegarde les scripts)
Si vous avez un script "global_data", alors vous devez ajouter les fonctions et variables globales que vous trouvez dans le code ci-dessous.
Code : Tout sélectionner
-- this scripts holds all the globally persistent variables and helper functions
-- see the documentation in the wiki
-- NOTE:
-- THERE CAN BE ONLY ONE global_data SCRIPT in your Domoticz install.
return {
-- Variables Globales Persistentes
data = {
-- ANIMATE COLOR VARS --
cancelTransition = { initial = { [0] = nil } }
-- END ANIMATE COLOR VARS --
},
-- Fonction Globales
helpers = {
-- Does the argument is a number
-- x : the value to check
isNumber = function (x)
if tonumber(x) ~= nil then return true end
return false
end,
-- get the color of a light
-- deviceId : IDX or device name
getColor = function(domoticz, deviceId)
local idx = deviceId
if(not domoticz.helpers.isNumber(deviceId)) then idx = domoticz.devices(deviceId).idx end
cmd='"C:\\Program Files (x86)\\Domoticz\\scripts\\lua\\curl.exe" '..domoticz.settings.url..'/json.htm?type=devices^&rid='..idx
local httpRequest = assert(io.popen(cmd))
local html = httpRequest:read('*all')
local json = domoticz.utils.fromJSON(html)
-- adding brigthness to the color object
local color = domoticz.utils.fromJSON(json.result[1].Color)
color.br = domoticz.devices(deviceId).level
-- returning the result
return color
end,
-- ANIMATE COLOR FUNC --
--
cap255 = function(x)
if(x>255) then return 255 end
if(x<=0) then return nil end
return math.floor(x)
end,
cap100 = function(x)
if(x>100) then return 100 end
if(x<=0) then return nil end
return math.floor(x)
end,
-- Transition a light to a new color over time
-- device : light to be transitionned
-- color : the new color and brightness : { ['r']=0, ['g']=0, ['b']=0, ['br']=0, ['cw']=0, ['ww']=0, ['t']=0, ['m']=1/2/3/4 }
-- m = 1, white only br means something, br 0 to 100
-- m = 2, white temp only t mean something, t 0 to 255
-- m = 3, color only r,g,b mean something, rgb 0 to 255
-- m = 4, extended color only r,g,b,cw,ww mean something, cw,ww,rgb 0 to 255
-- duration : duration of the effect in seconds
-- NOTE : if the light is off, no transition is done other
-- than brightness (basically Off = color 0,0,0)
transitionTo = function(domoticz, device, color, duration)
-- compute the number of steps needed
-- minimum duration : 1 sec.
-- max. steps number : 30
local timeLapse = 1
local totalSteps = 30
if(duration >= 30) then
timeLapse = duration / 30
totalSteps = 30
else
timeLapse = 1
totalSteps = duration
end
-- creating array of steps
local startColor = domoticz.helpers.getColor(domoticz, device)
-- special case : device is off
if(domoticz.devices(device).inActive) then
startColor.r = 0
startColor.g = 0
startColor.b = 0
startColor.cw = 0
startColor.ww = 0
startColor.t = 0
startColor.br = 0
end
-- filling the array will all steps states
local colorSteps = { ['next'] = nil, ['color'] = color}
for step = totalSteps,1,-1 do
local stepColor = { ['r']=domoticz.helpers.cap255(startColor.r + (step * (color.r-startColor.r)/totalSteps)),
['g']=domoticz.helpers.cap255(startColor.g + (step * (color.g-startColor.g)/totalSteps)),
['b']=domoticz.helpers.cap255(startColor.b + (step * (color.b-startColor.b)/totalSteps)),
['br']=domoticz.helpers.cap100(startColor.br + (step * (color.br-startColor.br)/totalSteps)),
['cw']=domoticz.helpers.cap255(startColor.cw + (step * (color.cw-startColor.cw)/totalSteps)),
['ww']=domoticz.helpers.cap255(startColor.ww + (step * (color.ww-startColor.ww)/totalSteps)),
['t']=domoticz.helpers.cap255(startColor.t + (step * (color.t-startColor.t)/totalSteps)),
['m']=startColor.m }
colorSteps = { ['next'] = colorSteps, ['color'] = stepColor}
end
-- start the transition effect
domoticz.emitEvent('transitionState', { ['steps'] = colorSteps, ['delay'] = timeLapse, ['device'] = device })
end,
-- make a light blink
-- device : idx or device name to blink
-- color1 : first color { ['r']=0, ['g']=0, ['b']=0, ['br']=0, ['cw']=0, ['ww']=0, ['t']=0, ['m']=1/2/3/4 }
-- color2 : other color (blink = alternate color1 and color2)
-- if one of the color has br=0 or r=0 and g=0 and b=0 then light is turn off (blinking on / off)
-- speed : in seconds time between each color change
-- duration : total duration of the effect in seconds (if 60 : the light will blink for a minute)
blink = function(domoticz, device, color1, color2, speed, duration)
local colorSteps = { ['next'] = color2, ['color'] = color1}
domoticz.emitEvent('alternateState', { ['steps'] = colorSteps, ['delay'] = speed, ['duration'] = duration, ['device'] = device })
end,
-- swap the colors of each light in a group scenes
-- group : idx or name of group / scene
-- speed : in seconds, time between each color change
-- duration : total duration of the effect in seconds
animateGroup = function(domoticz, group, speed, duration)
-- create the list of colors and states of all device in group
-- when the animation starts
local colors = {}
local devices = {}
local count = 0
local idx = nil
if(domoticz.utils.sceneExists(group)) then idx = domoticz.scenes(group).idx
elseif(domoticz.utils.groupExists(group)) then idx = domoticz.groups(group).idx end
-- We have a valid group or scene
if(idx) then
-- get the devices and state in the group / scene
local cmd='"C:\\Program Files (x86)\\Domoticz\\scripts\\lua\\curl.exe" '..domoticz.settings.url..'/json.htm?type=command^¶m=getscenedevices^&isscene=true^&idx='..idx
local httpRequest = assert(io.popen(cmd))
local html = httpRequest:read('*all')
local json = domoticz.utils.fromJSON(html)
-- results are valid JSON
if(json.status == 'OK') then
-- review each device and store its id and state (color / on/off...) in array
for i, device in ipairs(json.result) do
count = count + 1
-- device ID
devices[count] = device.DevID
-- device state : color / on/off / Level
if(device.Color) then device.Color = domoticz.utils.fromJSON(device.Color) end
if(device.Color) then device.Color.br = device.Level else device.Color = { ['br'] = device.Level } end
-- if device is not On then the device is off, we simplify by stating its brightness is 0
if(device.Command == "On") then colors[count] = device.Color else colors[count] = { ['br'] = 0 } end
end
end
end
-- starting the transition
domoticz.emitEvent('switchState', { ['devices'] = devices, ['colors'] = colors, ['step'] = 0, ['delay'] = speed, ['duration'] = duration })
end,
-- alternate scenes : change a scene each xx sec.
-- scenes : scenes / groups array to alternat ex : {'Scene 1', 'Scene 2', 'Scene 3'}
-- speed : in seconds, time between each scene change
-- duration : total duration of the effect in seconds
animateScenes = function(domoticz, scenes, speed, duration)
domoticz.emitEvent('sceneChangeState', { ['scenes'] = scenes, ['step'] = 0, ['delay'] = speed, ['duration'] = duration })
end,
-- cancel a running transition
-- work only for "transitionTo" et "blink"
cancelTransition = function(domoticz, device)
if(not domoticz.helpers.isNumber(device)) then device = domoticz.devices(device).id end
-- signal the transition to end early
domoticz.globalData.cancelTransition[device] = true
end,
--
-- END ANIMATE COLOR FUNC
}
}
cmd='"C:\\Program Files (x86)\\Domoticz\\scripts\\lua\\curl.exe" '..domoticz.settings.url..'/json.htm?type=devices^&rid='..idx
Remplacez ce chemin par le vôtre.
Lorsque c'est fait il faut ensuite créer le script principal : dans l'éditeur de scripts, cliquez sur "+" puis sélectionnez "DZVENTS" -> "CUSTOM EVENTS", donnez lui le nom que vous voulez à la place de "Script #1", par exemple "Transition Etat" (attention pas d'accents etc.. sinon ça coince), copiez / collez le code ci-dessous et cliquez sur "SAUVEGARDER".
Code : Tout sélectionner
return {
on = { customEvents = { 'transitionState', 'alternateState', 'switchState', 'sceneChangeState' } },
logging = { level = domoticz.LOG_ERROR,
marker = 'TRANSITION STATE', },
execute = function(domoticz, item)
-- TRANSITION
if (item.isCustomEvent and item.trigger == 'transitionState') then
-- Get JSON in event data
local eventData = domoticz.utils.fromJSON(item.data)
-- should we cancel our transition ?
local deviceId = domoticz.devices(eventData.device).id
if(domoticz.globalData.cancelTransition[deviceId]) then
domoticz.globalData.cancelTransition[deviceId] = nil
return
end
-- color data for the transition
local currentColor = eventData.steps.color
local nextColorSteps = eventData.steps.next
-- checking colors values (we use nil instead of 0
-- as it shortens the string for the custom event)
if(not currentColor.r) then currentColor.r = 0 end
if(not currentColor.g) then currentColor.g = 0 end
if(not currentColor.b) then currentColor.b = 0 end
if(not currentColor.br) then currentColor.br = 0 end
if(not currentColor.cw) then currentColor.cw = 0 end
if(not currentColor.ww) then currentColor.ww = 0 end
if(not currentColor.t) then currentColor.t = 0 end
-- setting color / state
if(domoticz.devices(eventData.device).deviceType == 'Color Switch') then
domoticz.helpers.setColor(domoticz, eventData.device,
currentColor.r,currentColor.g,currentColor.b,
currentColor.br,
currentColor.cw,currentColor.ww,
currentColor.m,currentColor.t)
elseif(domoticz.devices(eventData.device).switchType =='Dimmer') then
domoticz.devices(eventData.device).dimTo(currentColor.br)
end
-- schedule next transition
if(nextColorSteps) then
domoticz.emitEvent('transitionState', { ['steps'] = nextColorSteps, ['delay'] = eventData.delay, ['device'] = eventData.device }).afterSec(eventData.delay)
end
end
-- BLINKING
if (item.isCustomEvent and item.trigger == 'alternateState') then
-- Get JSON in event data
local eventData = domoticz.utils.fromJSON(item.data)
-- should we cancel our transition ?
if(eventData.duration <= 0) then return end
local deviceId = domoticz.devices(eventData.device).id
if(domoticz.globalData.cancelTransition[deviceId]) then
domoticz.globalData.cancelTransition[deviceId] = nil
return
end
-- color date for the transition
local currentColor = eventData.steps.color
local nextColorSteps = eventData.steps.next
-- swappping
eventData.steps.color = nextColorSteps
eventData.steps.next = currentColor
-- reducing duration
eventData.duration = eventData.duration - eventData.delay
-- checking colors values (we use nil instead of 0
-- as it shortens the string for the custom event)
if(not currentColor.r) then currentColor.r = 0 end
if(not currentColor.g) then currentColor.g = 0 end
if(not currentColor.b) then currentColor.b = 0 end
if(not currentColor.br) then currentColor.br = 0 end
if(not currentColor.cw) then currentColor.cw = 0 end
if(not currentColor.ww) then currentColor.ww = 0 end
if(not currentColor.t) then currentColor.t = 0 end
-- setting color / state
if((currentColor.r == 0 and currentColor.g == 0 and currentColor.b == 0 and currentColor.m == 3) or
(currentColor.br == 0)) then
domoticz.devices(eventData.device).switchOff()
elseif(domoticz.devices(eventData.device).deviceType == 'Color Switch') then
domoticz.helpers.setColor(domoticz, eventData.device,
currentColor.r,currentColor.g,currentColor.b,
currentColor.br,
currentColor.cw,currentColor.ww,
currentColor.m,currentColor.t)
elseif(domoticz.devices(eventData.device).switchType =='Dimmer') then
domoticz.devices(eventData.device).dimTo(currentColor.br)
end
--scheduling next event
domoticz.emitEvent('alternateState', { ['steps'] = eventData.steps, ['delay'] = eventData.delay, ['duration'] = eventData.duration, ['device'] = eventData.device }).afterSec(eventData.delay)
end
-- GROUP SWAPPING
if (item.isCustomEvent and item.trigger == 'switchState') then
-- Get JSON in event data
local eventData = domoticz.utils.fromJSON(item.data)
-- should we cancel our transition ?
if(eventData.duration <= 0) then return end
-- compute number of steps
local colorCount = 0
for i, color in ipairs(eventData.colors) do
colorCount = colorCount + 1
end
-- setting color and state
-- enum devices and choose state based on step number
for i, deviceId in ipairs(eventData.devices) do
deviceId = tonumber(deviceId)
if(eventData.step >= colorCount) then eventData.step = 0 end
local colorIndex = i + eventData.step
if(colorIndex > colorCount) then colorIndex = colorIndex - colorCount end
if(eventData.colors[colorIndex].br == 0)then
-- turning off
domoticz.devices(deviceId).switchOff()
elseif(eventData.colors[colorIndex].m) then
-- set color if device is capable of color
if(domoticz.devices(deviceId).deviceType == 'Color Switch') then
domoticz.devices(deviceId).setColor(eventData.colors[colorIndex].r,eventData.colors[colorIndex].g,eventData.colors[colorIndex].b,
eventData.colors[colorIndex].br,
eventData.colors[colorIndex].cw,eventData.colors[colorIndex].ww,
eventData.colors[colorIndex].m,eventData.colors[colorIndex].t)
else
-- at least set brightness or turn the device on...
if(domoticz.devices(deviceId).switchType =='Dimmer') then
domoticz.devices(deviceId).Level = eventData.colors[colorIndex].br
else
domoticz.devices(deviceId).switchOn()
end
end
else
-- set level / turning on
if(domoticz.devices(deviceId).switchType =='Dimmer') then
domoticz.devices(deviceId).Level = eventData.colors[colorIndex].br
else
domoticz.devices(deviceId).switchOn()
end
end
end
-- schedule next transition
domoticz.emitEvent('switchState', { ['devices'] = eventData.devices, ['colors'] = eventData.colors, ['step'] = eventData.step + 1, ['delay'] = eventData.delay, ['duration'] = eventData.duration - eventData.delay }).afterSec(eventData.delay)
end
-- CHANGEMENT DE SCENE
if (item.isCustomEvent and item.trigger == 'sceneChangeState') then
-- Get JSON in event data
local eventData = domoticz.utils.fromJSON(item.data)
-- should we cancel our transition ?
if(eventData.duration <= 0) then return end
-- compute number of steps
local sceneCount = 0
for i, scene in ipairs(eventData.scenes) do
sceneCount = sceneCount + 1
end
-- selecting scene to apply / group to turn on
if(eventData.step >= sceneCount) then eventData.step = 0 end
local sceneIndex = 1 + eventData.step
if(sceneIndex > sceneCount) then sceneIndex = sceneIndex - sceneCount end
-- applying
if(domoticz.utils.sceneExists(eventData.scenes[sceneIndex])) then
domoticz.scenes(eventData.scenes[sceneIndex]).switchOn()
elseif(domoticz.utils.groupExists(eventData.scenes[sceneIndex])) then
domoticz.groups(eventData.scenes[sceneIndex]).switchOn()
end
-- schedule next transition
domoticz.emitEvent('sceneChangeState', { ['scenes'] = eventData.scenes, ['step'] = eventData.step + 1, ['delay'] = eventData.delay, ['duration'] = eventData.duration - eventData.delay }).afterSec(eventData.delay)
end
end
}
domoticz.helpers.transitionTo(domoticz, device, color, duration)
Change progressivement la couleur de l'ampoule vers la nouvelle couleur. Vous pouvez choisir la durée de l'effet (en secondes). La couleur est dans le format habituel { ['r']=0, ['g']=0, ['b']=0, ['br']=0, ['cw']=0, ['ww']=0, ['t']=0, ['m']=1/2/3/4 }.
Vous pouvez effectuer une transition vers l'état éteint simplement en utilisant la couleur noir ou la luminosité à 0.
domoticz.helpers.blink(domoticz, device, color1, color2, speed, duration)
Fait clignoter une lumière. On peut choisir deux couleurs à alterner ainsi que la vitesse de changement et la durée totale du clignotement. Si une des couleurs est noire ou que la luminosité est à 0 alors un clignotement allumé / éteint est effectué.
domoticz.helpers.animateGroup(domoticz, group, speed, duration)
Echange la couleur de chaque lampe au sein d'un groupe / scène. Vous pouvez choisir la vitesse et la durée de l'effet
domoticz.helpers.animateScenes(domoticz, scenes, speed, duration)
Alterne les scènes / groupes : Change de scène toutes les xx secondes. Vous choisissez xx (speed) et la durée totale de l'effet. C'est un tableau de scènes / groupes qu'il faut donner
domoticz.helpers.cancelTransition(domoticz, device)
Annule une animation en cours pour une ampoule. Ne fonctionne qu'avec blink et transitionTo.