Use string to get defined variable

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

Moderator: leecollings

Post Reply
jake
Posts: 751
Joined: Saturday 30 May 2015 22:40
Target OS: Raspberry Pi / ODroid
Domoticz version: beta
Contact:

Use string to get defined variable

Post by jake »

I have declared 5 variables (which define the 5 micro solar inverter devices) like this:

Code: Select all

local inv1 = domoticz.devices('11000xxx power')
local inv2 = domoticz.devices('110007xxx power')
local inv3 = domoticz.devices('1100xxx2 power')
local inv4 = domoticz.devices('100xxxx9 power')
local inv5 = domoticz.devices('100Xxxx8 power')
then I would like to run a loop 'for i = 1, 5 do' (do some calculations with the daily generated energy per micro inverter, by comparing the daily energy generation from inverter 1 to 4 with the value of inverter 5).
So I set up my code like this:

Code: Select all

for i = 1,4 do
inverterName = 'inv'..i
inverterValue = inverterName.WhToday
etc
etc
Unfortunately the value of 'inverterValue' is 'nil', while it has the correct value when I use inv1.WhToday.
My conclusion is that 'inverterName' doesn't inherit the defined variable in the for..next loop.

I looked all over the place, found tips about using global variables (don't need those) or tables (don't understand how to apply them).
I could already add the '.WhToday' to my variable declaration, but I think it end up with the same trouble that the generated string inv1 is not equal to variable inv1.
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Use string to get defined variable

Post by waaren »

jake wrote: Thursday 28 June 2018 22:56 ....
I looked all over the place, found tips about using global variables (don't need those) or tables (don't understand how to apply them).
....
Please have a look at below example of storing devices (objects ) in a Lua table and get some of the attributes of the devices in a for loop.
as an Array like Lua table

Code: Select all

local testArrayTable = {    domoticz.devices('Testje_1'),   -- This is a syntax shortcut for [1]= domoticz.devices('Testje_1')
                            domoticz.devices('Testje_2'),   -- This is a syntax shortcut for [2]= domoticz.devices('Testje_2')
                            domoticz.devices('Testje_3')    -- This is a syntax shortcut for [3]= domoticz.devices('Testje_3')
                        }
            
for i = 1,#testArrayTable do                  -- #testArrayTable is last element of testTable
          domoticz.log("Name of object (device): " .. testArrayTable[i].name,domoticz.LOG_INFO)
end
or as a Lua table with named keys

Code: Select all

local testKeyTable = {}                               --- In this table the key will be a string (test1, test2, etc)
testKeyTable.test1 = domoticz.devices('Testje_1')
testKeyTable.test2 = domoticz.devices('Testje_2')
testKeyTable.test3 = domoticz.devices('Testje_3')
            
for key,deviceObject in pairs(testKeyTable) do            -- Loop over all elements in the table
   domoticz.log("Name of key: object (device): " .. key .. ": " .. deviceObject.name,domoticz.LOG_INFO)
end
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
jake
Posts: 751
Joined: Saturday 30 May 2015 22:40
Target OS: Raspberry Pi / ODroid
Domoticz version: beta
Contact:

Re: Use string to get defined variable

Post by jake »

waaren wrote: Thursday 28 June 2018 23:48 Please have a look at below example of storing devices (objects ) in a Lua table and get some of the attributes of the devices in a for loop.
as an Array like Lua table
...
Thanks, this saved my day. I am glad with your help, because the online examples didn't work for me.

One more question:
Now I am able to read my inverter value in the for..next loop, I want to store it in a persistent data field in dzVents.
I have defined the different parts in the beginning of my script:

Code: Select all

        data = {
                Ratio1to5 = { history = true, maxItems = 7 },
                Ratio1to5dev = { history = true, maxItems = 7, maxHours = 7*24 },
                Ratio2to5 = { history = true, maxItems = 7 },
                Ratio2to5dev = { history = true, maxItems = 7, maxHours = 7*24 },
                Ratio3to5 = { history = true, maxItems = 7 },
                Ratio3to5dev = { history = true, maxItems = 7, maxHours = 7*24 },
                Ratio4to5 = { history = true, maxItems = 7 },
                Ratio4to5dev = { history = true, maxItems = 7, maxHours = 7*24 },
and now try to call out the average values of the stored data (with a check for nil value afterwards to catch the initial call of the script with an empty table):

Code: Select all

        RatioName = 'Ratio'..i..'to5'
        print('Ratio name is '..RatioName)
        RatioAverage = domoticz.data.RatioName.avg()
        if RatioAverage == nil then RatioAverage = Ratio end
.
However, the domoticz log comes back with this error about the code line "RatioAverage = domoticz.data.RatioName.avg()":
"... attempt to index field 'RatioName' (a nil value)"

I'm guessing that the error is in the same ball field as the first question, but maybe slightly different? RatioName is nog recognized (for i = 1) as Ratio1to5 and therefore doesn't get the average out of the stored data either.
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Use string to get defined variable

Post by waaren »

jake wrote: Friday 29 June 2018 9:07 ....
One more question:
Now I am able to read my inverter value in the for..next loop, I want to store it in a persistent data field in dzVents.
....
I'm guessing that the error is in the same ball field as the first question, but maybe slightly different? RatioName is nog recognized (for i = 1) as Ratio1to5 and therefore doesn't get the average out of the stored data either.
@jake, according to google using dynamic names for Lua variable is possible but considered bad coding practice. I am not sure the tricks with _G will even work in dzVents.
I also would not know how to tackle your requirement with dzVents history aware persistent variables. I am sure there are other users on this forum that will know how to do that.
My approach to this is based on a table in dzVents persistent data. The code below does have its own housekeeping, to kind of mimic the behavior of dzVents history aware data.
Please have a look and feel free to ask when things are not clear. Of course I am also open for improvements of which I am sure they can be made.

Code: Select all

return {
    on  = {     devices     =   { "string2VarSwitch" }},  -- used during development and test
     
                data        =   { ratios = { initial = {}}},   -- Table 

               logging      =   {   level     =   domoticz.LOG_INFO,           -- Change to LOG_DEBUG to check what happens
                                    marker    =   "ratioTable"    },
                
    execute = function(dz, trigger)
        
        local houseKeepingDone    
        local secondsToKeep, numberToKeep = 3600, 10          -- during test and development max. 1 hour or 10 cycles whatever comes first
        
        local function removeRatios(secondsToKeep,numberToKeep)     -- based on time and number  
            secondsToKeep = secondsToKeep or ( 7 * 24 * 3600 )      -- defaults to a week
            numberToKeep = numberToKeep or 100                      -- defaults to 100 
        
            for i = #dz.data.ratios,1,-1 do   -- Backwards to make sure table.remove works for subsequent rows
                dz.data.ratios[i].sequence = dz.data.ratios[i].sequence + 1
                if  (dz.data.ratios[i].time < os.time(os.date('*t')) - secondsToKeep) or 
                    (dz.data.ratios[i].sequence > numberToKeep) then  
                   table.remove(dz.data.ratios,i)       -- table housekeeping
                end
            end
            return "Done"      -- You can return anything as long as it is not nil or false
        end  
    
        local function addRatio(parsedKey,parsedValue)   -- Add ratios with time stamps  
            if not(houseKeepingDone) then
                houseKeepingDone = removeRatios(secondsToKeep,numberToKeep)
            end 
            table.insert(dz.data.ratios,{
                                          sequence      = 0,                         -- Needed for housekeeping ( numbertoKeep will look at this)
                                          key           = parsedKey,
                                          value         = parsedValue,
                                          time          = os.time(os.date('*t'))  -- Needed for housekeeping ( secondsToKeep will look at this)
                                        })
        end						-- You will find the table in domoticz dir/dzvents/scripts/data 
          
        local function getAverageRatio(key,seconds)
            seconds = seconds or ( 7 * 24 * 3600 )  -- Defaults to a week
            local total,count = 0, 0
            for i = 1,#dz.data.ratios,1  do   
                if dz.data.ratios[i].key == key and  dz.data.ratios[i].time >= os.time(os.date('*t')) - seconds then  
                   total = total + dz.data.ratios[i].value
                   count = count + 1
                end
            end
            if count ~= 0 then return dz.utils.round(total / count,1)
            else return 0 end
        end              

        -- Add ratios (ratioName, ratioValue    
        for i =1,5 do
            addRatio('ratio'..i..'to5',math.random(100))            
        end

        for i =1,5 do
            dz.log("Average for: " .. "Ratio"..i.."to5: " ..getAverageRatio("ratio"..i.."to5"),dz.LOG_INFO)
        end
    end
}   
Last edited by waaren on Sunday 01 July 2018 9:14, edited 1 time in total.
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
jake
Posts: 751
Joined: Saturday 30 May 2015 22:40
Target OS: Raspberry Pi / ODroid
Domoticz version: beta
Contact:

Re: Use string to get defined variable

Post by jake »

@waaren, thanks for this example script. You put a lot of work in it.
I find it quite difficult to grasp the steps in your script, but I think I will just need to implement it and adapt to my original script needs.

@dannybloe I wonder if it is really necessary to add all the functions to each script to have more flexible persistent data access. Is there currently a way around, or is this for the dzVents 'wishlist'.
Post Reply

Who is online

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