Page 1 sur 1

[DzVents] Stocker et restaurer l'état d'une ampoule (couleur / luminosité etc...)

Publié : 11 août 2021, 18:11
par StephaneM
Salut

Je partage avec vous ce script DZVents de mon cru : un mécanisme pour stocker et restaurer l'état d'une ampoule (tous les types de lumières, y compris les interrupteurs, si je suis passé à côté de quelque chose faites le moi savoir)

Par exemple : Vos ampoules éclairent faiblement en bleu, puis vous voulez les allumer en blanc à 100% parce qu'une porte s'est ouverte ou au passage devant un détecteur de mouvement.

Après quelques instants (minutes / secondes) vous voulez que les ampoules retournent à leur état précédent : éclaire en bleu faiblement.

Le script que je vous propose offre des fonctions partagées globales que vous pouvez utiliser dans vos propres scripts DZVents

Par exemple un script DZVents pour un détecteur de mouvement :

Code : Tout sélectionner

return {
	on = {
		devices = { 'Détecteur Mouvement' },
	},
	
	logging = {
		level = domoticz.LOG_INFO,
		marker = 'MOTION SENSOR TEST',
	},
	
	execute = function(domoticz, device)
	    -- Passe l'ampoule en blanc à 100% pendant une minute
	    -- puis restaure l'état qu'elle avait avant le changement
	    if(device.isDevice) then

		-- Stocke l'état actuel de l'ampoule et programme sa restautation dans 1 minutes (60 sec.)
		domoticz.helpers.restoreStateAfter(domoticz, 'Mon Ampoule', 60)

		-- Change la couleur de l'ampoule (blanc / 100% luminosité)
                domoticz.devices('Mon Ampoule').setColor(0,0,0,100,0,0,2,128)

	    end

	end
}
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. So if

return {
	-- Persistent Global Variables
	data = { 
	         -- RESTORE STATE VARS --
	         previousStates = { initial = { [0] = nil } },
	         -- END RESTORE STATE VARS

	         },

	-- Global Functions
	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,
	    
	    -- RESTORE STATE FUNC --
		
	    -- store the state of a light
	    -- domoticz : domoticz object
	    -- deviceName : device name
	    -- holdFor : validity of the state. if nil the state can be restored at anytime, otherwise state can be restored upto the "holdFor" duration (in seconds)
	    storeState = function(domoticz, deviceName, holdFor)
	        -- Get the device ID
	        local device = domoticz.devices(deviceName)
			local deviceId = device.id
			domoticz.log('Sotring state for device :'..deviceName, domoticz.LOG_INFO)
			-- time when the state will expire (ie : when it should be restored)
			local validTill
			local storeState = true
			local checkStates = false
			if(holdFor == nil) then validTill = nil else validTill = domoticz.time.addSeconds(holdFor).dDate end
			-- should we store this new state
			if(validTill ~= nil) then
			    -- we know when this state must end, we have
			    -- to check that the previous state should end
			    -- before this new one
			    local lastState = domoticz.globalData.previousStates[deviceId]
			    if(lastState ~= nil) then
			        if(lastState.value.validTill == nil) then
			            -- nok : our time is supposed to be past
			            -- the one already stored
			            -- we change the date of the stored state by
			            -- the date of the new state
			            lastState.value.validTill = validTill
			            storeState = false
			            checkStates = true
			        elseif(lastState.value.validTill > validTill) then
			            -- ok our date is past the date of the
			            -- already stored state
			            storeState = true
			        elseif(lastState.value.validTill <= validTill) then
			            -- nok our date is before the date of
			            -- the already stored state
			            -- we change the date of the stored state by
			            -- the one of the new state
			            lastState.value.validTill = validTill
			            storeState = false
			            checkStates = true
			        end
			    end
			else
			    -- we dont know the duration of the state we are storing
			    -- so we cannot store this state if one state is already stored
			    if(domoticz.globalData.previousStates[deviceId] ~= nil) then storeState = false end
			end
			
			-- checking if states are not conflicting
			while(checkStates) do
			    checkStates = false
			    local lastState = domoticz.globalData.previousStates[deviceId]
			    while(lastState.next ~= nil) do
			        if((lastState.next.value.validTill == nill) or
			           (lastState.next.value.validTill <= lastState.value.validTill)) then
			            -- current state will expire before next state
			            -- replacing expiration time of next state by current
			            lastState.next.value.validTill = lastState.value.validTill
			            -- deleting current state
			            lastState.next = lastState.next.next
			            lastState.value = lastState.next.value
			            domoticz.globalData.previousStates[deviceId] = lastState
			            -- need one more pass to check conflicts
			            checkStates = true
			        else
			            -- all is ok no need to continue
			            break
			        end 
			    end
			end
			
			if(storeState) then
			    -- storing state (on/off)
			    local currentState = { ['validTill'] = validTill, ['state'] = 'Off', ['color'] = nil }
			    currentState.state = device.state
		        -- storing color (when RGB+ device)
		        if(device.deviceType == 'Color Switch') then
		            local color = domoticz.helpers.getColor(domoticz, device.idx)
		            currentState.color = color
	            else
	                if(device.switchType == 'Dimmer') then
	                    --storing brightness level
	                    currentState.color = {['br'] = device.level }
	                end
                end
                -- push device state in the states linked list
                domoticz.log('Stored state for device '..deviceId..' : '..domoticz.utils.toJSON(currentState), domoticz.LOG_INFO)
                domoticz.globalData.previousStates[deviceId] = { next = domoticz.globalData.previousStates[deviceId], value = currentState }
            end
	    end,
	    
	    -- restore a device state (if a stored state exists)
	    -- deviceName : idx or device name to restore
	    restoreState = function(domoticz, deviceName)
	        -- get device ID
			local deviceId = domoticz.devices(deviceName).id
	        -- ask for device state restoration now (custom event)
	        domoticz.emitEvent('restoreState', deviceId)
	    end,
	    
	    -- store the current state (color / power) of light and schedule its restoration
	    -- deviceName = idx / device name (light or switch)
	    -- holdFor = time in seconds before restoring the state
		restoreStateAfter = function(domoticz, deviceName, holdFor)
		    -- get device ID
		    local deviceId = domoticz.devices(deviceName).id
		    -- store device state with "holdFor" lifetime
		    domoticz.helpers.storeState(domoticz, deviceName, holdFor)
	        -- schedule device restoration in "holdFor" sec.
	        domoticz.emitEvent('restoreState', deviceId).afterSec(holdFor)
		end,
		
		-- clear the stored state of a device, canceling its future restoration
	    -- this is useful to prevent light to turn back on when you want them
	    -- to stay off and don't know if a state is about to be restored.
		-- deviceName = idx or device name
		cancelRestoreState = function(domoticz, deviceName)
		    -- get device ID
		    local deviceId = domoticz.devices(deviceName).id
		    domoticz.log('Cancel stored states for device '..deviceId, domoticz.LOG_INFO)
		    -- clear all stored device states
		    domoticz.globalData.previousStates[deviceId] = nil
	    end
		-- END RESTORE STATE FUNC
	}
}

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 "Restauration 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 = { 'restoreState' } },
	
	logging = { level = domoticz.LOG_INFO, 
	            marker = 'RESTORE STATE', },
	        
	execute = function(domoticz, item)
	    
	    -- Restore State
	    if(item.isCustomEvent) then
	        
            -- Custom Event = restoreState
	        if(item.trigger == 'restoreState') then
	            -- Get the ID of the device to restore state
	            local deviceId = tonumber(item.data)
	            domoticz.log('Restore state for device '..item.data, domoticz.LOG_INFO)
	            
	            -- if the stored state had a validTill date
	            -- greater that the current time : we do nothing
	            -- because we expect to restore this state at a later time
	            local lastState = nil
	            if(domoticz.globalData.previousStates[deviceId]) then
	                lastState = domoticz.globalData.previousStates[deviceId].value
	                if(lastState.validTill ~= nil and
	                    lastState.validTill > domoticz.time.dDate) then
	                    domoticz.log('State restoration delayed', domoticz.LOG_INFO)
	                    return
	                end
	            end
	            -- we have a state to restore
	            if(lastState ~= nil) then
	                -- restoring previous state
	                domoticz.log('State to restore for device '..deviceId..' : '..domoticz.utils.toJSON(lastState), domoticz.LOG_INFO)
	                if(lastState.state ~= 'Off') then
	                    if(domoticz.devices(deviceId).deviceType == 'Color Switch' and lastState.color ~= nil) then
	                        -- color device : restoring color / white level as well as brightness
	                        domoticz.devices(deviceId).setColor(lastState.color.r, lastState.color.g, lastState.color.b,
	                                                            lastState.color.br,
	                                                            lastState.color.cw, lastState.color.ww,
	                                                            lastState.color.m, lastState.color.t)
                        else
                            -- restoring brightness only
	                        domoticz.devices(deviceId).switchOn()
	                        if(domoticz.devices(deviceId).switchType=='Dimmer' and lastState.color ~= nil) then
	                            domoticz.devices(deviceId).dimTo(lastState.color.br)
	                        end
	                    end
                    else
                        -- restoring power state only
	                    domoticz.devices(deviceId).switchOff()
	                end
	                -- clean up stored states
	                domoticz.globalData.previousStates[deviceId] = domoticz.globalData.previousStates[deviceId].next
	            else
	                domoticz.log('No stored state found', domoticz.LOG_INFO)
	            end
	       end
	      
	    end
	end
}
Désormais dans vos scripts vous pouvez utiliser les fonctions suivantes :

domoticz.helpers.storeState(domoticz, deviceName, holdFor)
Pour stocker l'état actuel de l'ampoule/switch deviceName, holdFor c'est le temps en secondes au bout duquel l'état doit être restauré. Par exemple si vous stockez l'état d'un ampoule parce que vous changez temporairement sa couleur pendant 1 minute après détection d'un mouvement, holdFor est égal à 60 secondes. Si vous ne savez pas quand l'état doit être restauré alors utilisez nil.

Vous pouvez utiliser cette fonction plusieurs fois pour la même ampoule, car de mulitples états peuvent être stockés. Le script se débrouille tout seul pour savoir si oui ou non l'état doit être stocké (justement en utilisant holdFor)


domoticz.helpers.restoreState(domoticz, deviceName)
Restaure l'état de l'ampoule deviceName. Plusieur étant pouvant être stockés, Le script choisi lui même quelle état restaurer (bien souvent c'est dernier stocké, dernier restaurés mais pas tout le temps)

domoticz.helpers.restoreStateAfter(domoticz, deviceName, holdFor)
Stocke l'état de l'ampoule et programme sa restauration dans holdFor secondes. Habituellement juste après l'appel à cette fonction, vous llez changer l'état de l'ampoule (couleur / luminosité / alimentation)

domoticz.helpers.cancelRestoreState(domoticz, deviceName)
Efface tous les états stockés pour l'ampoule deviceName. Ceci empêche toute restauration d'état pour cette ampoules qui aurait été programmé avant. Cette fonction s'utilise principalement lorsque vous éteignez une ampoule et que vous souhaitez vraiement qu'elle reste éteinte.