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


HC3 QuickApps coding - tips and tricks


jgab

Recommended Posts

On 10/6/2022 at 10:04 PM, colhemm said:

I have the Device ID and Local key but i'm having trouble trying to work out how to do the rest to integrate it into HC3.

 

two things:

- on TUYA developer page, cloud, api explorer, you can read the Instruction set, please read it and post here, that will be helpful

 

Please login or register to see this image.

/monthly_2022_10/image.png.020223c929706761fe3606448b998f8e.png" />

 

 

- you device is color/music/etc. device, so take the NEO Smart Bulb tuya QuickApp (maybe even work for you immediatelly .. who knows who knows)

 

Please install it, set ip, device and key, save, open edit tab, go to line 21 and set the showdebug to true (and save)

 

    self.showdebug = true

 

Now you should see lot of thing coming in the console window,

 

image.png.db75dd1d4a7c50fabce39222169de923.png

 

if so go to dashboard view and click in that tuya quickapp all the buttons and sliders, then copy all the information from console window and send me it via PM (better - let's not spam here)

 

EDIT: added some "how to use for unkown devices in EDIT2 here

 

Edited by tinman
  • Like 1
Link to comment
Share on other sites

  • 1 month later...

Hello,

 

I have a problem with QA Slider read and display value.

 

I have 10 pieces of venatian blinds and I want to adjust with the same time and same value all the venatian blinds lamella.

I created QA with slider to adjust the lamella value and one button for start the necessary Scene.

My idea is that I give the value with the slider and save this value in one Global variable. Next time when I open the QA the slider must show me the latest saved slider value.

 

Here is my QA code:

 

local tmpLamella
function QuickApp:onInit()
    self:debug("onInit")
    tmpLamella = fibaro.getGlobalVariable("LamellaValue", value)
    self:updateView("label", "text", "Label value: " .. tostring(tmpLamella))
    self:updateView("sldLamella", "value", tmpLamella)
    self:updateView("lblLamella", "text", "Lamella open % :" .. tostring(tmpLamella))
end
 
function QuickApp:onSliderChanged(event)
   tmpLamella = event.values[1]
   self:updateView("lblLamella", "text", "Lamella open % :" .. tostring(tmpLamella))
   fibaro.setGlobalVariable("LamellaValue", tostring(tmpLamella))
end

 

Please login or register to see this image.

/monthly_2022_11/image.png.ca246c2477f514bc30d633aeed769e0d.png" />

 

- Write the value to the Global Varieable --> OK, working

- Read the value from the global Variaable --> Ok, working

- Lamella open % --> shows the % of the slider what was adjusted

- Label value just for temporary here for show the init of the QA the Global Variable value

 

The problem is when I close this QA and open again the application read the Global variable and show in the "Lamella open%" and this is good.

But don't move the slider to that position. The slider is stay on the previous position value.

 

If I press the "Edit" for see the QA code and close the QA initalized and all value get the Global Variable value. But just when I go to the Edit --> see the program code.

If I just close and open the slider stay in the previously value and not on the Global Variable value.

 

As in the picture show the Global Variable is 21 but the slider stay in the value 55 what was the previous vaalue adjustment.

 

image.png.3a1cfebf6b1d0d88e7157aba60cda20b.png

image.png.64cb25dcdd3ecd19e993a8b8356040b4.png

 

image.png.9a126c7dd97cc7254065e58b5cf111a9.png

 

Can you help us to solve that issue ?

 

Thank you

Edited by Szakos
Link to comment
Share on other sites

  • Topic Author
  • 1 hour ago, Szakos said:

     

     

    Please login or register to see this link.

    Please login or register to see this link.

     

    Please login or register to see this link.

    Can you help us to solve that issue ?

     

    Thank you

     

    You don't update the label 'label in the QuickApp:onSliderChanged(event) function

    Please login or register to see this code.

     

    Link to comment
    Share on other sites

    1 hour ago, jgab said:

     

    You don't update the label 'label in the QuickApp:onSliderChanged(event) function

    Please login or register to see this code.

     

    Hi It dosn't matter the "label" is just for testing there. The problem is when I modify the slider value it will be saved in the Global Variable but if I close and open the QA the slider don't move to the value what is in the Global Variable.

    Edited by Szakos
    Link to comment
    Share on other sites

    10 hours ago, Szakos said:

    Hi It dosn't matter the "label" is just for testing there. The problem is when I modify the slider value it will be saved in the Global Variable but if I close and open the QA the slider don't move to the value what is in the Global Variable.

    Just a guess,

    Maybe its because you set the slider value only in oninit function. 

    Link to comment
    Share on other sites

    • 2 weeks later...
  • Topic Author
  • Here is a

    Please login or register to see this link.

    implementation in "limited" Lua aka works on the HC3

    <

    Please login or register to see this link.

    >

    Added to a separate QA file it will extend the json functions with json.path(<str>)

    json.path then returns a function that can traverse a Lua (json) table.

    The parser function returned by json.path can be used several times and we avoid having to re-parse the json expression every time.

    Please login or register to see this code.

    Other examples:

    Please login or register to see this code.

    It also runs all the "bookstore" examples on the net.

     

    It's useful to collect values from complex json values returned by external devices.

    It can also be used parse what we get back from api.get..

    Ex. 

    Please login or register to see this code.

     

    Please login or register to see this code.

    Edited by jgab
    • Like 3
    Link to comment
    Share on other sites

    I'm just starting to learn about QA's. I'm working through every example of @jgab fantastic tutorials and am nearly at the end of the first one  The anatomy of QuickApps - Part 1. I have sooo much to learn !!

     

    I'm stuck at this section of the tutorial......

     

    We will also have a 'createObject' function that creates new objects by creating copies of the class template.

    Please login or register to see this code.

     Lets define the functions 'createClass' and 'createObject'

    Please login or register to see this code.

    When I do.......

     

    function createClass(tab) return tab end 

    function createObject(foo) return foo end 

    myClass = createClass({a = 42, b = 17}) -- class or 'template'

    object = createObject(myClass,{a = 17}) -- copy template and initialize object with specific values

    print(object.a+object.b)

     

    I get 59

     

    I think I should get 34 because the first a = 42 should be replaced with a = 17

     

    I'm I doing something wrong ? 

     

    Thanks for any help on this

    Link to comment
    Share on other sites

  • Topic Author
  • createObject is defined in the lines below in the tutorial and is a bit more complicated

    (not sure where you got the function createObject(foo) return foo end from...)

    It needs to copy over the class values and the values we give (in that order) to our new object.

    Please login or register to see this code.

     

    Edited by jgab
    Link to comment
    Share on other sites

    3 hours ago, jgab said:

    createObject is defined in the lines below in the tutorial and is a bit more complicated

    (not sure where you got the function createObject(foo) return foo end from...)

    It needs to copy over the class values and the values we give (in that order) to our new object.

    Please login or register to see this code.

     

    Tack så mycket @jgab

    The  "function createObject(foo) return foo end", was me trying to figure out how to get it working !!  This is what happens when a 60 year old starts to learn coding from scratch 🙃

     

    Your tutorials are fantastic. I'm determined to get some QA's working and I'm tantalisingly close to "Part2" tutorial !!

     

     

    Link to comment
    Share on other sites

  • Topic Author
  • 1 hour ago, Rosavision said:

    Tack så mycket @jgab

    The  "function createObject(foo) return foo end", was me trying to figure out how to get it working !!  This is what happens when a 60 year old starts to learn coding from scratch 🙃

     

    Your tutorials are fantastic. I'm determined to get some QA's working and I'm tantalisingly close to "Part2" tutorial !!

    I think the tutorials are a bit "deep" going into how stuff work under the hood of a QA - you could probably get away coding without this - on the other hand, knowledge is never wrong :-)

    Really understanding Lua will make life easier developing QAs...

     

    I think there is a space for a missing tutorial focusing on "QA best practices" when coding...

     

    Link to comment
    Share on other sites

    @jgab  Finally the "penny dropped" for me!

    I had been struggling with using.....

     

    myClass = createClass({a = 42, b = 17}) -- class or 'template'

    object = createObject(myClass,{a = 17}) -- copy template and initialize object with specific values

    print(object.a+object.b)

     

    and getting an error... "attempt to call a nil value (global 'createClass')"

     

    Then I added ... "function createClass(tab) return tab end" at the beginning and I learned the reason for the error and how to fix it, but I got the wrong result.......

     

    function createClass(tab) return tab end

    myClass = createClass({a = 42, b = 17}) -- class or 'template'

    object = createObject(myClass,{a = 17}) -- copy template and initialize object with specific values

    print(object.a+object.b)

     

    returns 59

     

    Then based on your last post I added the Object elements and of course, it works and I understand why - I think!! .....

     

    function createClass(tab) return tab end 

    myClass = createClass({a = 42, b = 17}) -- class or 'template'

    object = createObject(myClass,{a = 17}) -- copy template and initialize object with specific values

    function createObject(class,args) 

      local obj = {} -- create a new table that is going to be our object

      for key,value in pairs(class) do obj[key]=value end -- copy the values from our class template to our new object

      for key,value in pairs(args) do obj[key]=value end -- copy the values from provided argument to initialize our new object     

      return obj -- return our new object.

    end

    print(object.a+object.b)

     

    returns 34 

     

    This is tough stuff, but worth it. Thanks again for great tutorials. Moving onto Part 2😀

     

    God jul och gott nytt år

    • Thanks 1
    Link to comment
    Share on other sites

    • 3 weeks later...

    Its @jgab its still early days for me with QA’s and I’ve got another syntax problem.

     

    I’m setting up a QA to monitor movement sensors (from several rooms) and depending on which movement sensor is triggered, different QuickApp functions will run.

     

    The code is very basic at the moment, its running in a loop (not included below), and it works with one movement sensor being triggered and calling QuickApp:lounge() which turns the lights on & then off

     

    sensors ={718}

    room={"lounge"}

    if#sensors>0 then

    for i = 1,#sensors do

     a=fibaro.getValue(sensors[i],"value")

     b=(room[i])

    if a>0 then self:lounge() else 

    end end end

     

    To be able to scale this I want to add more “sensors” and “rooms” like below and instead of calling self:lounge() I want to use  self:<myVariable() 

     

    sensors ={718, 820,940,980}

    room={"lounge",”B2”,”B3”,”snug”}

    f#sensors>0 then

    for i = 1,#sensors do

     a=fibaro.getValue(sensors[i],"value")

     b=(room[i])

     if a>0 then self:b()else

    end end end

     

    I’ve tried many syntax options and the one above doesn’t crash, but it also doesn’t call the QuidkApp !!

     

    Is it possible to use code which uses a variable after “self” to call a QuickApp like self:<my Variable>()

     

    Thanks for advice on this one.

    Link to comment
    Share on other sites

  • Topic Author
  • self is kind of a Lua table but you can't print it out because it's "protected".

    However, when you define 

    function QuickApp:snug()

        ...

    end

     

    it's added to the 'self' table as 

    self = { snug = function(self) ... end }

     

    note that even if you defined the function snug() taking no arguments it will have an added argument 'self' as the first argument. This is because you defined it with a ':', i.e. QuickApp:snug()

     

    Anyway, to call that function in self you do

      self['snug']()

    self['snug'] will retrieve the value that has the key 'snug', our function in this case. Then we call the function by adding ()

     

    In your case it becomes

    b=(room[i])

    if a>0 then self[b]() else ...

    • Like 1
    Link to comment
    Share on other sites

    Many thanks again @jgab  Its great that you take the time to help me with the answer and an explanation which helps me with syntax logic.

     

    Here's another thing I'm battling with... I'm trying to make one QA for whole house lighting which runs a method "QuickApp:<room>()" for each room. To make scalable I would like to be able to get the <room> part from the method name and use it as a variable within the method which can then call various tables.

     

    Example:

     

    function QuickApp:Hall()

     

    at the moment I create a variable within this method

     

    local qaRoom="Hall"

     

    What would be really cool is if I could extract "Hall" from the method name automatically, then the methods for each room could populate local qaRoom variable themselves.

     

    Setting up the variable local qaRoom="Hall" isn't so much work, but being able to automate would be 😎

     

    I've read through your notes on QA anatomy and your listing of functions and variables, but I don't see anything that enables me to do this. 

     

    Link to comment
    Share on other sites

  • Topic Author
  • 31 minutes ago, Rosavision said:

    Many thanks again @jgab  Its great that you take the time to help me with the answer and an explanation which helps me with syntax logic.

     

    Here's another thing I'm battling with... I'm trying to make one QA for whole house lighting which runs a method "QuickApp:<room>()" for each room. To make scalable I would like to be able to get the <room> part from the method name and use it as a variable within the method which can then call various tables.

     

    Example:

     

    function QuickApp:Hall()

     

    at the moment I create a variable within this method

     

    local qaRoom="Hall"

     

    What would be really cool is if I could extract "Hall" from the method name automatically, then the methods for each room could populate local qaRoom variable themselves.

     

    Setting up the variable local qaRoom="Hall" isn't so much work, but being able to automate would be 😎

     

    I've read through your notes on QA anatomy and your listing of functions and variables, but I don't see anything that enables me to do this. 

     

    Unfortunately, a Lua function doesn't know what its name is - Lua functions are just 

    function(...) ..... end

    objects that are assigned to variables or table.

    I think the trick is to let the code that calls the function pass on the name of the room. That code should know what the name is.

    How are you QuickApp:<room> functions called?

    Link to comment
    Share on other sites

    Hi @jgab That suggesting works perfectly, thanks for the great idea. All’s well & good & working on ZeroBrane but when I move into a QA on HC3 I immediately run into CPU issues with the loop set at 250ms. With the loop at 1 second HC3 doesn’t really like it. Longer than 1 second will give too much lag. 

     

    It’s frustrating that we can’t auto trigger like we can is scenes.

     

    To speed things up with less CPU I’m thinking about having one simple scene who’s only purpose is to be triggered by movement sensors and do two things. 1. It send a trigger to a receiving QA method 2. Save the trigger ID as a variable which the receiving QA method uses to trigger the correct room method.

     

    Not a very elegant solution but I’m hoping that it will be faster than the 1 second loop and it should consume less CPU

     

    Any thoughts on this approach?

     

     

     

    Link to comment
    Share on other sites

  • Topic Author
  • Posted (edited)
    1 hour ago, Rosavision said:

     

    Hi @jgab That suggesting works perfectly, thanks for the great idea. All’s well & good & working on ZeroBrane but when I move into a QA on HC3 I immediately run into CPU issues with the loop set at 250ms. With the loop at 1 second HC3 doesn’t really like it. Longer than 1 second will give too much lag. 

     

    It’s frustrating that we can’t auto trigger like we can is scenes.

     

    To speed things up with less CPU I’m thinking about having one simple scene who’s only purpose is to be triggered by movement sensors and do two things. 1. It send a trigger to a receiving QA method 2. Save the trigger ID as a variable which the receiving QA method uses to trigger the correct room method.

     

    Not a very elegant solution but I’m hoping that it will be faster than the 1 second loop and it should consume less CPU

     

    Any thoughts on this approach?

     

    Are you attempting to loop and check sensors?

    The trick is that you shouldn't. There is an underlying mechanism in the HC3 that emit events when a device, like a sensor, changes state. These are the events that a scene can trigger on.

    There is no ready made way to do that in an QA, but we can access the event stream with the api.

    api.get("/refreshStates")

     

    I would strongly recommend you to use my readymade library, fibaroExtra.lua, that you can add to any QA as an extra file. It also works to use fibaroExtra in QAs developed with ZeroBrane. (include it with the --FILE directive)

     

    It will add a lot of functions, but in particular functions to work with events and triggers in a QA.

        function QuickApp.post(_,...) return fibaro.post(...) end
        function QuickApp.event(_,...) return fibaro.event(...) end
        function QuickApp.cancel(_,...) return fibaro.cancel(...) end
        function QuickApp.postRemote(_,...) return fibaro.postRemote(...) end
        function QuickApp.publish(_,...) return fibaro.publish(...) end
        function QuickApp.subscribe(_,...) return fibaro.subscribe(...) end

     

    It will let you trigger on system events. post your own custom events. post and handle events between different QAs. ...and even a publish/subscribe system that lets one QA publish an event and every QA that subscribes to the event will receive it - thus decoupling the sender receiver so they don't need to know each others IDs.

     

    The fibaroExtra also contains a lot of other "missing" QA functions and it can be a good source to look at how things are implemented.

     

    Anyway, the event model is something I swear by and use in all my QAs as it lends itself well to QAs needing to react to asynchronous stuff/events going on.

     

    Please login or register to see this image.

    /monthly_2021_07/layers.png.19435943d1287e3c3f0bfec339e165ce.png" />

    Let me know if you need some examples, happy to spread the gospel of "event handling" for QA programming....

    Edited by jgab
    • Like 1
    Link to comment
    Share on other sites

    Hi @jgab, thanks as always. This has made me think! I have some homework to do, learning how to work with event streams with API, but I am sure I will find what I need in your tutorials. I will also take your advice and utilise fibaro extra. I'll give you a shout if I need more help.... Hmmmm when I need more help !!

    Link to comment
    Share on other sites

    • 2 weeks later...
  • Topic Author
  • Think this is a good example of a QA with children. Credits to

    Please login or register to see this link.

    in the French forum 

     

    It creates children defined in the children Lua table (6 children)

    It removes children not in the table (if you change the number of children)

    Each child has a unique ID that is used to call methods on the children

     

    Now all the children is of the same type, but the initialisation table 'children' can contain type and class also, to initialise children of different types.
     

    Please login or register to see this code.

     

    Edited by jgab
    • Thanks 1
    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...