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

Guest dobsovicj
On 5/27/2020 at 6:31 PM, 10der said:

@Bodyart Dear!

 

no.

fibaro.call(plugin.mainDeviceId, "setVariable""BodyArt""rulez!")

Please login or register to see this link.

 

Please login or register to see this link.

 

Hello @10der,

please, can you help me with QA? Is it possible to change "the value" of for example Humidity senzor (QA)?

 

Is it possible to use command: 

self:updateProperty("value"10.00
 
from other QA?
Thank you.

 

Link to comment
Share on other sites

  • Topic Author
  • 2 hours ago, dobsovicj said:

     

    Hello @10der,

    please, can you help me with QA? Is it possible to change "the value" of for example Humidity senzor (QA)?

     

    Is it possible to use command: 

    self:updateProperty("value"10.00
     
    from other QA?
    Thank you.

     

     

    fibaro.call(<other_QA_deviceID>,"updateProperty","value",10.00)

    Link to comment
    Share on other sites

    How do I get data from a nested json file?

     

    I’m trying to get some values from a json table. If I simplify the data (cut and paste some date) it works, but I want to retrieve the data from the original file. 
     

    The table looks like: 

     

    Please login or register to see this attachment.

     

    And the structure is like this:

     

    Please login or register to see this attachment.


     

    This ain’t working:

    Please login or register to see this code.

     

    How do I retrieve the two values “sensordatavalues” ??? 
     

     

     

    Link to comment
    Share on other sites

  • Topic Author
  • 47 minutes ago, SmartHomeEddy said:

    How do I get data from a nested json file?

    I’m trying to get some values from a json table. If I simplify the data (cut and paste some date) it works, but I want to retrieve the data from the original file. 

    The table looks like: 
     

    This ain’t working:

    Please login or register to see this code.

     

    How do I retrieve the two values “sensordatavalues” ??? 

     

    Looks like it's an array on toplevel?

    Please login or register to see this code.

     

    • Thanks 1
    Link to comment
    Share on other sites

    15 minutes ago, jgab said:

     

    Looks like it's an array on toplevel?

    Please login or register to see this code.

     

     

    Thanks @jgab

    That works !

    Link to comment
    Share on other sites

    How can i trigger a QA function by a sensor?

    I can use a scene to call the QA function, is it possible without the extra lua scene?

     

    In a lua scene in DECLARATIONS i can set a trigger for a motion sensor (id:36)

     

    {
      conditions = { {
          id = 36,
          isTrigger = true,
          operator = "==",
          property = "value",
          type = "device",
          value = true
        } },
      operator = "any"
    }
     
    And then in ACTIONS i can call a QA function "Action" with ID:48
     
    fibaro.call(48"Action"
    Link to comment
    Share on other sites

  • Topic Author
  • 48 minutes ago, xirilius said:

    How can i trigger a QA function by a sensor?

    I can use a scene to call the QA function, is it possible without the extra lua scene?

     

    In a lua scene in DECLARATIONS i can set a trigger for a motion sensor (id:36)

     

    {
      conditions = { {
          id = 36,
          isTrigger = true,
          operator = "==",
          property = "value",
          type = "device",
          value = true
        } },
      operator = "any"
    }
     
    And then in ACTIONS i can call a QA function "Action" with ID:48
     
    fibaro.call(48"Action"

    Yes... or did you encounter any problem?

    Link to comment
    Share on other sites

    This works fine but i use a lua scene (just for the trigger) and a QA.
    My question is: "is it possible without the extra lua scene?"

    And how does that work?
    How can i combine this? (Put the triggering in the QA itself)

    Edited by xirilius
    Link to comment
    Share on other sites

  • Topic Author
  • 10 hours ago, xirilius said:

    This works fine but i use a lua scene (just for the trigger) and a QA.
    My question is: "is it possible without the extra lua scene?"

    And how does that work?
    How can i combine this? (Put the triggering in the QA itself)

    Ok,

    You need to poll the device to see if it changed value - This polls every second - you can make it 1/2s without causing issues. It depends on how quick you want it to react to a changed value. 

    Please login or register to see this code.

    This sends the new value to the Action function, check there if it's true and do whatever you should do...

     

    Alternatively, you use a helper QA like this. one

     

    Edited by jgab
    Link to comment
    Share on other sites

  • Topic Author
  • 6 hours ago, jgab said:

    Ok,

    You need to poll the device to see if it changed value - This polls every second - you can make it 1/2s without causing issues. It depends on how quick you want it to react to a changed value. 

     

     

    Just as a note. It may seem resource hogging to poll for values this way - and to some extent it is. One way around it is to have only one QA poll for events and send to the others like in the example I linked to in the last post (event-watcher).

    If I do a simple test using the polling example in the previous example

    Please login or register to see this code.

    Here I start 500 setInterval loops that poll a device. The setInterval loops do it every 500ms. I also spread them out a bit (the sleep) so they will not run at the same time thus spiking the load.

    If I run this my CPU load goes up from ~20% to ~50%, which is not that bad.It gives a feeling on what it costs...

    Now these are running in the same QA. If you would spread these 500 loops over several QAs I would expect the load to increase a bit more.

     

    I would like though that there was a QA function to register a callback for specific triggers, maybe using the "conditions" format from scenes as a filter.

    Edited by jgab
    Link to comment
    Share on other sites

  • Topic Author
  • File: 

    Please login or register to see this attachment.

    v0.23 

     

    Some documentation on the basic toolbox <

    Please login or register to see this link.

    >

     

    I have started to assemble a toolbox of "QuickApp" functions that are missing or "good to have". Based on my best practices so far - or functions that I'm "missing". I'm using it as a baseline for the QAs I'm currently coding.

    Backward compatible with existing functions but add easy handling of children, easy scheduling of timers, formatting of output, updating type of QA, etc.

    Also supports optional event handler that simplifies asynchronous code (like http) and will make it easy to declare sourceTrigger handlers in the QA -tbd (based on the same mechanism as in eventrunner)

     

    It's modular and any module can be removed from the code if wanted. Modules that you need should be listed in local variable 'modules' in the beginning of the QA, see examples below). 

    Then the QA files need to be added to your QA.

    If you have a 'main' file your structure could look like:

    Please login or register to see this image.

    /monthly_2020_07/filesQApic.png.199213efd35a8018a06dffc4129f0a43.png" />

    Of course you could have more files.

     

    The current modules are:

    • '

      Please login or register to see this link.

      ' - always loaded as other modules depend on it
    • '

      Please login or register to see this link.

      ' - extra functions for managing child devices
    • '

      Please login or register to see this link.

      ' - extra function for setting up event handlers and structure your code accordingly.
    • '

      Please login or register to see this link.

      ' - extra functionality for receiving triggers (like scenes) - per default sends triggers to 'events' module if available 
    • '

      Please login or register to see this link.

      ' - functions to copy QA files
    • '

      Please login or register to see this link.

      ' - module for remote (synchronous) functions provided from another  "library" QA.
    • '

      Please login or register to see this link.

      ' - module for publish/subscribe functions for exchanging events between QAs
    • '

      Please login or register to see this link.

      ' - a module to manipulate UI elements. Ex adding/removing labels
    • Please login or register to see this link.

       - makes it possible to do "loadstring" or evaluate Lua expression from strings
    • Please login or register to see this link.

      - Functions for timing code used in QA

     

    A convenient way to add the files is to install the QA_toolbox QA (linked at the top the post). Then in your QA add this:

    Please login or register to see this code.

    If you install a never version of the QA_Toolbox the new files will be copied when your QA restarts.

     

    The QA Toolbox

    Please login or register to see this link.

    and makes it easy to include the modules and automatically create/debug/deploy a multi-file QA. 

     

    The functions currently available are:

    Please login or register to see this code.

    You declare your own functionQuickApp:onInit() but you can keep it simple as the toolbox will log the name, deviceID, type etc of your QA at startup.

    It will also load and initialise child devices if you have any.

    Ex.

    Please login or register to see this code.

    All quickAppvariables will be loaded and put in the self variable config.

    e.g. a quickAppVariable "Test" will be available in self.config.Test

    Ex.

    Please login or register to see this code.

    There are some self variables that can be set to affect how things are logged.

    self._2JSON = true will convert tables to json strings before they are printed (with self:debug etc) - default is true

    self._DEBUG = false will ignore self:debug logs - default is true 

    self._NOTIFY = true will create NotificationCenter entries for self:warning and self:error messages - default is false

    self._HTML = true will replace spaces with &nbsp; and \n with <br> in log printouts with self:debug/self:tracef - default is true

     

    You can change name, and interfaces of the QA with self:setName(name), self:addInterfaces(table)

    If the name is the same as the current name the actions will not be carried out. This is because they typically restart the QA and will create an infinite loop of restarts otherwise.

     

    Ex.

    Please login or register to see this code.

     

    Another example using (local) event handlers to create timed loops

    Please login or register to see this code.

    A third example using triggers to react on a device (device id 66)  changing state

    Please login or register to see this code.

    Note, need to call self:enableTriggerType with the type of events you want to receive. This is to avoid unnecessary processing of events you are not interested in.

     

    Version 0.3.

     - Children inherit toolbox functions like self:tracef etc.

    - Removed self:setup() for children - use quickAppVariables instead.

    - Code is modular - any module (childs,events,triggers,rpc) can be removed from code

    Version 0.4 - Fixed bug in 'rpc' module

    Version 0.5 - self._HTML=true will replace spaces with &nbsp; and <newline> with <br> for self:debug/self:tracef - gives nicer log printout

    Version 0.6 - Various bug fixes. HTTPEvent for asynchronous http requests.

    Version 0.7 - Event handling improvements

    Version 0.8 - Bugfixes galore....

    Version 0.10 - Better handling of childDevices

    Version 0.12 - Better handling of NotificationCenter

    Version 0.14 - Support for new QA file format

    Version 0.15 - More modular, utilizing the QA file structure.

    Version 0.16 - Bug fixes and pushYesNo and prettyJsonStruct

    Version 0.17 - Bug fixes and addition of pubsub module

    Version 0.19 - Bug fixes and addition of ui module

    Version 0.21 - Fixes and addition of lua compiler/parser

     

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

  • Topic Author
  • The

    Please login or register to see this link.

     posted previously makes it easy to code QAs that triggers on HC3 events - like Scenes do.

    The events currently supported are:

    Please login or register to see this code.

    I try to be close to the scene sourceTrigger format.

     

    To receive triggers you add an event handler function that will receive triggers

    Please login or register to see this code.

    It works well with the 'events' module that automatically adds itself as an event handler for triggers

    Please login or register to see this code.

     

    Edited by jgab
    Forgot to use self:enableTriggerType in examples
    • Thanks 1
    Link to comment
    Share on other sites

  • Topic Author
  • The 

    Please login or register to see this link.

     also have support for remote calls to use functions exported from other QAs

    Here is an example library

    Please login or register to see this attachment.

    It exports 2 functions.

    'jsonFormat' that pretty formats lua tables as json structs

    'sunCalc' that calculates sunrise, sunset, down, dusk for any date (unix/epoc time, what you get from os.time())

     

    To use it:

    Please login or register to see this code.

    The self:importRPC(id) takes the id of another QA exporting functions and declare them in this QA - it will also list in the log what functions was imported.

    Because the functions are 'synchronous' we can do self:debug(remoteFunction()), i.e. they behave like normal functions.

    These "remote" functions are not as fast as normal Lua calls but pretty fast (less than 100ms) but it of course depends on what calculations the function does.

    However, they are useful for code you use seldom and don't want to include in every QA...

     

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

  • Topic Author
  • Here is an example of QuickAppChild devices using the 

    Please login or register to see this link.

    .

    The idea is that we have a main QA that steers 3 rollerShutters as one. up/down/stop/setValue

    Then we have 3 childDevices that can be steered individually.

    Please login or register to see this attachment.

    The QA toolbox lets us focus on providing the logic for the devices. The example just log a theoretical http request .

    Please login or register to see this code.

    Here is the full QA to play with 

    Please login or register to see this attachment.

     

    Edited by jgab
    Link to comment
    Share on other sites

    I took the challenge to create child devices for my Luftdate.info (air polution) quickapp. 
     

    I now have child devices for Temperature, Humidity, PM2.5 level and PM10 level. That way I would like to use a separate scene to read the values of a child device, for instance to notify for high levels. 
     

    My question is: how can I update the value property of the child devices, every time I read out the sensor from the “mother” quickapp? 
     


     

    Edited by SmartHomeEddy
    Link to comment
    Share on other sites

  • Topic Author
  • 20 minutes ago, SmartHomeEddy said:

    I took the challenge to create child devices for my Luftdate.info (air polution) quickapp. 
     

    I now have child devices for Temperature, Humidity, PM2.5 level and PM10 level. That way I would like to use a separate scene to read the values of a child device, fir instance to notify for high levels. 
     

    My question is: how can I update the value property of the child devices, every time I read out the sensor from the “mother” quickapp? 
     

     

    In short, the mother needs to find the child she wants to update and call child:updateProperty("value",newValue)

     

    So the mother needs to have a way to map external sensors/devices to each of her children - and that can be done in different ways.

    If you have used my framework in the previous post I would recommend you do like this:

     

    When you create them or when they are loaded all your children are put in the self.childDevices variable. It's a key-value list with {childID1=childObject1, childID2=childObject2, childID3=childObject3, ...}

     

    One way is to map to the names you gave the children. (assuming the child names are unique)

    If your temp sensor has the name "Temp 1" and another "Temp 2" and your humidity has the name "Humidity 1" etc. you can do 

    Please login or register to see this code.

    and later access them as 

    Please login or register to see this code.

     

    You can also store additional data in the child to tell the difference between different devices.

    In the previous post I had 3 rollerShutters all mapping to the same class - 'Shutter'

    There I instead give each rollerShutter a quickAppVariable 'sid' that is the shutter ID of that shutter object.

    Please login or register to see this code.

    and in the class' __init method I move the quickAppValue 'sid' over to a self.variable of the child

    Please login or register to see this code.

    Then I can loop over self.childDevices and find out what each child has as shutter id (in child.sid)

     

    Note, the first time you run the QA there will be no children so the loop in :onInit() will find no children and not create a map in self.children{}

    However, your code will create child devices in some way and then need to map it correctly in your self.children variable.

    So when you create "Temp 1" the first time you do self.children['Temp 1']=self:createChild{name = 'Temp 1', ...}

    etc.

     

    Please ask if something is unclear. I could also have a look at your QA and give some advice if you want.

     

    Link to comment
    Share on other sites

    Thanks !

     

    I tried the first method:

    Please login or register to see this code.

    and later access them as 

    Please login or register to see this code.

    That works !!

     

     

    And if someone changes the name, than the updateProperty doesn’t work anymore?

    I will study on the second method. 
     

    This is the source of the quickapp

     

    Please login or register to see this code.

     

     

     

     

     

     

     

    Edited by SmartHomeEddy
    Link to comment
    Share on other sites

  • Topic Author
  • 7 hours ago, SmartHomeEddy said:

    Thanks !

    I tried the first method:

    That works !!

    And if someone changes the name, than the updateProperty doesn’t work anymore?

     

    Ok, the 3rd method, and a bit more "object oriented" in style,  is to delegate the actions to the children themselves.

    The idea is that you send all the data you collected to all the children, and each child picks out the data relevant for it and uses that to update whatever.

    Here we define a method :updateValue for all children that we call. Then we don't need to know their names - they know what to do with the data...

    I haven't been able to test it but at least it compiles :-)

    Please login or register to see this code.

     

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

  • Topic Author
  • I would probably do the loop like below. Then you can keep 'ipaddress' etc as local lua variables and don't need to read them in every time in the loop.

    ...and you are not using the 'otherData' field so I removed that too.

     

    Please login or register to see this code.

     

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

    Hi,

    I like the idea so i thought i might modify it a little for my sensor, but i failed :(  Need some help please ?

     

    My sensor address is :  192.168.1.100 for example

    The Path is :  /j

    Full Address: http://192.168.1.100/j

    The response in chome is :  {"data":{"id":"160000EF","type":"16","temperature":30.32,"humidity":48.87,"pressure":99760,"pm1":23,"pm25":39,"pm10":46,"uptime":2692308}}

     

    So i added the variables: IPaddress, Path, Interval and UserID.  Local url gets created correctly, child devices also but QA crashes in

    [30.06.2020] [09:34:00] [ERROR] [QUICKAPP1109]: line: 32 attempt to call a nil value (global 'getChildVariable')

     

    any ideas please ? I did not change anything apart from setting up the variables. I know i will have to , but up to this point it should work ?!

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