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


How to call a child function from a QuickApp-Mother?


pflugj
 Share

Recommended Posts

Hi. there.

I am trying to adopt some of the brilliant code from "jgab" and "SmartHomeEddy" and most likely some others,
to write a QA to read out data via MQTT.


I have been reading through jgab's tutorial - I do not know how many times and I will most likely have to do it a couple more times
 
The QA has create the child defined like so:
--=-=-=-=-=-=-=
class 'InverterPower'(QuickAppChild)
function InverterPower:__init(dev)
  QuickAppChild.__init(self,dev)
  self:trace("InverterPower QuickappChild initiated, deviceId:", self.id)
end

function InverterPower:updateValue(data)
    self:trace(self..":updateValue - entered")
    self:trace(data.AC_Consumption_L1_Power)
    self:updateProperty("value", tonumber(data.AC_Consumption_L1_Power))
    self:updateProperty("unit", "W")
    self:updateProperty("log", data.lastUpdateTime )
    self:trace(self,"finished")
end
--=-=-=-=-=-=-
The childs are created and are visible in the WebUI.


When the QA receives a "MQTT topic" it should update the value of that Child: "InverterPower"
The self:trace displays the message in the terminal, meaning the message was intercepted!
...but some how it doesn't execute the following command:

InverterPower:updateValue(data)

There is "NO error message" at this point!
 
The function that receives MQTT messages looks like so:
----------------------------------------
function QuickApp:onMessage(event)
    _value = event.payload
    local tbl = json.decode(event.payload)
    if     event.topic == ("N/"..vrmID.."/system/0/Ac/Consumption/L1/Power") then
            data.AC_Consumption_L1_Power = tbl.value
            self:trace("AC Consumption on L1:",data.AC_Consumption_L1_Power .."W")            -- this message is correctly displayed in the terminal
-- vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv            
            InverterPower:updateValue(data)
--^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^            
    else self:error ("No Topic matched")
    end
end
---------------------------------------

So: What is wrong here??

 

I have already spent more than 2days on solving this but I am to stupid to figure out what is wrong :-(
How must I call the Child function:

"Inverter:Power:updateValue(data)??

 

Any advice/idea is highly appreciated
Cheers

 

Link to comment
Share on other sites

Looks like it could work. I update the child devices with this routine:

 

Please login or register to see this code.

 

But it looks like you do in a different way the same. Maybe put this code in the place of yours?

 

 

Link to comment
Share on other sites

So you only have one child?

In your :onInit() function you create and load childDevices. When you do that

the QuickApp.childDevices variables will be set to a table with {ID1=childObject1, ID2=childObject2, ...}

If you only have one child the list only contain one entry.

 

When you do

InverterPower:updateValue(data)

you call updateValue on the class, not the child object (you can create many children from the same class)

Your child objects will be in the self.childDevices table.

 

To call the child, do like @SmartHomeEddy suggests. 

Please login or register to see this code.

Now every child gets called, but I assume you only have one? Otherwise the child can look at the data and decide if it is data for it.

I would probably send the whole event to the children and let them decide if it's data that they care about.

This way you also don't need to concern yourself with what deviceId the child got.

Edited by jgab
Link to comment
Share on other sites

  • Topic Author
  • Hi and thanks for the advice.

     

    There are more than 1 child, currently 3 ... and the family is about to grow :-)

    Just to simplify my problem I only showed one device, as the others I have so far do exactly the same: "nothing"

     

    I understand the loop through the devices but as far as I can see,

    there is only 1  MQTT topic received per function call: QuickApp::onMessage(event)

    Meaning: In most case there is also only 1 value to update

     

    So instead of updating ALL child's I wanted to speed up the process and update ONLY the once where the update is needed.

     

    The "MQTT explorer" that I use to monitor the Victron MQTT Broker shows quite number of value updates per second on various topics I want to monitor.

     

    I was also thinking of using the self:updateProperty("log", os.date()) to monitor when the last "child" update was done.

     

    I tried the loop like so:
    function QuickApp:onMessage(event)
        _value = event.payload
        local tbl = json.decode(event.payload)
        --self:debug( "Received Topic:", event.topic, "payload:",_value)
        data.lastUpdateTime = os.date()
        if      event.topic == ("N/"..vrmID.."/system/0/Ac/ActiveIn/Source") then
                data.AC_ActiveIn_Source = tbl.value
                self:trace("AC Active In:", data.AC_ActiveIn_Source)
                
        elseif     event.topic == ("N/"..vrmID.."/system/0/Ac/Consumption/L1/Power") then
                data.AC_Consumption_L1_Power = tbl.value
                self:trace("AC Consumption on L1:",data.AC_Consumption_L1_Power .."W")
                --InverterPower:updateValue(data)
                            
        elseif    event.topic == ("N/"..vrmID.."/system/0/Dc/Battery/Power") then
                data.DC_Battery_Power = tbl.value
                self:trace("Battery Power:",data.DC_Battery_Power.."W")
                --Battery_Power.updateValue(data)
                            
        elseif    event.topic == ("N/"..vrmID.."/system/0/Dc/Pv/Power") then
                data.DC_PV_Power = tbl.value
                self:trace("PV Power:",data.DC_PV_Power.."W")
                --PV_Power.updateValue(data)
                
          else self:error ("No Topic matched")
        end

    --vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
      for id,child in pairs(self.childDevices) do print("ChildId:", id, child ) child:updateValue(data) end

    --^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    end

    In the terminal I can see all topics get updates but it actually updates only the last defined child ("Battery Power")  ;-(  at least something

    I have also noted that the child:updateValue() loops through only 2 of the 3 devices ( the 1st and last defined)   🤫

    [2021-08-11] [16:10:04] [TRACE] [QUICKAPP3309]: PV Power: 3744.880991539W

    [2021-08-11] [16:10:04] [DEBUG] [QUICKAPP3309]: ChildId: 3312 custom [luabind::detail::null_type] object: (nil)

    [2021-08-11] [16:10:04] [DEBUG] [QUICKAPP3309]: ChildId: 3310 custom [luabind::detail::null_type] object: (nil)

    [2021-08-11] [16:10:05] [TRACE] [QUICKAPP3309]: AC Consumption on L1: 3791W

    [2021-08-11] [16:10:05] [DEBUG] [QUICKAPP3309]: ChildId: 3312 custom [luabind::detail::null_type] object: (nil)

    [2021-08-11] [16:10:05] [DEBUG] [QUICKAPP3309]: ChildId: 3310 custom [luabind::detail::null_type] object: (nil)

    [2021-08-11] [16:10:06] [TRACE] [QUICKAPP3309]: PV Power: 3721.8301398468W

    [2021-08-11] [16:10:06] [DEBUG] [QUICKAPP3309]: ChildId: 3312 custom [luabind::detail::null_type] object: (nil)

    [2021-08-11] [16:10:06] [DEBUG] [QUICKAPP3309]: ChildId: 3310 custom [luabind::detail::null_type] object: (nil)

    [2021-08-11] [16:10:07] [TRACE] [QUICKAPP3309]: AC Consumption on L1: 3776W

    [2021-08-11] [16:10:07] [DEBUG] [QUICKAPP3309]: ChildId: 3312 custom [luabind::detail::null_type] object: (nil)

    [2021-08-11] [16:10:07] [DEBUG] [QUICKAPP3309]: ChildId: 3310 custom [luabind::detail::null_type] object: (nil)

    [2021-08-11] [16:10:08] [TRACE] [QUICKAPP3309]: PV Power: 3594.2917950897W

    [2021-08-11] [16:10:08] [DEBUG] [QUICKAPP3309]: ChildId: 3312 custom [luabind::detail::null_type] object: (nil)

    [2021-08-11] [16:10:08] [DEBUG] [QUICKAPP3309]: ChildId: 3310 custom [luabind::detail::null_type] object: (nil)

    [2021-08-11] [16:10:10] [TRACE] [QUICKAPP3309]: Battery Power: -555W

    [2021-08-11] [16:10:10] [DEBUG] [QUICKAPP3309]: ChildId: 3312 custom [luabind::detail::null_type] object: (nil)

    [2021-08-11] [16:10:10] [DEBUG] [QUICKAPP3309]: ChildId: 3310 custom [luabind::detail::null_type] object: (nil)

    [2021-08-11] [16:10:11] [TRACE] [QUICKAPP3309]: PV Power: 3225.0041203079W

    [2021-08-11] [16:10:11] [DEBUG] [QUICKAPP3309]: ChildId: 3312 custom [luabind::detail::null_type] object: (nil)

    [2021-08-11] [16:10:11] [DEBUG] [QUICKAPP3309]: ChildId: 3310 custom [luabind::detail::null_type] object: (nil)

    ...

     

     

     

     

    Link to comment
    Share on other sites

    I kind of initialize all the data.[variables] at startup, so I never get a null value. I think you need to put a value in the other data.[variables]

     

     

    This is the way I walk through my quickapps

    onInit

    setupChildDevices

    getQuickAppVariables

    createVariables

    getData (or simData if I only want to test/simulate)

    I loop the getData with: 

       getValues

       updateLabels

       updateProperties

       updateValue (Childs devices)

     

     

     

    Edited by SmartHomeEddy
    Link to comment
    Share on other sites

    My thinking was that you should. handle most of the work  in the child's updateValue method.

    Your global data table I renamed to gData and I only exemplify with the InverterPower class. Do you need the gData. table? We can see the children as data structures where we can keep values relevant to each child.

    In the self.childDevices loop we check if they want the topic before calling (we could  also do that in thee child)

    We can prepare the child with topic in it's constructor.

    Please login or register to see this code.

    I have not tried the code. so there could be typos.

    Edited by jgab
    Link to comment
    Share on other sites

    If you give each child a name you could store that in a table (done in the Child constructor) to quickly find the child from anywhere in the code and don't have to rely on deviceId.

    Ex.

    Please login or register to see this code.

     

    If the InverterPower child is named "AC_Consumption_L1_Power" then you can fro anywhere in the code ex. find the power by

    Please login or register to see this code.

     

    Hindsight; I would probably rename self.AC_Consumption_L1_Power to self.power...

    Edited by jgab
    Link to comment
    Share on other sites

  • Topic Author
  • Hi and thank you so much!👍

     

    Here it is almost sunset and I will have to shut down the PC to conserve Battery Power 🥺

    I will try to implement that tomorrow

    cheers

    Link to comment
    Share on other sites

  • Topic Author
  • Hi there.

    Thanks to

    Please login or register to see this link.

    Please login or register to see this link.

    and 

    Please login or register to see this link.

    . 👍

    I manged to implement the approach from jgab.
    ... and now i have already like ~18 childs and the family is still growing 🙂

    So far most of it works as intended :-)
    I also reviewed when/where to it is necessary to store value in local/or global variables - good that you pointed that out👍


    I do have more questions.
    Is there any interface that can display "Text" - not only in the log-part?

    I haven't-found one - so far🤔

    Some of the MQTT messages come number-coded and I tried to map them into "human readable" text-messages.

    It look's like any attempt to update values with "self:updateProperty("value", value ) requires a number value and just crashes if one tries to display some text.


    AND ... I noticed something very odd:
    There is NO error message in the terminal,  when a child fails!!
    This happened a couple of times where I had some errors in the code and the "child.update" codes was not executed

    This makes it really difficult to find errors in the child code.

    Is this normal??
    Thx again and have a nice weekend

    Link to comment
    Share on other sites

    17 minutes ago, pflugj said:

    It look's like any attempt to update values with "self:updateProperty("value", value ) requires a number value and just crashes if one tries to display some text.


    you can put some text in self:updateProperty("log", “sample text” ), below the value. 
     

    oh you found that out. Well, than only on the labels and the unit. 
     

     

    Edited by SmartHomeEddy
    Link to comment
    Share on other sites

    54 minutes ago, pflugj said:

    I do have more questions.
    Is there any interface that can display "Text" - not only in the log-part?

    I haven't-found one - so far🤔

    Some of the MQTT messages come number-coded and I tried to map them into "human readable" text-messages.

    It look's like any attempt to update values with "self:updateProperty("value", value ) requires a number value and just crashes if one tries to display some text.

    No, it's very limited here. Property values are typed so you can't store what you want - some properties are numbers, some booleans, some strings etc.

    Your mother QA could have labels and display messages on behalf of the children?

    54 minutes ago, pflugj said:


    AND ... I noticed something very odd:
    There is NO error message in the terminal,  when a child fails!!
    This happened a couple of times where I had some errors in the code and the "child.update" codes was not executed

    This makes it really difficult to find errors in the child code.

    Is this normal??

    Well, it's not really a problem with the child code. You will see the same behaviour with the QuickApp itself.

     

    In your case it's the :onMessage that's is called from a thread that makes it not very good at logging errors. (If you still have the :onMessage method)

    You could protect the code inside with a pcall and log any error yourself.

    Please login or register to see this code.

    Then you would catch the error and print out a message that could lead you to the error

     

    54 minutes ago, pflugj said:

     

     


    Thx again and have a nice weekend

     

    Link to comment
    Share on other sites

    1 hour ago, pflugj said:

    Is there any interface that can display "Text" - not only in the log-part?

     

    as jgab already said, all property values are typed. While one can add interface types to get some specific properties, or create child as specific type of device (which then give us some extra or special properties), one can as well use "userDescription" property - which is generic for all devices, and can be used for strings.

    Link to comment
    Share on other sites

  • Topic Author
  • Thx for the tips.
    I tried displaying the unit without a value but that does not seem to work either ;-(
    The label option is OK but then you have to click to see ;-(

     

    Where would I find information about the "userDescription" poperty?

    This is the first time I read something about this 🤔
    I tried:

    self:updateProperty("userDescription", self.AC_ActiveIn_Source_mapping )

    I can not see any output :-(   but at least it does not crash the child.😀
     

    @jgab
    I tried something similar to your solution :-)
    ...but yours looks so much more professional 👍

     

    cheers

    PS: That is why home-automation makes our lives so much easier!!
    Nothing else to worry about than Home-Automation
     

    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.

     Share

    ×
    ×
    • Create New...