Pre-execution/definition code  [Solved]

Easy to use, 100% Lua-based event scripting framework.

Moderator: leecollings

Post Reply
Marque1968
Posts: 60
Joined: Tuesday 03 April 2018 18:41
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta
Contact:

Pre-execution/definition code

Post by Marque1968 »

At the top of any dzvents script, I can insert some variables, which I for instance use to set up the device list that is used in the "on = {" section. But now I want to go one step further. I want the device array to be set up as a result of other variables. But my proof of concept fails:

Code: Select all

local listgroup = {{182,"hello"},{VDI_livingroom,"bye"},{VDI_diningroom,"greetings"},{VDI_radiation,"hi"},{VDI_perfume,"last"}}
local devicelist = {}
local devcount = 0
for devkey,devtxt in ipairs(listgroup) do
    devcount = devcount + 1
    devicelist[devcount]=devkey 
end

return {
	on = {
		devices = devicelist,
	},

	execute = function(domoticz, triggeredItem, info)
        for devkey,devtxt in listgroup do
            if (devkey == triggeredItem.deviceId) then
                domoticz.helpers.sendTelegram(domoticz, 'marque', devtxt)
            end
        end
    end
}
For clarity sake:
- The VDI_... variables are device ID's, set in the global_date (a technique I use for all my scipts succesfully)
- Device 182 is the ID for the virtual device I use for any proof of concept.
- The proof would be succesful if the text "hello" is send to my telegram app, when I switch the virtual device 182.

As you might have gathered from the fact I am posting here: it is not working. No errors, but no event gets triggered eithers.

So either:
- It is not possible to enter any active code before the "on = {"
or
- I have messed up my code.
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Pre-execution/definition code

Post by waaren »

Marque1968 wrote: Tuesday 28 May 2019 21:42 either
- It is not possible to enter any active code before the "on = {"
not true
or
- I have messed up my code.
:D

Have a look at this.

Code: Select all

local listgroup = { [182] = "hello",VDI_livingroom = "bye", blabla = "What ? ", VDI_diningroom = "greetings", VDI_radiation ="hi" , VDI_perfume = "last"}
local devicelist = {}
local devcount = 0
for devkey, devtxt in pairs(listgroup) do
    devicelist[#devicelist + 1] = devkey 
end
Have a look at this[code]
return {
	on = {
		timer = {'every minute'}, 
		devices = devicelist,
	},

	execute = function( dz )
        devicelist[3] = nil -- break the ipairs
        for key, value in ipairs(devicelist) do -- ipairs ==>> used for numeric associative array. 
                                                -- Non numeric keys in are ignored, index order is deterministic (numeric and consecutive order).
            dz.log('devicelist[' .. key .. '] : ' .. value ,dz.LOG_FORCE)
        end
        dz.log('------- above =  ipairs ----------- below = pairs '  ,dz.LOG_FORCE)
        listgroup.blabla = nil -- does not break the pairs 
        for key, value in pairs(listgroup) do  -- standard associative array (unspecified key order)
            dz.log('listgroup["' .. key .. '"] : ' .. value ,dz.LOG_FORCE)
        end
    end
}
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
Marque1968
Posts: 60
Joined: Tuesday 03 April 2018 18:41
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta
Contact:

Re: Pre-execution/definition code

Post by Marque1968 »

Thank you Waaren, but I must have more active fields. This was just an attempt for the proof of concept. The first real life implementation will need 3 parameters per array item, and will be something along the lines of:

Code: Select all

PSEUDO CODE

listgroup : { 
                  {RealDeviceID1, VirtualDeviceID1, CorrectionAction}
                  {RealDeviceID2, VirtualDeviceID2, CorrectionAction}
                  {RealDeviceID3, VirtualDeviceID3, CorrectionAction}
                  {RealDeviceID4, VirtualDeviceID4, CorrectionAction}
                  {RealDeviceID5, VirtualDeviceID5, CorrectionAction}
                }

for each row in listgroup
               devicelist = devicelist + row[1]

On {devicelist}

return function (dz, trigger ) {
               for icount = 1 to #listgroup
                      if device(trigger).deviceId = listgroup[icount][1]
                          if device(trigger).active <> device(listgroup[icount][2]).active  -- physical device has different active state from the virtual device
                              case listgroup[icount][3] of -- do correction action
                                   0: sendmessage(device(listgroup[icount][1].name .. ' not in the correct state. Ignored')
                                   1: sendmessage(device(listgroup[icount][1].name .. ' not in the correct state. Re-attempting')
                                       dz.helpers.virtualtoreal(listgroup[icount][2],listgroup[icount][1])
                                   2: sendmessage(device(listgroup[icount][1].name .. ' not in the correct state. Attempting to switch on')
                                       device(listgroup[icount][2]).switchOn
                                   3: sendmessage(device(listgroup[icount][1].name .. ' not in the correct state. Attempting to switch off')
                                       device(listgroup[icount][2]).switchOff
                              end case
                         end if
                     end if
                end for
end function
In essence.
- All switches will be operated (be it from scripts or user interaction) via virtual devices
- The virtual device will call 'virtual to real' to their associated device(s)
- This script will instantly be called, but ignored as the state of virtual and real will be identical.
- When ZWave fails to switch the real device (as happens too often) the polling in the device will eventually switch back the domoticz value to the actual state. In that case this script is called to correct the error in the way that is required from the device (most likely it will always be option 1: re-attempt to set the real device to the virtual value


And this is the first multi dimentional array I will be working with. I already have an idea to simplify other parts of my scripting to use well over 3 items in a multi dimentional array. So I assume that (i)pairs are no help to me...
Marque1968
Posts: 60
Joined: Tuesday 03 April 2018 18:41
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta
Contact:

Re: Pre-execution/definition code  [Solved]

Post by Marque1968 »

Ok, as nobody was able to help me on this, I have expiremented myself and in the end got myself a working program. As others may have the same issues, I add my script code here

Code: Select all

local setdelay = 10

-- ADD DEVICES JUST ABOVE THE PROGRAM EXECUTION WITH return {
-- NO MORE CONFIGURING UNTIL THAT BLOCK OF CODE


local function addnewdevicelink (devicearray, virtual, physical, action, groupname)
    local new = {}
    if type(physical) == "table" then
        for k, v in pairs(physical) do
            addnewdevicelink(devicearray,virtual,v,action,groupname)
        end
    else
        -- First  set the name to device "name", even when empty (only for a new device)
        new["name"]=groupname
        local found=false
        for k, v in pairs(devicearray) do
            if k==virtual then
                found=true
            end
        end
        if not(found) then
            devicearray[virtual]=new
        end
        -- now add device to the list (should always exist now)
        local new = {}
        new[physical]=action
        local found=false
        for k, v in pairs(devicearray) do
            if k==virtual then
                v[physical]=action
                found=true
            end
        end
    end
    
end

local function createdevicelist (linklist)
    local returnarray = {}
    for virt, val in pairs(linklist) do
        if type(val) == "table" then
            for real, action in pairs(val) do
                if real ~= "name" then -- ignoring the 'name' device
                    local found = false
                    for icount=1,#returnarray do 
                        if returnarray[icount]==real then
                            found = true
                        end
                    end
                    if not(found) then
                        table.insert(returnarray,real)
                    end
                end
                
            end
        end
    end
    return returnarray
end

local function returnmatch(linklist,foundid) -- only the first virtual device will be returned
    local returnarray = {}
    local found = false
    for virt, val in pairs(linklist) do
        if type(val) == "table" then
            for real, action in pairs(val) do
                if real == foundid then
                    if not(found) then
                        returnarray[virt] = action
                        found = true
                    end
                end
            end
        end
    end
    return returnarray
end

local function returnname(linklist,virtid) -- only the first virtual device will be returned
    local foundname = ""
    local found = false
    for virt, val in pairs(linklist) do
        if virt==virtid then
            if type(val) == "table" then
                for real, action in pairs(val) do
                    if real == "name" then
                        if not(found) then
                            foundname = action
                            found = true
                        end
                    end
                end
            end
        end
    end
    return foundname
end

function vertoon (a)
    local retstring = ""
    if type(a) == "table" then
        for k, v in pairs(a) do
            if type(v) == "table" then
                retstring = retstring .. " " .. k .. " = { " .. vertoon(v) .. "},"
            else
                retstring = retstring .. " " .. k .. " = " .. v .. ","
            end
        end
    else
        retstring = retstring .. a .. ","
    end
    return retstring
end


local workarray = {}

-- ADD DEVICES HERE

addnewdevicelink(workarray,VDI_winkellicht,DID_winkellicht,ACT_followvirtual+ACT_notify,"Winkellicht")
addnewdevicelink(workarray,VDI_etalage,DID_etalage,ACT_onlyretryoff+ACT_notify,"Etalage")
addnewdevicelink(workarray,VDI_eetkamerlicht,{DID_eetkamerlicht, DID_eetkamergroot},ACT_donothing,"Eetkamer")

-- FINISH CONFIGURING HERE

return {
	on = {
		devices = createdevicelist(workarray),
	},

	execute = function( dz, trig, info )
       for key, value in pairs(returnmatch(workarray,trig.id)) do
            if key > 0 then
                if dz.devices(key).active ~= trig.active then
                    if value >= 10 then
                        value = value - 10
                        dz.helpers.sendTelegram(domoticz, TEL_sysalarmgroup, 'Value mismatch ' .. returnname(workarray,key) .. ' between ' .. key .. ' and ' .. trig.id)
                    end
                    
                    if value == ACT_followvirtual then
                        dz.log('Need to Reset ' .. trig.id .. ', ' .. returnname(workarray,key),dz.LOG_FORCE)
                        if dz.devices(key).active then trig.switchOn().afterSec(setdelay)
                        else trig.switchOff().afterSec(setdelay)
                        end
                    end
                
                    if value == ACT_onlyretryoff then
                        if not(dz.devices(key).active) then
                            dz.log('Need to Reset ' .. trig.id .. ', ' .. returnname(workarray,key),dz.LOG_FORCE)
                            trig.switchOff().afterSec(setdelay)
                        end
                    end
                    
                    if value == ACT_onlyretryon then
                        if dz.devices(key).active then
                            dz.log('Need to Reset ' .. trig.id .. ', ' .. returnname(workarray,key),dz.LOG_FORCE)
                            trig.switchOn().afterSec(setdelay)
                        end
                    end
                    
                end
            else 
                dz.log('device ' .. trig.id .. ' not found in matchlist (' .. key .. "," .. value .. ")", dz.LOG_FORCE)
            end
            
        end
    end
}

a) Sorry that my devices are in Dutch. I hope you have a grasp of things they do anyway (winkellicht=shoplight,eetkamer=diningroom,etalage=shopwindow)
b) I have set up global_data to have all the devices as variable names. When a device fails and needs to be replaced by another, I just have to change the device numbers there and all my other scripts just keep on functioning without any alteration.
  • VDI = Virtual Device ID's
  • DID = Device ID's of real devices {I am switching over from letting buttons and scripts change the status of the real device, but must change a virtual device that in turn switches one or multiple devices}
  • ACT = Actions on what to do when there is a mismatch. I have defined:
    • ACT_donothing = 0
      ACT_followvirtual = 1
      ACT_onlyretryoff = 2
      ACT_onlyretryon = 3
      ACT_notify = 10 -- this is a + action (e.g. ACT_followvirtual+ACT_notify)
c) Notification to my mobile device is done via a Telegram messaging function in my global_data
d) As any aftermin etc are executed by the virtual device, I do not need to take any of that info with me to the real devices
e) Make sure your physical switches are set to poling, otherwise they will never notify you that they have not executed the switch-command
f) I put a delay option (here set to 10 seconds) to prevent lights switching too fast, especially when a loop failure occurs. But this might be set to zero.
g) Easy ways to test this is to switch a powerplug by the button on it, or to change the state of the physical device in Domoticz, without changing the virtual value first.
h) Make sure your dashboard or dashticz do not show physical switches anymore, but just the virtual switches
i) I just finished programming it, but have only limitly tested it. So if you use it, use it as is and be aware, problems my pop up at any time. (you need to tweek it to your needs anyway)
Post Reply

Who is online

Users browsing this forum: Google [Bot] and 1 guest