Welcome to Smart Home Forum by FIBARO
Dear Guest,
as you can notice parts of Smart Home Forum by FIBARO is not available for you. You have to register in order to view all content and post in our community. Don't worry! Registration is a simple free process that requires minimal information for you to sign up. Become a part of of Smart Home Forum by FIBARO by creating an account.
As a member you can:
- Start new topics and reply to others
- Follow topics and users to get email updates
- Get your own profile page and make new friends
- Send personal messages
- ... and learn a lot about our system!
Regards,
Smart Home Forum by FIBARO Team
Search the Community
Showing results for tags '2nd edition'.
-
[TUTORIAL] Introduction to Lua tables (2nd edition)
AutoFrank posted a topic in Tutorials and Guides
**MAJOR UPDATE TO THIS TUTORIAL** Hi, This tutorial has been going through a major update and expansion since the first release. Special thanks deserved to @petergebruers and others for helping me understand many of the underlying table concepts and for also contributing a lot to this tutorial. It may be a good idea to paste some of the code in this tutorial into a test scene to understand how they work by reviewing the output Topics covered with lots of sample code and expected outputs Table basics Creating tables and printing (ordered, non-ordered, numerical and non numerical keys) #operator - pros and cons kv pairs - advantages Updating tables - adding adding, inserting values Nested Tables - printing, updating, inserting, Summary of key points Storing tables in global variables I would have found this very useful when I started so hopefully some users will find it useful as well. -frank & peter Tables A table is a tree structure, consisting of field and each field has a "key" and "value" pair. The key can be any Lua value except nil and NaN. A table can store anything except nil. The name of the table is the variable that stores a reference to the table so it can be accessed Creating Tables and displaying the table data a = {} This is the smallest table and stores the reference to the table {} in the variable a Consider the following table print("table with numerical keys") fav = {[1] = "4FM", [2] = "96FM", [3] = "Calm", [4] = "Heart", [5] = "Red_FM"} fav is the table (or at least the name of the variable where the table is stored), in the above table 'fav', it has 5 fields and each field consists of a key/value pair 4 is the key and 4FM is the value , 2 is a key and 96FM is the value, etc You can display all the key/value pairs using the following ... print("table with numerical keys and using k/v pairs to display the fields but they won't be in order") fav = {[1] = "4FM", [2] = "96FM", [3] = "Calm", [4] = "Heart", [5] = "Red_FM"} for k,v in pairs(fav) do print("k: " ..k..", v: "..v) end the result is ... and you'll notice that the results are NOT returned in order if you have numerical keys [1], [2] then you will need to use ipairs to return them in order print("table with numerical keys and using k/v ipairs to display the fields in order") fav = {[1] = "4FM", [2] = "96FM", [3] = "Calm", [4] = "Heart", [5] = "Red_FM"} for k,v in ipairs(fav) do print("k: " ..k..", v: "..v) end #operator The #operator (#tablename) is used by a lot of people to identify the length of the table and use this to iterate through the table but it is not always recommended an example of where it will work is here print("table with numerical keys and using the #operator to iterate through the table") radio = {"4FM", "96FM", "Calm", "Heart", "Red_FM"} print("#operator: "..#radio) for i = 1, #radio do print(radio[i]) end if the table keys are numerical and contiguous, it will work.. ....but if they are not or you have inserted or removed values then it won't work A good example of where it doesn't work very well is here print("table where numerical keys are not explicitly defined but are still the table keys") print(" example where the #operator doesnt return the correct count") radio = {"4FM", "96FM", "Calm", "Heart", "Red_FM"} for k,v in pairs(radio) do print("k: " ..k..", v: "..v) end print("#operator: "..#radio) -- remove one value, set it to nil radio[3] = nil for k,v in pairs(radio) do print("k: " ..k..", v: "..v) end print("#operator: "..#radio) you can see that the second loop in the debug is showing an #operator value of 5 (because it is the last key but there are only 4 key/value pairs as we removed one Another approach that is recommended to use is as follows use the k/v approach to count the fields and then use the counter to iterate through.. print("table where numerical keys are not explicitly defined but are still the table keys") print(" example using k/v pairs to calculate the correct table field count") radio = {"4FM", "96FM", "Calm", "Heart", "Red_FM"} counter = 0 for k,v in pairs(radio) do counter=counter+1 end print("counter: "..counter) for i = 1, counter do print(radio[i]) end radio[3] = nil -- remove the row by setting the key to nil counter = 0 for k,v in pairs(radio) do counter=counter+1 end print("counter: "..counter) for i = 1, counter do print(radio[i]) end and you can see that the counter is correct in both loops Updating Tables you can update a table by setting Key/Value pairs or delete a value as follows print("table where numerical keys are not explicitly defined but are still the table keys") print("examples of updating the table") fav = {"4FM", "96FM", "Calm", "Heart", "Red_FM"} -- update one value add another value fav[2] = "Soul" fav[4] = "Classic" -- delete value at key 1 fav[1] = nil for k,v in pairs(fav) do print("k: " ..k..", v: "..v) end if the k/v pair already exists it overwrites it or of the k/v pair didn't exist, it simply adds it as above This is the same example but the table has the numerical keys explicitly defined print("updating a table") fav = { [1] = "4FM", [2] = "96FM", [3] = "Calm", } fav[2] = "Soul" fav[4] = "Classic" for k,v in ipairs(fav) do print("k: " ..k..", v: "..v) end Example of adding key/value pairs to this table using table.insert fav= {"4FM","96FM", "Soul", "Jazz"} table.insert(fav, "Calm") table.insert(fav, "Red_FM") table.insert(fav, "Heart") for k,v in pairs(fav) do print("k: " ..k..", v: "..v) end The extra key/value pairs will be added as extra fields as you cannot specify the exact field you want to update as in the approach above Tables with non-numerical keys are also possible as shown below print("Table initialiser with alpha keys") fav = { ["a"] = "4FM", ["b"] = "96FM", ["c"] = "Calm", ["d"] = "Heart", ["e"] = "Red_FM"} for k,v in pairs(fav) do print("k: " ..k..", v: "..v) end the same table can be represented in a simpler form print("Table initialiser with alpha keys - simplified") fav = { a = "4FM", b= "96FM", c= "Calm", d = "Heart", e= "Red_FM"} for k,v in pairs(fav) do print("k: " ..k..", v: "..v) end If you chose or have to use non numerical keys or a mix, then Lua makes no guarantee on order as the spec says random. The only way to order a table with non-numerical keys (such as alphabetical order) is to use an external reference. Nested Tables Lets take the following table, it looks like each value in the key/value pair is a table in itself as if one table is nested inside the other table = { [1] = {loc="utility_room", name="HeatingTemp"}, [2] = {loc="bed_room", name="FreezerTemp"}, } for k,v in pairs(table) do print(k,v) end if you run the usual k/v code you will see the second/nested set of tables To list the k/v inside the second table you need to iterate through the first table we use a counter like before to find out how many fields are in the outer most table There are two tables nested within the outer most table table [1] which has two fields with k/v pairs table [2] which has two fields with k/v pairs print("Nested table example") table = { [1] = {loc="utility_room", name="HeatingTemp"}, [2] = {loc="bed_room", name="FreezerTemp"}, } for k,v in pairs(table) do print("first level key: " ..k..", first level value: "..tostring(v)) for k2,v2 in pairs(v) do -- This works because we KNOW v is a table. print(" second level key: " ..k2..", second level value: "..v2) end end we then use the counter to expose the k/v pairs at table[1] and table [2] with the following result You could also expose specific values (in the nested able) using the following table = { [1] = {loc="utility_room", name="HeatingTemp"}, [2] = {loc="bed_room", name="FreezerTemp"}, } for k,v in pairs(table) do print("location: "..table[k].loc) end with the following expected result You could also have used the #operator that we discussed earlier BUT only because the key's in the outer-most table are numerical and contingous for i = 1, #table do -- #list refers to the max number of items in the table fibaro:debug(table[i].ip, table[i].port) end Updating a value in a nested table If you want to update a specific value in the nested table you need to use the k/v method we have discussed fav = { [1] = {loc="utility_room", name="HeatingTemp"}, [2] = {loc="bed_room", name="FreezerTemp"}, } -- update nested table on the second field with a new value fav[2].loc = "kitchen" fav[2].name = "Hobtemp" -- or you could use the following format to do accomplish the same update fav[2]["loc"] = "kitchen" fav[2]["name"] = "Hobtemp" -- print out the updated table... for k,v in pairs(fav) do for k,v in pairs(fav[k]) do print("k: " ..k..", v: "..v) end end -- second option to print out the updated table with more explanation for k,v in pairs(fav) do print("first level key: " ..k..", first level value: "..tostring(v)) for k2,v2 in pairs(v) do -- This works because we KNOW v is a table. print(" second level key: " ..k2..", second level value: "..v2) end end the result is If you want to add/insert a new k/v pair in the nested level, you can use the table.insert method fav = { [1] = {loc="utility_room", name="HeatingTemp"}, [2] = {loc="bed_room", name="FreezerTemp"}, } -- insert a new value table.insert(fav,{loc="bedroom", name="sinktemp"}) -- print out the updated table... for k,v in pairs(fav) do for k,v in pairs(fav[k]) do print("k: " ..k..", v: "..v) end end -- second option to print out the updated table with more explanation for k,v in pairs(fav) do print("first level key: " ..k..", first level value: "..tostring(v)) for k2,v2 in pairs(v) do -- This works because we KNOW v is a table. print(" second level key: " ..k2..", second level value: "..v2) end end and the result is three fields in the table So before we go to the last task of storing the table in a global variable, I thought it would be good to have a quick recap.. Summary A table is a tree structure, consisting of field and each field has a "key" and "value" pair. The name of the table is the variable that stores a reference to the table so it can be accessed you can explicitly declare a numerical key in a table but you don't have to for a table with a numerical key - use ipairs to print the table fields in order #operator can be used but ONLY for tables with numerical keys that are contiguous it is recommended to use the standard k/v approach to count the number of fields remove a value by setting its key = nil update a table using the table[key] method add a new field using table.insert(table, "value") and will add a numerical key table.insert will not work with tables with non-numerical keys tables with non-numerical keys cannot be printed in order by ipairs, result will be random nested tables require iteration to print the inner-most tables multiple levels of iteration required for multi-nested tables updating nested table - iterate with k/v and use table[key].nested-key = "value" inserting into nested table - iterate with k/v and use table.insert(table,{key="value, key="value} tables can be very confusing and frustrating to us newbie's , so take your time Storing a table in a global variable if you take the following table structure Table = { group = { option1=1560,option2=1507,option3=881 }, } If you want to store this table in a global variable you will need to encode the table as a string. One of the most common formats to encode a table (structure) is json from json.org "JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate." To save the table you need to encode it and then save it to the global variable jTable = json.encode(table) fibaro:setGlobal("StateTable", jTable) In order to read back a single value you need to decode the string local jT = json.decode(fibaro:getGlobalValue("Table")) once it's decoded you can then read one of the values or manipulate the table fibaro:debug(jT.group.option1) Updating a single value - assign the new value, encode it and the store it..... jT.group.option3 = 987 jTable = json.encode(jT) fibaro:setGlobal("StateTable", jTable) Making json strings/output easier to read... Sometimes a json string can be difficult to read and understand its structure. Typically they would look something like this... {"widget": {"debug": "on","window": {"title": "Sample Konfabulator Widget","name": "main_window","width": 500,"height": 500},"image": {"src": "Images/Sun.png","name": "sun1","hOffset": 250, "vOffset": 250,"alignment": "center"},"text": {"data": "Click Here","size": 36,"style": "bold","name": "text1","hOffset": 250,"vOffset": 100,"alignment": "center","onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"}}} There are a number of websites that will 'pretify' the string make it easier to read the structure and enable you to understand how you might navigate it. If you take json string above and paste it into http://jsonprettyprint.com/ it will display it more like a table This format is easier to understand { "widget": { "debug": "on", "window": { "title": "Sample Konfabulator Widget", "name": "main_window", "width": 500, "height": 500 }, "image": { "src": "Images\/Sun.png", "name": "sun1", "hOffset": 250, "vOffset": 250, "alignment": "center" }, "text": { "data": "Click Here", "size": 36, "style": "bold", "name": "text1", "hOffset": 250, "vOffset": 100, "alignment": "center", "onMouseUp": "sun1.opacity = (sun1.opacity \/ 100) * 90;" } } } Finally.... There is a very good discussion on using a table in a predefined variables to store the ID's of scenes and devices for the HC2 - https://forum.fibaro.com/index.php?/topic/23942-tutorial-using-a-hometable-to-store-device-and-scene-ids/ suggestions to improve welcome -f- 47 replies
-
- 9
-
- 2nd edition
- lua
-
(and 3 more)
Tagged with: