Page 1 of 1

blind percentage position

Posted: Tuesday 02 October 2018 11:07
by megamarco83
hi, i have an nodemcu where i flash espeasy and i connect 2 relays for my blind: 1relay to UP, and 1relay to DOWN
i have also connect 2 wall switch: 1 switch UP 1switch DOWN
in EspEasy rules i create a rule to identify short press or longpress (pression >= 4seconds of wall swith)
if i use shorpres the corrisponding relay is active for 1sec. if i use longpress the corresponding relay is acrived for 46sec. (46sec. = time to all open or all close the blind)
domoticz is ablo to recognize the moviment UP or DOWN if i use wall switch thanks to command inside domoticz blind switch:

http://192.168.0.154/control?cmd=event, ... N_domoticz
http://192.168.0.154/control?cmd=event, ... P_domoticz

now i want to recognize the position of the blind i have in mind to monitoring the seconds, starting from the activation of the switch. for example the idea is:

starting from all close -> i longress UP on wall swith (relay start to UP with a time of 46sec) -> after 15sec i want to stop my blind i press DOWN shortpress on the wall switch and the blind stop in that position that i choose -> script in domoticz should have counting this 15sec passed and give to domoticz that result: (15sec / 46sec ) * 100= 36% and show on the blind with percentage open 36%

if i use a shortpress wall switch -> i will activate the relay for 1sec -> send to domoticz the value 1sec -> domoticz calcolate (1sec / 46 sec) * 100 = 2% open

if i use again a shorpress from wall swith -> domoticz activate the relay for 1sec -> domoticz calcolate (1sec / 46 sec) * 100 = 2% open + 2% of previous position = 4%open


how i can implement that?

Re: blind percentage position

Posted: Tuesday 02 October 2018 14:53
by waaren
megamarco83 wrote: Tuesday 02 October 2018 11:07 ...I want to recognize the position of the blind i have in mind to monitoring the seconds, starting from the activation of the switch. for example the idea is:

starting from all close -> i longress UP on wall swith (relay start to UP with a time of 46sec) -> after 15sec i want to stop my blind i press DOWN shortpress on the wall switch and the blind stop in that position that i choose -> script in domoticz should have counting this 15sec passed and give to domoticz that result: (15sec / 46sec ) * 100= 36% and show on the blind with percentage open 36%
...
I played a little bit with the idea.
This script uses the lastupdate.secondsAgo and state attribute of the blind to estimate the position. Script is not
complete nor failsafe but might help you in design and develop process.

Code: Select all

local blindCheckVar = "checkBlindState"                -- type string; need to be created manually
local blindIDX      = 296                              -- idx of your blind 

return {
    on      =   {   devices   =   { blindIDX },
                    variables =   { blindCheckVar }},
                
    logging =   {   level     =   domoticz.LOG_DEBUG,
                    marker    =   "Blinds position"    },

    data    =   {   action    = { initial = "Open" },                  -- device.state  
                    active    = { initial = 0 },                       -- information only 
                    position  = { initial = 0  }},                     -- 0 = open / 100 = closed
                    
    execute = function(dz, item )
        local maxActionTime = 46
        local blind         = dz.devices(blindIDX)
        local idleTime      = blind.lastUpdate.secondsAgo
        
        local function updatePersistent(action,active,position)
            dz.data.position = dz.utils.round(math.max(math.min(position,100),0)) or dz.data.position  
            dz.data.active   = active or dz.data.active
            dz.data.action   = action or dz.data.action
        end
        
        -- This block will be triggered by the var change and will set
        -- the position to completely Open or completely Closed when no stop Command is received
        if item.isVariable then
            if idleTime > maxActionTime then
                if dz.data.action == "Open" then 
                    updatePersistent("Stopped",idleTime,0)
                elseif dz.data.action == "Closed" then
                    updatePersistent("Stopped",idleTime,100)
                end
            end
            return
        end    
        
        -- This block will do the actual calculation
        local position = dz.data.position
        if    blind.state == "Stopped"  or
            ( blind.state == "Open"     and dz.data.action == "Closed" ) or 
            ( blind.state == "Closed"   and dz.data.action == "Open"   ) then
            local factor = 1
            if dz.data.action == "Open" then
                factor = -1
            end
            position = dz.data.position + factor * (( idleTime )  * ( 100/maxActionTime ))
        end
        updatePersistent(blind.state,idleTime,position)
        
        -- Next if block will schedule an update of a uservariable that will force 
        -- a trigger of this script even when no stop command is given
        if blind.state == "Open" or blind.state == "Closed" then
            local timeRemains = dz.data.position/100 * maxActionTime  
            if blind.state == "Closed" then
                timeRemains = maxActionTime - timeRemains
            end
            dz.variables(blindCheckVar).set(blind.state).afterSec(timeRemains + 3) 
        end
       
    end
}

Re: blind percentage position

Posted: Tuesday 02 October 2018 23:15
by megamarco83
waaren wrote: Tuesday 02 October 2018 14:53
I played a little bit with the idea.
wow thanks so much!!!!
i try to adapt your code and i create this:
i create a user var as string named: "checkBlindState"
variabili.jpg
variabili.jpg (89.29 KiB) Viewed 3495 times
this is my blind with percentage switch, that as id=31
idx31.jpg
idx31.jpg (23.52 KiB) Viewed 3495 times
and this is what is inside:
blind command.jpg
blind command.jpg (31.09 KiB) Viewed 3495 times
this is your code:

Code: Select all

local blindCheckVar = "checkBlindState"                -- type string; need to be created manually
local blindIDX      = 31                             -- idx of your blind 

return {
    on      =   {   devices   =   { blindIDX },
                    variables =   { blindCheckVar }},
                
    logging =   {   level     =   domoticz.LOG_DEBUG,
                    marker    =   "Blinds position"    },

    data    =   {   action    = { initial = "Open" },                  -- device.state  
                    active    = { initial = 0 },                       -- information only 
                    position  = { initial = 0  }},                     -- 0 = open / 100 = closed
                    
    execute = function(dz, item )
        local maxActionTime = 10  -- seconds to completly the action (10 for test)
        local blind         = dz.devices(blindIDX)
        local idleTime      = blind.lastUpdate.secondsAgo
        
        local function updatePersistent(action,active,position)
            dz.data.position = dz.utils.round(math.max(math.min(position,100),0)) or dz.data.position  
            dz.data.active   = active or dz.data.active
            dz.data.action   = action or dz.data.action
        end
        
        -- This block will be triggered by the var change and will set
        -- the position to completely Open or completely Closed when no stop Command is received
        if item.isVariable then
            if idleTime > maxActionTime then
                if dz.data.action == "Open" then 
                    updatePersistent("Stopped",idleTime,0)
                elseif dz.data.action == "Closed" then
                    updatePersistent("Stopped",idleTime,100)
                end
            end
            return
        end    
        
        -- This block will do the actual calculation
        local position = dz.data.position
        if    blind.state == "Stopped"  or
            ( blind.state == "Open"     and dz.data.action == "Closed" ) or 
            ( blind.state == "Closed"   and dz.data.action == "Open"   ) then
            local factor = 1
            if dz.data.action == "Open" then
                factor = -1
            end
            position = dz.data.position + factor * (( idleTime )  * ( 100/maxActionTime ))
        end
        updatePersistent(blind.state,idleTime,position)
        
        -- Next if block will schedule an update of a uservariable that will force 
        -- a trigger of this script even when no stop command is given
        if blind.state == "Open" or blind.state == "Closed" then
            local timeRemains = dz.data.position/100 * maxActionTime  
            if blind.state == "Closed" then
                timeRemains = maxActionTime - timeRemains
            end
            dz.variables(blindCheckVar).set(blind.state).afterSec(timeRemains + 3) 
        end
       
    end
}
i used just to test 10seconds to simulate a completly moviment of blind
so also in ESPeasy on nodemcu i changed:
shor press down wall switch = 2sec DOWN
short press UP wall switch = 2 sec UP
long press DOWN wall switch = 10 sec down
long press UP wall switch = 10 sec UP

if i press domoticz UP = 10 sec UP relay is activation
if i press domoticz DOWN = 10sec DOWN relay down activation
so all is ok, now related to the percentage:

i started to all close (domoticz 0%) then i short press wall switch UP -> 2sec activation relay UP -> i see in domoticz 40% open (why?!?!?) (the string checkBlindState is closed)
then i short press again wall switch UP-> 2sec activation relay UP -> i see again in domoticz 40% open (same as previous) (the user string checkBlindState is closed)
then i long press again wall switch UP -> 10sec activation relay UP -> i see in domoticz 100% open (the user string checkBlindState now is open)
when i short press wall switch DOWN -> 2sec activation relay DOWN -> i see again in domoticz 0% (all close) (the user string checkBlindState is closed)
when i long press wall switch DOWN -> 10sec activation relay DON -> i see in domoticz 0% (all close) (the user string checkBlindState is closed again)

i do not understand....

if it's needed this is my ESP rules:

Code: Select all

on B_UP#Shortpress do
 if [relayp#R_UP]>0
  output,relayp,0,0
 else
  output,relayp,1,0
  output,relayp,0,1
SendToHTTP 192.168.0.105,8085,/json.htm?type=command&param=switchlight&idx=31&switchcmd=Set%20Level&level=40
  timerset,1,2
 endif 
endon

on B_UP#Longpress do
event,event_UP_domoticz
endon

on event_UP_domoticz do
 if [relayp#R_UP]>0
  output,relayp,0,0
 else
  output,relayp,1,0
  output,relayp,0,1
  timerset,1,10   // 10 sec as test to simulate completly UP
SendToHTTP 192.168.0.105,8085,/json.htm?type=command&param=udevice&idx=31&nvalue=1&svalue=40
 endif 
endon

on B_DOWN#Shortpress do
 if [relayp#R_DOWN]>0
  output,relayp,1,0
 else
  output,relayp,0,0
  output,relayp,1,1
SendToHTTP 192.168.0.105,8085,/json.htm?type=command&param=switchlight&idx=31&switchcmd=Set%20Level&level=0
 endif 
endon

on B_DOWN#Longpress do
event,event_DOWN_domoticz
endon

on event_DOWN_domoticz do
 if [relayp#R_DOWN]>0
  output,relayp,1,0
 else
  output,relayp,0,0
  output,relayp,1,1
  timerset,2,10   // 10 sec as test to simulate completly DOWN
SendToHTTP 192.168.0.105,8085,/json.htm?type=command&param=udevice&idx=31&nvalue=0&svalue=0
 endif 
endon


on Rules#Timer=1 do
 output,relayp,0,0
endon

on Rules#Timer=2 do
 output,relayp,1,0
endon 
where i have:
gpio15= relay UP
gpio12= relay DOWN
gpio1 = wall switch UP
gpio3 = wall switch DOWN

Re: blind percentage position

Posted: Wednesday 03 October 2018 0:28
by waaren
megamarco83 wrote: Tuesday 02 October 2018 23:15
waaren wrote: Tuesday 02 October 2018 14:53 I played a little bit with the idea.
short press down wall switch = 2sec DOWN
short press UP wall switch = 2 sec UP
long press DOWN wall switch = 10 sec down
long press UP wall switch = 10 sec UP

I do not understand....
The script is created for a Blind that return "Open", "Closed" or "Stopped" as state.
The %-age "Open" is calculated when a "Stop" command is received or when the time until max. Open or Close has passed (controlled by the afterSeconds command mode)
The script is now just to give an idea. It does not update anything else than the uservariable and dzVents persistent data.
I am a bit busy the next couple of weeks but after that I am happy to look at it again. Probably better to discuss via PM and come back here if /when we have something working. OK ?

Re: blind percentage position

Posted: Wednesday 03 October 2018 8:08
by emme
be aware that time for rolling up could be NOT the same for rolling down... due to forces, gravity and performances of the actuator. ;)

you'd better evaluate to split timers into 2 different values

Re: blind percentage position

Posted: Wednesday 03 October 2018 8:27
by waaren
emme wrote: Wednesday 03 October 2018 8:08 be aware that time for rolling up could be NOT the same for rolling down... due to forces, gravity and performances of the actuator. ;)
you'd better evaluate to split timers into 2 different values
Thx. Will keep that in mind

Re: blind percentage position

Posted: Wednesday 03 October 2018 9:28
by megamarco83
emme wrote: Wednesday 03 October 2018 8:08 be aware that time for rolling up could be NOT the same for rolling down... due to forces, gravity and performances of the actuator. ;)

you'd better evaluate to split timers into 2 different values
yes, true. i misured both time UP and DOWN and i have a difference that is only 2 sec, but you are true, if we want to generalize for other person (and i think that is very usefull for many person) is better to follow your suggestion and using 2 timers
thanks!

Re: blind percentage position

Posted: Wednesday 03 October 2018 9:32
by megamarco83
waaren wrote: Wednesday 03 October 2018 0:28
The script is created for a Blind that return "Open", "Closed" or "Stopped" as state.
The %-age "Open" is calculated when a "Stop" command is received or when the time until max. Open or Close has passed (controlled by the afterSeconds command mode)
The script is now just to give an idea. It does not update anything else than the uservariable and dzVents persistent data.
I am a bit busy the next couple of weeks but after that I am happy to look at it again. Probably better to discuss via PM and come back here if /when we have something working. OK ?
ok, no problem for me, that's fantastic
i PM you with my contact, then if we succeed i will write here, i think that could be very usefull for many users!
keep in touch, in the meanwhile i'll try to do some tests (i'm a beginner, so very very small steps contribution from my side )
thanks for your kindness as usual

Re: blind percentage position

Posted: Thursday 13 December 2018 11:38
by DewGew
Any progress with this script? I need this..:)

Re: blind percentage position

Posted: Thursday 13 December 2018 23:12
by waaren
DewGew wrote: Thursday 13 December 2018 11:38 Any progress with this script? I need this..:)
The script is ready and in use but probably not generic enough to share with a wide audience. I attach it here but I cannot give much support on it.
I will try to answer questions to clarify but will not make modifications. So use it at it is and make the necessary adjustments for your specific situation yourself.
@megamarco83 can share the detailed rules and settings necessary in the nodemcu but in short you will have to setup MQTT as communication and listen to incoming MQTT messages and set the attached relais accordingly.

Have Fun !

Code: Select all

--[[     this scripts handles two way commmunication between domoticz and nodemcu / relais
     *** nodemcu to domoticz: nodemcu update the (type string) uservariable blindControl with an MQTT command json string like
         
        Publish domoticz/in,{"command":"setuservariable","idx":55,"value":"blind_1;Up;42"}     -- testJSON up
        Publish domoticz/in,{"command":"setuservariable","idx":55,"value":"blind_1;Down;2"}    -- testJSON down
          
         dzVents will pickup the variable and set the virtual blind accordingly
         
     *** domoticz to relais :  dzVents is triggered by a change (open / close / On / Off and setting a percentage with the slider )in any device with a name 
                               that starts with "blind_", it will calculate the number of equivalent seconds and the direction and send that together 
                               with the name of the device back to nodemcu with an MQTT command
                               the constructed OS command to send the MQTT message looks like:  
        
        mosquitto_pub -t LM46_213/blind_1_Down -m 1
        
        The OS Command to send the off signal is scheduled for after n seconds using a delayed URL    
                         
         the description field of the virtual blind contain the necessary information to identify the nodemcu and the settings there.
         Layout: {"nodemcu":"LM46_213","maxUpTime":"42","maxDownTime":"36"}
         
        some history (last action per device and last nodemcu action will be maintained in 
        dzVenst persistent data. Lay-out in  domoticzdir/scripts/dzVents/data/__data_scriptname.lua
        also in persistent data is per blind a line setting the until blocktime (in seconds from epoch)
        
        MQTT messages can be monitored on the CLI with mosquitto_sub -F "%U - %t - %p" -v -h <broker IP or broker DNS name> -p 1883 -t '#'
        


]] --

return {
    -- active = false,
    
    on      =   {   devices         =   { "blind_*"  },
                    variables       =   { "blindControl" },
                    httpResponses   =   { "nodemcu_*"              }},     -- wildcard
                
    logging =   {   level           =   domoticz.LOG_DEBUG,
                    marker          =   "MQTT Blindposition"    },
                    
    data    =   {   blinds          = { initial = {}  },
                    commands        = { history = true, maxItems = 10 },
                },

    execute = function(dz, item, info )
       
        _G.logMarker             = info.scriptName                  -- sets the logmarker for dz.log
        local allBlinds          = {"blind_1","blind_2","blind_3"}  -- blind names in domoticz
        local maxBlindDownTime   = 36                               -- default time in seconds for blind to go from fully open to fully closed (can be overruled in description)
        local maxBlindUpTime     = 42                               -- default time in seconds for blind to  go from fully closed to fully open (can be overruled in description)  
        local control            = {}
        local entryTime          = os.date(os.time())
        
        local function logWrite(str,level)
            dz.log(tostring(str),level or dz.LOG_DEBUG)
        end
        
        local function dumpPersist()
            for k,v in pairs(dz.data.blinds[item.name]) do
                logWrite(k .. "  ===>>> " ..tostring(v) )
            end
            logWrite(item.name .. "; state: " .. item.state)
            
        end
        
       -- if item.isDevice then
         --   logWrite("\n\n" .. item.name .. "; state: " .. item.state .. "\n" .. item.name .. "; level: " .. item.level .. "\n")
           -- return
        -- end
        
        local function blockBlind(blind,blockSeconds,blocker)
            dz.data.blinds[blind] = dz.data.blinds[blind] or {}
            dz.data.blinds[blind].blockedUntil = math.ceil(os.date(os.time() + blockSeconds+1))     -- blocked until
            dz.data.blinds[blind].blockedBy    = blocker
            dz.data.blinds[blind].blockedFrom  = os.date(os.time())
            dz.data.blinds[blind].levelFrom    = dz.devices(blind).lastLevel
            
            logWrite(blind .. " is blocked until " .. os.date("%X",os.time() + blockSeconds))
        end

        local function isBlocked(blind) 
            if dz.data.blinds[blind] == nil then dz.data.blinds[blind] = {} end
            dz.log("isBlocked = ".. tostring((tonumber(dz.data.blinds[blind].blockedUntil or 0)) >  tonumber(os.date(os.time()))),dz.LOG_DEBUG)
            return (tonumber(dz.data.blinds[blind].blockedUntil or 0) >  tonumber(os.date(os.time())))
        end
        
        local function delta2Seconds(delta)
            local maxUpTime = control.maxUpTime or maxBlindUpTime
            local maxDownTime = control.maxDownTime or maxBlindDownTime
            
            if    delta > 0 then return "Up", math.abs(math.ceil(math.min((delta * maxUpTime / 100 ),maxUpTime)))  end
            return "Down" , math.abs(math.ceil(math.min((delta * maxDownTime / 100 ),maxDownTime)))
        end
        
        local function keepTrack(origin,targetLevel)
            local tail, info
            if item.level  ~=  nil then info = "; level to " .. item.level .. "%"  -- when triggered by variable, there is no level
            else if bTable.s then tail = " for " .. bTable.s   .. " seconds"              -- variable contain s (seconds)
                 else tail = "; level " .. bTable.p end                            -- variable contain p (position)
                 info = ", moving " .. bTable.d .. tail
            end
            dz.data.blinds[origin].levelTo = targetLevel
            dz.data.blinds[origin].info    = dz.data.blinds[origin].info or {}
            dz.data.blinds[origin].info[dz.data.blinds[origin].direction] = dz.time.rawDate .. " " .. dz.time.rawTime .. info
        end
        
        local function newLevel(direction, duration, oldLevel, screenInversion)
            logWrite("1 ---------")
            
            logWrite(tostring(inverted))
            
            local factor   = 100 *  screenInversion
            local maxTime  = control.maxUpTime or maxBlindUpTime
            if direction  ~= "Down" and not inverted then 
                factor = -1 * factor 
                maxTime = control.maxUpTime or maxBlindDownTime     -- time in seconds for blind to go from fully closed to fully open
            elseif direction ~= "Up" and inverted then 
                 factor = -1 * factor 
                 maxTime = control.maxDownTime or maxBlindDownTime     -- time in seconds for blind to go from fully closed to fully open
            end
            return dz.utils.round(math.min(math.max(oldLevel + ( factor * duration / maxTime ),0),100))
        end

        local function delayedURL(callback,seconds)
            callback = "nodemcu_" ..  callback
            local url = dz.settings['Domoticz url'] .. "/json.htm?type=command&param=addlogmessage&message=" .. 
                        callback ..  "%20Scheduled%20for%20after%20" .. seconds .. "%20seconds."
            dz.openURL  ({ url      = url , method   = "GET", callback = callback,}).afterSec(seconds)
        end
           
        local function makeTableFromVar(str)
            local bTable = {}
             
            bTable.n = item.value:match("[a-zA-Z0-9_]+")       -- blind name 
            bTable.d = item.value:match(";[A-Z][a-z]+"):sub(2)      -- direction  
            
            local seconds = item.value:gsub(bTable.n .. ";" .. bTable.d .. ";","")
            bTable.s = tonumber( seconds )
            logWrite("Seconds: " .. bTable.s)
           
            return bTable
        end        
        
        local function osExecute(cmd)
            logWrite("command for osEexecute: ".. cmd) 
            local fileHandle     = assert(io.popen(cmd, 'r'))
            local commandOutput  = assert(fileHandle:read('*a'))
            local returnTable    = {fileHandle:close()}
            
            logWrite("commandOutput: " .. commandOutput)
            logWrite("returncode   : " .. returnTable[3])
           return commandOutput,returnTable[3]            -- rc[3] contains returnCode
        end
        
        local function sendMQTT(nodemcu,blind,direction,seconds) 
            local seconds   = tonumber(seconds) or 0
            local baseMQTT  = "mosquitto_pub -t " .. nodemcu .. "/" .. blind .. "_" .. direction .. " -m "
            if seconds == 0 then 
                osExecute(baseMQTT .. "0" )
            elseif seconds >= 1 then 
                osExecute(baseMQTT .. "1")            
                delayedURL(blind,seconds)
            else    
                osExecute(baseMQTT .. "1")
                osExecute("sleep 0.5")
                osExecute(baseMQTT .. "0")
            end
            
            dz.data.blinds[blind].nodemcu   = nodemcu
            dz.data.blinds[blind].direction = direction
        end        
        
        local function initPersistentBlind(blind)
            dz.data.blinds[blind] = dz.data.blinds[blind] or {}
        end
        
        local function Response2Parms(str)
            str = str:gsub("nodemcu_","")
            return dz.data.blinds[str].nodemcu, str, dz.data.blinds[str].direction
        end
        
        local function setLevelAfterInterrupt(blind)
            -- When a blind action is interrupted, the new level should take this into acount 
            local deltaLevel = dz.data.blinds[blind].levelFrom - dz.data.blinds[blind].levelTo
            local deltaTime  = dz.data.blinds[blind].blockedUntil - dz.data.blinds[blind].blockedFrom
            local newTime    = entryTime - dz.data.blinds[blind].blockedFrom 
            local newLevel   = dz.utils.round(dz.data.blinds[blind].levelFrom - newTime / deltaTime *  deltaLevel ) 
            
            dz.devices(blind).dimTo(newLevel).silent()
            dz.data.blinds[blind].blockedUntil = os.date(os.time())  -- unblock blind 
            dz.data.blinds[blind].levelTo = newLevel 
        end
        
        local function isCut(silent)
            local closed = 99
            local opened = 1

            
            if item.state == "Closed" then
               item.dimTo(closed)
               return true
            elseif item.state == "Open" then
               item.dimTo(opened)
               return true
            elseif item.level == 100  then
                if inverted then 
                    item.dimTo(opened)
                else
                    item.dimTo(closed)
                end
                return true
            elseif item.level == 0 then
                if inverted then 
                    item.dimTo(closed)
                else
                    item.dimTo(opened)
                end
                return true
            
            end
            return false
        end
        
        local function handleBlind(blind)
            initPersistentBlind(blind)
            control = dz.utils.fromJSON(dz.devices(blind).description)
            local targetLevel
            
            if isBlocked(blind) then 
                dz.log("Blind ".. blind .. " is active; Stopping now",dz.LOG_DEBUG) 
                sendMQTT(control.nodemcu,blind,"Up",0) 
                sendMQTT(control.nodemcu,blind,"Down",0) 
                setLevelAfterInterrupt(blind)
                return 
            else
                blockBlind(blind,bTable.s,control.nodemcu)
            end 
                
            local factor = 1
            if inverted then factor = -1 end
            targetLevel = newLevel(bTable.d,bTable.s,dz.devices(blind).level,factor)
            dz.devices(blind).dimTo(targetLevel).silent()
            sendMQTT(control.nodemcu,blind,bTable.d,bTable.s) 
            keepTrack(blind,targetLevel)
        end
        
        local function dzHandleBlind(blindName)
            local blind = dz.devices(blindName)
            local control = dz.utils.fromJSON(blind.description)           
            local direction 
            local delta     = control.maxUpTime or maxBlindUpTime
            
            
            if not(isBlocked(blindName)) then                                       -- too Quick
                if isCut() then
                    dumpPersist()
                    return
                end
                if  dz.data.blinds[blindName].levelTo == 1 then
                        direction, delta = delta2Seconds(blind.lastLevel - 1)
                        direction = "Up"
                elseif dz.data.blinds[blindName].levelTo == 99 then    
                        direction, delta = delta2Seconds(blind.lastLevel - 99)
                        direction = "Down"
                else
                       direction, delta = delta2Seconds(blind.lastLevel - blind.level)
                end
                
                dumpPersist()
                logWrite("lastLevel: " .. blind.lastLevel)
                logWrite("level: " .. blind.level)
                logWrite("direction: " .. direction)
                logWrite("delta: " .. delta)
                
                
                sendMQTT(control.nodemcu,blindName,direction,delta)
                blockBlind(blindName,delta,"dzVents")
            else
                dz.log("Not enough time (still blocked) ...", dz.LOG_DEBUG)
                blind.dimTo(blind.lastLevel).silent()
                return
            end
            keepTrack(blind.name,blind.level)        -- We are here because blind was set in domoticz so blind.level is targetLevel
        end
        
        --- Main code
        if item.isHTTPResponse then                                  -- Used for switching relais off only
            local nodemcu,blind,direction = Response2Parms(item.trigger)
            sendMQTT(nodemcu,blind,direction,0) 
                
        elseif item.isVariable then                                  -- triggered by nodemcu
            bTable = makeTableFromVar(item.value)
            inverted = dz.devices(bTable.n).switchType ==  "Blinds Percentage Inverted"
            
            if bTable.n ~= "ALLBLINDS" then 
                blinds2Handle = {bTable.n} 
            else
                blinds2Handle = allBlinds 
            end
            
            for i = 1,#blinds2Handle do 
                handleBlind(blinds2Handle[i])
                logWrite(blinds2Handle[i])
            end
        else                                                        -- triggered by device 
            local inverted = item.switchType ==  "Blinds Percentage Inverted"
            if item.name == "blind_Master" then
                if isCut() then return end
                for i = 1,#allBlinds do 
                    dz.devices(allBlinds[i]).dimTo(math.max(math.min(item.level,99),1))
                end
                
            else
                if isCut() then 
                    return 
                end
               
                dzHandleBlind(item.name)
            end 
        end
    end
}