Jump to content

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


[TUTORIAL] Introduction to Lua tables (2nd edition)


AutoFrank

Recommended Posts

 

**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

Please login or register to see this code.

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 ...

Please login or register to see this code.

the result is ...

 

Please login or register to see this image.

/monthly_2017_02/result.PNG.78c043a440f8a84918431f4197f1a1fb.PNG" />

 

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

Please login or register to see this code.

 

#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 

Please login or register to see this code.

Please login or register to see this attachment.

 

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

Please login or register to see this code.

Please login or register to see this attachment.

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..

Please login or register to see this code.

Please login or register to see this attachment.

 

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

Please login or register to see this code.

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

Please login or register to see this attachment.

 

 

This is the same example but the table has the numerical keys explicitly defined

Please login or register to see this code.

Please login or register to see this attachment.

 

Example of adding key/value pairs to this table using table.insert

Please login or register to see this code.

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

Please login or register to see this attachment.

 

Tables with non-numerical keys are also possible as shown below

Please login or register to see this code.

Please login or register to see this attachment.

 

the same table can be represented in a simpler form

Please login or register to see this code.

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

Please login or register to see this code.

if you run the usual k/v code you will see the second/nested set of tables

Please login or register to see this attachment.

 

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

Please login or register to see this code.

we then use the counter to expose the k/v pairs at table[1] and table [2] with the following result

 

Please login or register to see this attachment.

 

You could also expose specific values (in the nested able) using the following 

Please login or register to see this code.

with the following expected result

image19.PNG

 

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

Please login or register to see this code.

 

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

Please login or register to see this code.

the result is 

Please login or register to see this attachment.

 

If you want to add/insert a new k/v pair in the nested level, you can use the table.insert method

Please login or register to see this code.

and the result is three fields in the table

image21.PNG

 

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

Please login or register to see this code.

 

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

Please login or register to see this code.

 

In order to read back a single value you need to decode the string 

Please login or register to see this code.

once it's decoded you can then read one of the values or manipulate the table

Please login or register to see this code.

 

Updating a single value

- assign the new value, encode it and the store it.....

Please login or register to see this code.

 

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...

Please login or register to see this code.

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 

Please login or register to see this link.

 it will display it more like a table

This format is easier to understand

 

Please login or register to see this code.

 

 

 

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

Please login or register to see this link.


suggestions to improve welcome

-f

 

Edited by AutoFrank
  • Like 7
  • Thanks 1
Link to comment
Share on other sites

I put this in one of my scenes:

 

lamp_ON = {"79", "148", "153", "238", "239", "284", "298", "299", "312", "313", "314", "314", "322"}

    --print("#operator: "..#lamp_ON)
    for i = 1, #lamp_ON do 
        if  tonumber(fibaro:getValue(lamp_ON, "value")) > 0 then
              fibaro:debug("Forgotten to Turn this Lamp OFF: " ..lamp_ON);
        end
    end
  

Output in debug if light is ON:

Forgotten to Turn this Lamp OFF: 79 < Lamp ID

 

But instead of the Lamp ID I would like to have a text.. like:

Forgotten to Turn this Lamp OFF: Kitchen Table 

 

How to accomplish this?

 

Link to comment
Share on other sites

@samuel, the following should work:

 

fibaro:debug("Forgotten to Turn this Lamp OFF: " ..fibaro:get(lamp_ON, 'name'));

 

Best, Rene.

Link to comment
Share on other sites

i get this error:

 

[DEBUG] 14:41:48: line 115: attempt to concatenate local 'deviceId' (a table value)

 

-- table with Lamp ID's
lamp_ON = {"79", "148", "153", "238", "239", "284", "298", "299", "312", "313", "314", "314", "322"}
 

     --print("#operator: "..#lamp_ON)
    for i = 1, #lamp_ON do 
        if  tonumber(fibaro:getValue(lamp_ON, "value")) == 0 then -- > 0 
              --fibaro:debug("Forgotten to Turn this Lamp OFF: " ..lamp_ON);
            fibaro:debug("Forgotten to Turn this Lamp OFF: " ..fibaro:get(lamp_ON, 'name'));
        end
    end

 

Link to comment
Share on other sites

  • Topic Author
  • 9 minutes ago, samuel said:

    i get this error:

     

    [DEBUG] 14:41:48: line 115: attempt to concatenate local 'deviceId' (a table value)

     

    -- table with Lamp ID's
    lamp_ON = {"79", "148", "153", "238", "239", "284", "298", "299", "312", "313", "314", "314", "322"}
     

         --print("#operator: "..#lamp_ON)
        for i = 1, #lamp_ON do 
            if  tonumber(fibaro:getValue(lamp_ON, "value")) == 0 then -- > 0 
                  --fibaro:debug("Forgotten to Turn this Lamp OFF: " ..lamp_ON);
                fibaro:debug("Forgotten to Turn this Lamp OFF: " ..fibaro:get(lamp_ON, 'name'));
            end
        end

     

     

    Hi @samuel

    As far as I can see you may need to use a call to the HC2 api using the device id to determine the device name

    I don't have time this minute to do a full solution but here is the api if it helps

     

    Please login or register to see this code.

    you'll need to pass the 'id' to the http:request string 

    'result' is the http response table that has the name you need.

     

    Link to comment
    Share on other sites

    2 hours ago, AutoFrank said:

     

    Hi @samuel

    As far as I can see you may need to use a call to the HC2 api using the device id to determine the device name

    (...)

     

    The API is certainly a generic solution, but HC has a builtin function to determine the name of a device. Like this (plus some other corrections to the code):

     

    Please login or register to see this code.

    Edit: fix type of table values and add nil test.

    Edited by petergebruers
    Link to comment
    Share on other sites

  • Topic Author
  • 5 minutes ago, petergebruers said:

     

    The API is certainly a generic solution, but HC has a builtin function to determine the name of a device. Like this (plus some other corrections to the code):

     

    Please login or register to see this code.

     

     

    thanks @petergebruers - more like what @ReneNL was referring to .... :-)

     

    Link to comment
    Share on other sites

     

     

    39 minutes ago, petergebruers said:

     

    The API is certainly a generic solution, but HC has a builtin function to determine the name of a device. Like this (plus some other corrections to the code):

     

    Please login or register to see this code.

     

     

    i got an error: [DEBUG] 15:48:54: line 36: Assertion failed: Expected number

     Line 36 below:

    Please login or register to see this code.

     

     

    in pairs, 

    I tried the one from @ Autofrank with ..id.. ..(79).. for a try, then i got the whole json string as output... 

     

    Edited by samuel
    Link to comment
    Share on other sites

    the table input are the id's from the lights

    Please login or register to see this code.

    Link to comment
    Share on other sites

  • Topic Author
  • **MAJOR UPDATE TO THIS TUTORIAL**

    Hi,

    This tutorial has been going through a major overhaul 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

    Edited by AutoFrank
    Link to comment
    Share on other sites

  • Topic Author
  • 56 minutes ago, samuel said:

     

     

     

    i got an error: [DEBUG] 15:48:54: line 36: Assertion failed: Expected number

     Line 36 below:

    Please login or register to see this code.

     

     

    in pairs, 

    I tried the one from @ Autofrank with ..id.. ..(79).. for a try, then i got the whole json string as output... 

     

     

    @samuel

     

    slight tweak - turning v into a number

    Try this

     

    Please login or register to see this code.

     

    Link to comment
    Share on other sites

    1 hour ago, AutoFrank said:

     

    @samuel

     

    slight tweak - turning v into a number

    Try this

     

    Please login or register to see this code.

     

     

    Thanks. Yes... I didn't catch that because I tested the code on my HC2, and purely, out of habit, I defined the lua table like this:

     

    Please login or register to see this code.

    You see the important difference? No quotes! So my values were all of type "number", while the original question defined them as strings! It's syntactic sugar, again!

     

     

    I also fixed another issue, in case you use a wrong ID and your device doesn't exist:

     

    Please login or register to see this code.

    This is very idiomatic Lua:

     

    (fibaro:getName(v) or "")

     

    and it means: get the name, or alternatively use an empty string if the name was nil. This is needed because the concatenation operator refuses to add nil to a string and aborts the script...

    Link to comment
    Share on other sites

  • Topic Author
  • 6 minutes ago, samuel said:

    Thanks guys: did did the trick:

    Please login or register to see this code.

     

    @samuel

     

    Great news

    if you use the rest of @petergebruers code it'll give you a bit more resilience

     

     

     

    Link to comment
    Share on other sites

    How to compare a value from a table, so that an action can be performed?

     

    table = {
      [1] = "dim",
      [2] = "bright",
      [3] = "off",
    }

     

    if value from number [1] == "dim" then

    -- code

    end

     

    thanks for your help

    Link to comment
    Share on other sites

    6 hours ago, samuel said:

    How to compare a value from a table, so that an action can be performed?

    (...)

     

    Here's an educational example. Does this help?

     

    Please login or register to see this code.

     

    Link to comment
    Share on other sites

    Join the conversation

    You can post now and register later. If you have an account, sign in now to post with your account.

    Guest
    Reply to this topic...

    ×   Pasted as rich text.   Paste as plain text instead

      Only 75 emoji are allowed.

    ×   Your link has been automatically embedded.   Display as a link instead

    ×   Your previous content has been restored.   Clear editor

    ×   You cannot paste images directly. Upload or insert images from URL.

    ×
    ×
    • Create New...