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

  • Topic Author
  • The new secret variables for QAs.

    Here is a version of QuickApp:setVariable that sets the secret/password property of a variable

    Please login or register to see this code.

     

    Usage:

    Please login or register to see this code.

    Note that the value is not encrypted so don't store secrets there... :-) 

    Link to comment
    Share on other sites

    2 godziny temu, jgab napisał:

    Note that the value is not encrypted so don't store secrets there...

    but it will be

    Link to comment
    Share on other sites

    • 4 weeks later...

    FIBARO just release the beta 5.72.14, so i updated the interfaces and types documents to latest version

     

     

    Link to comment
    Share on other sites

    cool, the new interface virtualEnergyConsumption give us some nice options in QuickApps

     

    Please login or register to see this image.

    /monthly_2021_07/image.png.ae135afa0d15f8603e5e370c1b1a41c8.png" />

    • Like 1
    Link to comment
    Share on other sites

    Does anybody know difference between Power and Energy interface and impact to Energy panel?

    In case of adding Energy interface - 

    1. I should also calculate energy property myself or it will be calculated from power?

    2. Energy property is in kW or W?

     

    Thanks

     

    Link to comment
    Share on other sites

    playing with net.TCPSocket i found interesting function, which extend the way in which one can read data.

     

    Normally we have

     

    sock:read() - to get all data
    sock:readUntil ('STOP') to reat till 'STOP' data

     

    the extra function is readBytes:

     

    Please login or register to see this code.

     

    which returns specific amount of bytes from buffer (e.g. above are 16). So one can read part of the buffer, evaluate it in success part and read then additional bytes. 

    • Like 5
    Link to comment
    Share on other sites

    On 7/17/2021 at 3:55 PM, petrkl12 said:

    Does anybody know difference between Power and Energy interface and impact to Energy panel?

    In case of adding Energy interface - 

    1. I should also calculate energy property myself or it will be calculated from power?

     

    i assume - without testing it - once one added the virtualEnergyConsumption, enabled it and the device reported some power changes, it will be calculated automatically, as the description in the picture.

     

    maybe @A.Socha or @m.roszak can tell us bit more about these virtual power metering mentioned in 5.072.14 changelog

     

     

    On 7/17/2021 at 3:55 PM, petrkl12 said:

    2. Energy property is in kW or W?

     

    none of them, i assume kWh

    Link to comment
    Share on other sites

    3 minutes ago, tinman said:

    i assume - without testing it - once one added the virtualEnergyConsumption, enabled it and the device reported some power changes, it will be calculated automatically, as the description in the picture.

     

    maybe @A.Socha or @m.roszak can tell us bit more about these virtual power metering mentioned in 5.072.14 changelog


    Generally you are right. 
    Power itself is not being used in Energy Panel but there is a mechanism which calculates consumed energy from power readings.

    And yes, Energy = kWh. 

    Link to comment
    Share on other sites

  • Topic Author
  • Posted (edited)

    I bring this up in this thread to not hijack @jakub.jezek thread

     

    My question is if this always work?

    Please login or register to see this code.

    The call (actual the Hue plugin) talks to the Hue hub asynchronous and needs to get an answer back. Risk is that the getValue returns the old value because the asynchronous call has not completed?

    I guess the plugin makes a "optimistic" property change before it gets an answer back from the Hub. However, then we have the issue if the requests fail (and the asynchronous behaviour of fibaro.call itself, more on that later) 

     

    I bring this up because this is an issue when writing QAs/plugins. 

     

    In my own Hue QA I do an optimistic property change while I wait for the response back from the Hue. It's a reasonable approach and the house will not blow up if the state is wrong once in a while. But imagine the QA control something more sensitive, like a lock or a boiler.

    If someone calls fibaro(ID,"lock") and it's supposed to update the property "locked" to true 

     

    Ex.

    fibaro.call(ID,"lock")

    if fibaro.getValue(ID,"locked") then

        -- Succeeded locking the door, will go on vacation

    end

     

    ...but in my QA I need to do an http request to lock and it's asynchronous... and the http requests failed (silently). How do I do? I guess I could send a push notification to the user that "...you know that fibaro.getValue you did to check if it was locked? I'm sorry to inform you that you got the wrong answer back..."  ;-)  

     

    So there are 2 issues here.

    (First off, I really like the new QA that allow us to write "real" devices - but there are some serious short commings, second in line is the

    Please login or register to see this link.

    )

     

    1. First http is asynchronous so it's an issue to update my QAs properties before I get an answer from my external devices. The user of my QA can call for a state change and then immediately ask for the change  (fibaro.call followed by a fibaro.getValue) and I have no way to sync that. http should be asynchronous but give us Lua coroutines and we can at least sync that part inside our QA in a reasonable way (I have users that add "code" in my QA that may do a call followed by getValue and I can at least try to control that inside my own QA).
    ...but then we have...

     

    2. fibaro.call in itself is asynchronous. 

    Here is an example:

    Please login or register to see this code.

    Please login or register to see this code.

     

    Log

    Please login or register to see this code.

    Btw, fibaro.useAsyncHandler (false) doesn't seem to affect this example - it seems only to relate to fibaro.call(self.id, ...) calls that used to hang the QA for a couple of seconds.

     

    So even if I manage to "synchronise" my QA code, the user of my QA calls it asynchronous and I may not be able to update the property in time. That's  why I wonder if the scene example always works.

     

    What to do about it?

     

    So, first I would like Fibaro to give us the Lua coroutine support that is standard and safe these days. It's already there as a standard of Lua, but being actively disabled for some reason. Look at something like

    Please login or register to see this link.

    for inspiration

     

    With coroutines we can synchronise stuff inside our own QAs. Home automation is inherently asynchronous with sensor going on and off all the time and external devices are being talked to. Not having a decent way to coordinate  asynchronous stuff is a real pain. Lua coroutines are really really helpful here and would actually make it easier for users as more advanced helper functions could be developed and shared in the community.

    A simple example; every week someone has a problem because net.HTTPClient is asynchronous.... with coroutines we could bring back a seemingly synchronous Net.FHttp that wouldn't block other setTimeouts or UIEvent/onAction callbacks. Just yield the current thread until the success/error handler resumes it.

     

    So please, @m.roszak, talk to your team about giving us coroutines....

     

    Back to the topic, the fibaro.call should be thought through a bit better. We should make fibaro.call synchronous (make onAction synchronous and the callers fibaro.call shouldn't return until onAction returns) and let the called QA decide when to return. Yes, in the sleep example above the fibaro.call should hang for 5s while the function/sleep completes. In this case it's just stupid but in others there may be a valid reason. The called QA could return immediately and spawn extra work with a setTimeout if needed.

    ...and if it's synchronous we could also allow the fibaro.call to return a value.

    Making fibaro.call being a "function call"  would make it easier for people to code and free the them from doing the risky

    Please login or register to see this code.

    dance anymore. 

     

    (Then there could be a fibaro.message(ID,...) that is asynchronous and doesn't return a value... and could be picked up by fibaro.messageCallback(fun))

     

    To implement this would not be too difficult. With Lua coroutines we could do everything within the existing framework, just patch fibaro.call and actionHandler to make fibaro.call synchronous and return values -  actually, it's not that many lines of Lua code - but of course it would be better (and maybe more efficient) if it came built-in.

    Here is an example of a hack for synchronous calls implemented in todays framework (

    Please login or register to see this link.

    ). However, with coroutines we wouldn't need to make it a busy wait for the response and we wouldn't need to use a global as message box. We could instead have a callback function that resumed the call when the response is sent back. Some kind of timeout would be needed but could be pretty long as default... and controllable with a fibaro.setCallTimeout(ms). Scenes would need some kind of message box for the return value - maybe sceneVariables are efficient enough?

     

    Dealing with asynchronous mechanisms are difficult and a good principle is that an easy to use framework should hide it from users and make everything look synchronous.

    Then if the user knows what he's doing and doesn't want to hang in a synchronous call, the user can do it in a separate thread (setTimeout) and deal with how to sync it back to his main thread when completed. (ex. by using coroutines). This way we can both have the cake and eat it - "synchronous" for most people and "asynchronous" for the occasions it's wanted.

    Most people don't "need" asynchronous calls as they do simple things that aren't time optimised and that can be synchronous (making a simple http request to set/get something from an external device)

     

    With a "flaky" execution model for user's code with no real good way to overcome the short comings, there will be no way to improve the quality of the code written for the HC3 over time - because there are always stuff outside the developers control.

    That's why it's so important that Fibaro, being responsible for the framework, constantly improves on stuff like this - because we don't get better user developed (or internally developed) QAs then what the framework allow us to - and now my QAs are buggy because I can't guarantee the behaviour - due to things outside my control (the framework).

     

    I believe that just fixing the stuff outlined in this post the user developed code/QAs would become 50+% more robust - and support calls to Fibaro will drop - and everyone will benefit...

     

    As it stands today we couldn't let the HC3 control a nuclear power plant - oh, wait, I guess it's already in the Terms Of Service....

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

  • Topic Author
  • Posted (edited)

    So here is an example of a simple QA simulator (~70 lines excluding code examples) that can run multiple QAs. It can be run in any standard Lua environment that has coroutines. It's only a subset of QA/fibaro functions and a fake net.HTTPClient. If you want to code your own offline QA emulator it's a decent start or you can use the more feature complete

    Please login or register to see this link.

    ...but for this demonstration this is enough.

    Please login or register to see this spoiler.

     

    If we run the first example with 2 QAs we get the standard behaviour in HC3 today:

    QA100

    Please login or register to see this code.

    QA200

    Please login or register to see this code.

     

    We get the expected log

    Please login or register to see this code.

    QA100 waits for a call.

    QA200 starts a PING job

    QA200 calls QA100 and fibaro.call returns nil, which is expected

    QA100 gets the call, calculates the result that no one cares about.

    We get the last PING from the job that QA200 started 

     

    This is the normal behaviour. This is a big problem as there is no way to synchronise actions and state updates in a QA as outlined in the previous post.

     

    If we had coroutines it would be pretty simple to fix this with the already existing mechanisms we have in the QA framework. Only missing piece is coroutines(!)

    Here is what is needed - still backward compatible with the original QAs:

     

    QA100-2

    Please login or register to see this code.

     

    QA200-2

    Please login or register to see this code.

     

    The log we get

    Please login or register to see this code.

    QA100 waits for call

    QA200 starts a PING job

    QA200 makes a synchronous http call and get the result back

    QA200 calls the other QA

    QA100 gets the call, calculates the value and returns it

    QA200 PING job terminates

    QA200 gets the result back and print it out

     

    Lot's of improvements with this add-on code:

    • We have a fibaro.sleep that doesn't block the other tasks. No need to use setTimeout to time actions.
      Ex.
      fibaro.call(11,"turnOn")
      fibaro.sleep(10000)
      fibaro.call(11,"turnOff")
      ...works very well and don't block other tasks in the QA
    • We have a synchronous http call (that doesn't block the other tasks)
      No need to juggle with success/error handlers if you aren't doing anything else in parallel anyway... and we would have less of the forum questions why they can't return the value from net.HTTPClient...
    • We have a synchronous fibaro.call to another QA that return a value and doesn't block tasks
      Yes, we can return values, and we can try to sync action/state for our QAs.
      Yes, we even get the errors from the called QA if something went wrong
    • We have a fibaro.setCallTimeout(ms) that controls timeouts if the called QA doesn't answers

    Much more intuitive programming model, less risks for errors due to hidden asynchronous behaviour, backward compatible, and very little overhead. What's not to like?

     

    Note, if scenes should support sync calls we need another mechanism for the return value - a scene variable or something more efficient. Some kind of signal to resume the call.

     

    Edited by jgab
    Cleanup
    Link to comment
    Share on other sites

  • Topic Author
  • This is in another thread, but I think it belongs here too. The issue with marshalling of arguments in fibaro.call

     

    Link to comment
    Share on other sites

    Jan, ChildrenofHue V1.18 I have a led cord working on/off but not possible to use saturation or brightness.

    If move slider led doest respond

    Please advice,

    //Sjakie

    Link to comment
    Share on other sites

  • Topic Author
  • Seems like they made some changes in child devices events.

    Try 1.19 with updates that should work

    Just update the code of the main file and you can keep the old QA and the existing childevices (and IDs)

    Link to comment
    Share on other sites

    Jan, you are the best!

    Thanks,

    //Sjakie

    Link to comment
    Share on other sites

    1 hour ago, jgab said:

    Seems like they made some changes in child devices events.

     

    and what part exactly?

    Link to comment
    Share on other sites

  • Topic Author
  • 3 hours ago, tinman said:

     

    and what part exactly?

    Well, they did something that made built-in child ui elements trigger onAction directly instead of going over UIEvent. Now it seems to be back calling UIEvent. My clever code that tried to handle children broke  but now I think I understand how they want it and will code it a bit better.

    Link to comment
    Share on other sites

    • 1 month later...

    Hello

     

    Anyone can give me some help..

     

    I have music on my PC stored in    "192.168.100.53/Users/Kiss/Music/MIX2.mp3"       I want to play this on SONOS. So i have followed instructions and called it like this.  fibaro.call(484"playFromCIFS","192.168.100.53/Users/Kiss/Music/MIX2.mp3")..

    First of all Fibaro/LUA cant even parse it, becasue it gives me in debug window this  onAction: {"actionName":"playFromCIFS","args":["192.168.100.53\/Users\/Kiss\/Music\/MIX2.mp3"],"deviceId":484}

     

    I tried to use the networkname of my PC "ALIENWARE/Users/Kiss/Music/MIX2.mp3" .. Any help please? Also the folder is added to my SONOS through the Sonos PC software,

    What did I do wrong?

     

    I am also trying to play Youtube music, as it is in my servicelist in SONOS, but i cant figure out how to find the URL what should beb called in FIbaro Sonos QA.. 

     

    Help is highly appreciated.

     

     

    Link to comment
    Share on other sites

    34 minutes ago, Neo Andersson said:

    I have music on my PC stored in    "192.168.100.53/Users/Kiss/Music/MIX2.mp3"       I want to play this on SONOS. So i have followed instructions and called it like this.  fibaro.call(484"playFromCIFS","192.168.100.53/Users/Kiss/Music/MIX2.mp3")..

     

    syntax is ok ...

     

    34 minutes ago, Neo Andersson said:

    First of all Fibaro/LUA cant even parse it, becasue it gives me in debug window this  onAction: {"actionName":"playFromCIFS","args":["192.168.100.53\/Users\/Kiss\/Music\/MIX2.mp3"],"deviceId":484}

     

    this is just message, that the action has been executed, nothing wrong with it

     

    34 minutes ago, Neo Andersson said:

    I tried to use the networkname of my PC "ALIENWARE/Users/Kiss/Music/MIX2.mp3" .. 

     

    not necessary, normally IP should be ok, name is good as well, if HC3 can resolve it in your network

     

    34 minutes ago, Neo Andersson said:

    What did I do wrong?

     

    it sounds like permission problem, how did you added it into Sonos? How it looks like, like 

     

    //192.168.100.53/Users

     

    or did you simply added your user folder? It must be added into Sonos as network share, with user/password.

     

     

    34 minutes ago, Neo Andersson said:

    I am also trying to play Youtube music, as it is in my servicelist in SONOS, but i cant figure out how to find the URL what should beb called in FIbaro Sonos QA.. 

     

    depends how/what are you playing it, one can re-use or not.

     

    Link to comment
    Share on other sites

    On 9/6/2021 at 12:57 AM, tinman said:

     

    syntax is ok ...

     

     

    this is just message, that the action has been executed, nothing wrong with it

     

     

    not necessary, normally IP should be ok, name is good as well, if HC3 can resolve it in your network

     

     

    it sounds like permission problem, how did you added it into Sonos? How it looks like, like 

     

    //192.168.100.53/Users

     

     

    or did you simply added your user folder? It must be added into Sonos as network share, with user/password.

     

     

     

    depends how/what are you playing it, one can re-use or not.

     

    Sorry, what do you mean be "one can re-use or not"?  Here is what i want to achieve: If I go to my PC and open the Youtube and playing my song lets say it has this URL in my browser: "

    Please login or register to see this link.

    "...so if I wanted to run this from Fibaro by a button press, how can I do ? My Youtube is added into SONOS services, just

    dont know how  to call this url in  fibaro.call(484"playFromCIFS", __what_to_add_here_)

    Thanks for your help.

     

     

    Just now, Neo Andersson said:

    Sorry, what do you mean be "one can re-use or not"?  Here is what i want to achieve: If I go to my PC and open the Youtube and playing my song lets say it has this URL in my browser: "

    Please login or register to see this link.

    "...so if I wanted to run this from Fibaro by a button press, how can I do ? My Youtube is added into SONOS services, just

    dont know how  to call this url in  fibaro.call(484"playFromCIFS", __what_to_add_here_)

    Thanks for your help.

     

     

    Also, your suggestion was right, i had to dig deeper for sharing options of my PC, so now I can play it...but the strange thing is, I can't get it work if I call it by IP address...works only if I call it by PC name...strange..

    Link to comment
    Share on other sites

    59 minutes ago, Neo Andersson said:

    Thanks for your help.

     

     

    you're welcome Mr. Anderson^^

     

    59 minutes ago, Neo Andersson said:

     

    Sorry, what do you mean be "one can re-use or not"?  Here is what i want to achieve: If I go to my PC and open the Youtube and playing my song lets say it has this URL in my browser: "

    Please login or register to see this link.

    "...so if I wanted to run this from Fibaro by a button press, how can I do ? My Youtube is added into SONOS services, just

    dont know how  to call this url in  fibaro.call(484"playFromCIFS", __what_to_add_here_)

     

    the plugin can only play streams or from shares/web.

     

    The YT link, is not exactly what Sonos is playing, you have to get the URI (check the QuickApp code .... there is description how)

     

    Please login or register to see this image.

    /monthly_2021_09/image.png.988f1f9104d00f44c4cada966e0d29c3.png" />

     

     

    and then later call it as playFromURI

     

    fibaro.call(SonosQAID, "playFromUri","stream.laut.fm/hiphop-forever")

     

     

    59 minutes ago, Neo Andersson said:

     

    Also, your suggestion was right, i had to dig deeper for sharing options of my PC, so now I can play it...but the strange thing is, I can't get it work if I call it by IP address...works only if I call it by PC name...strange..

     

    here the answer why ...

     

    Please login or register to see this link.

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