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

11 hours ago, cag014 said:

Is anyone has knowledge how to press button inside QuickApp (beside using API, which takes 5 seconds)?

 

there is something like "self:callAction(name,values)" within QuickApps, example attached. I hope that is what you looking for.

Value can be i think used to "click" with specific value, e.g. for slider, have to test it a bit more,anyway, it works for buttons

 

Please login or register to see this attachment.

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

18 minutes ago, tinman said:

 

there is something like "self:callAction(name,values)" withing QuickApps, example attached. I hope that is what you looking for

Values can be of Course used to "click" with specific value, e.g. for slider

 

Please login or register to see this attachment.

Great.... thank you... it works perfectly...

Where you found this?

Link to comment
Share on other sites

20 minutes ago, cag014 said:

Where you found this?

 

i tought there must be something calling QA components, something generic, called after QA got UIEvent, something similar to what BUI js code is using, a shortcut - tested a bit and found it (and killed my HC3 few times to get the proper syntax). 

Edited by tinman
Link to comment
Share on other sites

  • Topic Author
  • This method does not work in later HC3 firmwares. You could add a file to the QA with the code you want....

     

    An embryo to sharable code? ;-) 

    Please login or register to see this code.

     

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

    Looks like for QuickApp there is only one instance. While QuickApp busy (for example timeout on HTTP, api.get(), loops or setInterval() ) nothing else could be done.

    Clicking on icon in devices list (turn ON/OFF) , doesn't work while QuickApp busy also.

    Beware if you're using fibaro.call() for QuickApp:function() in scenes, it is asynchronous action

     

    Edited by cag014
    Link to comment
    Share on other sites

    Please can anyone help with the following.

    Trying to get a command to an other controller. In the HC2 I used scene or an VD to do that.

    In te HC3 QA and scene it wil not work .

    so code below:

    local http = net.HTTPClient()
     
    function call(url)
      http:request(url, {
          options = { method = 'GET' },
          success =function() fibaro:debug(url.." ,done."end,
          error = function(errorcode) fibaro:debug("error=" .. errorcode) end
        })
    end
     
    if ((tonumber(fibaro:getValue(203"value")) > 0 ))
    then
        call("http://192.168.xxx.yyy/api/app/com.internet/MotionPoort")
        Debug("green""Motion bij poort"
    end
     
    Thanks
    Link to comment
    Share on other sites

    Try this... use as template and make your changes as you need

    in your scene

    f ((tonumber(fibaro.getValue(203"value")) > 0 ))
    then
        fibaro.call(<QD-ID>, "getHttp", "http://192.168.xxx.yyy/api/app/com.internet/MotionPoort")
        Debug("green""Motion bij poort"
    end
     
     
     
    Edited by cag014
    Link to comment
    Share on other sites

  • Topic Author
  • 4 hours ago, cag014 said:

    Looks like for QuickApp there is only one instance. While QuickApp busy (for example timeout on HTTP, api.get(), loops or setInterval() ) nothing else could be done.

    Clicking on icon in devices list (turn ON/OFF) , doesn't work while QuickApp busy also.

    Beware if you're using fibaro.call() for QuickApp:function() in scenes, it is asynchronous action

     

    Sorry, long post - but this is not a problem - just a new way to think about how to program (well, not that new...)

     

    -setInterval is "implemented as" a chained setTimeout, HTTP does call-backs, so they are not (really) problems. HTTP has timeouts.

    -loops and  api.X calls do take all the processing - until they are done  - often api.X calls are very fast so that is not a problem. However, api.get(/refreshState) hangs if there are no events. That's a choice by fibaro and we have to accept it... (see below)

     

    More or less the QuickApp framework looks like

    1. dofile("Your QuickApp Lua code") -- that loads in the code, and defines functions and runs all the code that is called outside your function definitions. If you have

    Please login or register to see this code.

    88 is turned on every time the QuickApp starts/re-loads before :onInit(). A QuickApp "starts" when changes are made and it's saved or when they crash: QuickApps seem to restart every ~minute when they crash.

     

    Side-note: Assume that we have a working setTimeout mechanism that can schedule functions at times. setTimout creates a "thread", but it's cooperative. which means that the next function in line to run have to wait for the current function to end. This means that you may not be scheduled exactly when you wanted, but a bit later, however, in the long run it kind of evens out. However, if the function before you is hogging all the processing by running a never terminating loop you will never get time to run. You have to cooperate.

    This is why it is so important to chop up your code in setTimeouts - to give time to other "threads".

     

    2. Then, when the code is loaded the logic looks more or less like

    Please login or register to see this code.

    It's important to do the setTimeout(fun,0) here because even if we say that we want to run immediately (0) it puts the function in the "thread" queue and other threads (setTimeouts) have a chance to run if they were waiting. The way to think about it is that every piece of code that "runs" (execution flow) starts from a setTimeout - one when the QuickApp starts. One when QuickApp:onInit() is called, one when a QuickApp:function is called from the outside - and then you have your own setTimeout/setInterval threads. (when you call self:<function> no thread is created, just a regular function call)

     

    So, back to api.get calls. They are synchronous, which means that they "hang" until they get the result and can return it - they have to. However, there is nothing stopping an implementation of api.get to still look like it's synchronous but still give time to other threads (some issues about reentrance of the api functions but has been done for half a century in distributed system).

    The same goes for fibaro.sleep() - it could also give time to other threads so that calls to the QuickApp:functions or other threads are still handled.

    The normal way in Lua is to turn synchronous calls (calls that need to hang or sleep) is to wrap them in Lua's coroutine construct and so they can be suspended and resumed when they are ready to return with whatever they were waiting for.

     

    So, I think the current QuickApp model is actually elegant - but could improve (I have a ~3000 lines framework with a gazillion of timers and api.calls without any issues (besides Lua bugs :-) )

    Improvements? They could make net.HTTPClient() look "synchronous" like it used to look like in the old VD (FHTTP function I don't remember know the name of) - to make life a bit easier for users - and still keep asynchronous version  for people that need performance.

    And they could give us Lua's coroutines - they are as safe as it gets and it would allow us to create really elegant code away from juggling massive numbers of setTimeout callbacks.

     

    The take-away: Structure your code with setTimeouts - even if it's only setTimeout(fun,0) to give time to other threads in the QuickApp (like others calling your QuickApp:functions)

    Remember - you are writing code in a cooperative threaded environments - no real threads/processes. You have to show considerations. Because it's cooperated threading it's also quite easy to avoid race-conditions and protect shared resources if you worry about that.

     

    Secondly don't do fibaro.call on your own QuickApp, as pointed out by @Krikroff .

    If you can't resist that, just redefine fibaro.call()

    Please login or register to see this code.

    So, @cag014, your problem mostly comes from fibaro not being as “cooperative” in their api calls as they could be - and you needing to divide up your loops into threads giving time to other threads to run (e.g using setInterval). 

    Edited by jgab
    Link to comment
    Share on other sites

    37 minutes ago, jgab said:

    However, api.get(/refreshState) hangs if there are no events.

    At the moment, I use that and I don't mind the fact that it "hangs" my FQA but it is indeed an interesting idea to enable processing of buttons, in that case api.get is a no-go. I might be wrong, but simply changing from looping with api.get to using callback model with httpClient should do the trick. Anyone want to give that a try? I might, but probably not this week.

    Link to comment
    Share on other sites

  • Topic Author
  • 11 minutes ago, petergebruers said:

    At the moment, I use that and I don't mind the fact that it "hangs" my FQA but it is indeed an interesting idea to enable processing of buttons, in that case api.get is a no-go. I might be wrong, but simply changing from looping with api.get to using callback model with httpClient should do the trick. Anyone want to give that a try? I might, but probably not this week.

    Most api.get are pretty fast so it’s usually no problem.

    Yes, I suspect http callbacks may not hang but it depends how they implemented it. The other question is if they honor http’s timeout option? That case you limit the “hang” and return an empty result.

    Link to comment
    Share on other sites

  • Topic Author
  • 15 minutes ago, petergebruers said:

    At the moment, I use that and I don't mind the fact that it "hangs" my FQA but it is indeed an interesting idea to enable processing of buttons

    But it’s also about enabling your own threads. Assume you have a thread loop reading from a socket in the background - you can’t have that stopped for a long time or the other end think you died. If all api’s cooperated that would be less of an issue.

    and we would have a professional platform for developing integration towards external devices - where we can juggle many sessions in “parallel”...

    I can do it without threads in my own code using  a state machine, but if the fibaro api don’t cooperate i can’t get around it. 

    Link to comment
    Share on other sites

    6 minutes ago, jgab said:

    Most api.get are pretty fast so it’s usually no problem.

    Agreed. The "refreshStates" api is an exception.

     

    6 minutes ago, jgab said:

    Yes, I suspect http callbacks may not hang but it depends how they implemented it.

    It did not hang on HC2 so I expect it not to hang on HC3 either. Here's sample code I used to demonstrate people that you can call a few URLs "in parallel"...

     

     

    Link to comment
    Share on other sites

  • Topic Author
  • 4 minutes ago, jgab said:

    I can do it without threads in my own code using  a state machine, but if the fibaro api don’t cooperate i can’t get around it. 

    But it’s mainly refreshState and there are various ways around it so it’s not really a huge problem.

     

    Link to comment
    Share on other sites

    1 hour ago, jgab said:

    The take-away: Structure your code with setTimeouts - even if it's only setTimeout(fun,0) to give time to other threads in the QuickApp (like others calling your QuickApp:functions)

    I'm struggling with api.get("/refresh...), it could hang for ~30 seconds.... (I don't have a lot of devices yet). During this time there is no chance for others.

     

     

    But thanks for sharing info, will folow your suggestion

    1 hour ago, jgab said:

    Remember - you are writing code in a cooperative threaded environments - no real threads/processes. You have to show considerations.

     

    Very sad that Fibaro doesn't show considerations too.... (the Lua errors points to bizarre lines numbers and etc...)

    Link to comment
    Share on other sites

  • Topic Author
  • 2 minutes ago, cag014 said:

    I'm struggling with api.get("/refresh...), it could hang for ~30 seconds.... (I don't have a lot of devices yet). During this time there is no chance for others.

    So one hack I use is that I inside the loop that polls for refreshState (it’s a setInterval loop that polls every second) I increase a fibaro global at the end of every loop - thus generating a global changed event so I’m sure that there will always be events in the queue - not the most elegant solution but it gets the work done . See my example on getting triggers in a QA - linked from the first post.

    Another approach is to have a separate QA that only hangs on refreshState and then posts events as they come to other QAs - via fibaro.call(id,”hereAreNewEvents”,events)

    Or, as @petergebruers suggested, use httprequest. The issue I have with this is that I have to store my credentials in the code. 

    Link to comment
    Share on other sites

    cag014 thanks

    I will try it out, i am new in way of programming so i do not understand everything but still learning.

    Can you explain me what is the QD-ID what device  ???

     

    thanks

     

    Link to comment
    Share on other sites

    1 hour ago, RobS said:

    Can you explain me what is the QD-ID what device  ???

     

    When you upload the file, it becomes QuickApp device with unique device ID (same as Zwave device)

    So QD-ID is the device ID of QuickApp.

    Again same as Zwave device ID when you run fibaro.call(<device ID>,"turnON")

    Link to comment
    Share on other sites

    @jgab

    3 hours ago, jgab said:

    Another approach is to have a separate QA that only hangs on refreshState and then posts events as they come to other QAs - via fibaro.call(id,”hereAreNewEvents”,events)

    Have followed your suggestion and created QA for refreshState using fibaro.cal(...)

    Now when I make changes in main QA and press save, the entire system freezes for a minute +  and it takes another minute for QA to run.

    Nothing work and UI unresponsive.... all four CPU cores are almost at 100% and freeze.

    It happens because the refreshState QA call function that not "ready" yet. Have verified that by not calling the function.... everything works fine while saving and restarting main QA.

    Imagine what could happen if you have a lot of scenes or other QAs which using function in QA that you have change....  disaster...

    Fibaro encourage users to use QA functions in scenes (for pressing buttons and other features) and they're proud of that.

    To all, beware about this phenomena when your system suddenly freezes.

    I hope Fibaro will return full functionality to scenes. QA is a nice toy, nothing else.

    I thought to report about it to Fibaro, but I don't have enough will power to describe it when I know nobody cares,

     

    |================================================================|

           Please don't  use collectgarbage("collect"), your HC3 will disappear.        

    |=============================================================|

    Edited by cag014
    Link to comment
    Share on other sites

  • Topic Author
  • 18 hours ago, cag014 said:

    @jgab

    Have followed your suggestion and created QA for refreshState using fibaro.cal(...)

    Now when I make changes in main QA and press save, the entire system freezes for a minute +  and it takes another minute for QA to run.

    When I get time I will try to replicate/test this - see what's going on.

     

    Another topic. Many devices that have a 'value' property also have a 'state' property that seems to be more or less synched with the 'value' property - what's the idea behind this (design) decision? Can 'value' and 'state' have different values? or is 'state' just an 'alias' for 'value'? (Not all devices I have have the 'state' property).

     

    Link to comment
    Share on other sites

    1 hour ago, jgab said:

    When I get time I will try to replicate/test this - see what's going on.

     

    Another topic. Many devices that have a 'value' property also have a 'state' property that seems to be more or less synched with the 'value' property - what's the idea behind this (design) decision? Can 'value' and 'state' have different values? or is 'state' just an 'alias' for 'value'? (Not all devices I have have the 'state' property).

     

    Yes, I saw that and I think it's a good add-on for devices with level change (dimmers, RGBW controller)

    I have RGBW controller and while value shows the level 0-99 , state shows true or false (On or Off)

    Edited by cag014
    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...