Announcement

Collapse
No announcement yet.

HS3 Plugin Samples

Collapse
This is a sticky topic.
X
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    #46
    Originally posted by rjh View Post
    There are 3 samples provided, did you look at the samplebasic one? That one is suppose to be just the basics.
    Embarrassing, I think I have been fighting with HSPI_SAMPLE thinking it was the SAMPLE_BASIC one. I will see how I get on, thanks.

    Comment


      #47
      Rich/Rick/anyone...if you are subscribed to this thread can I ask whether the sample_basic plugin could be updated with a nice simple .triggerfire function example? I have the triggers set up, saving and processing but I just can't for the life of me work out how to trigger from them.

      I suspect I should be de-serializing the DataIn() in the strTrigActInfo from TriggerMatches but I can't work out the method for actually de-serializing it. The in built DeSerializeObject returns false when called as bteIn is nothing.

      I am not sure whether what I am doing is just wrong or I am missing something.

      Thanks.

      Comment


        #48
        In the original sample plug-in, not the basic or MI one, in the Util.vb module, look at Demo_Proc. That shows the use of TriggerFire.

        TriggerFire is completely different to how things were done in HS2. In HS2, you would give HS2 a trigger built out to look like a trigger that matches the current state of things, and then HS2 would go through all of the triggers to see if there was one configured like that. You could also use PreCheckTrigger to gather up all of the triggers that meet criteria and see if one exists that matches certain things that may have just changed in your plug-in, and if you find one, then call into HS2.

        In HS3, rather than giving a broadly defined set of criteria to HomeSeer to then compare against all of the triggers to see if there is a match, we let you tell us when you already know there is a match with TriggerFire.

        Here is an example for both situations...

        In HS2, let's say you had (as in the current example plug-in) something that measured the weight of something, and when the weight is greater than 123lbs, you want to trigger an event. What you would do is to ask HS2 for all triggers where it is checking that the weight is greater than a value. Let's say HS2 returns 3 triggers, one is greater than 50, one is greater than 100, and the other is greater than 150. You would have to go through those and discover that two of them match, and then send those two back to HS2.

        In HS3, you already keep a collection of the triggers that were defined for your plug-in. Perhaps you got them all at startup and then you added to the list whenever BuildUI or one of the other trigger functions was called, but you already have a list and so you know that there is a trigger for the weight being greater than 50 and greater than 100. BECAUSE you knew this already, you might even optimize the polling of the weight measuring device so that you read it more frequently as it reaches 50 and 100. Regardless of when you knew the weight was over 50 and 100 because it is 123, you now have the trigger info that you can pass to HS3 in TriggerFire, and that trigger info tells HS3 exactly which event and which trigger is true - it does not have to search.

        You could build your HS3 plug-in to match how things worked in HS2 by calling TriggerMatches all the time when a triggerable value changes, but it is definitely more efficient if you load those at startup and then maintain the list. If you call GetTriggers at startup of your plug-in to get all of the triggers for your plug-in, you can then register for the event change notification from HS3 and use that as a mechanism to update the list by calling GetTriggers again.

        Let us know if this does not help!
        Regards,

        Rick Tinker (a.k.a. "Tink")

        Comment


          #49
          I do not maintain a list of the triggers for my plugin, I call GetTriggers or TriggerMatches when a triggerable value changes. Does GetTriggers is optimized (using some kind of dictionnary for example) so that to retrieve all the triggers for a specific plugin it doesn't have to rescan all the events?

          Which one is the more efficient GetTriggers or TriggerMatches ?

          For plugin with multiple instances I call GetTriggers( PLUGIN_NAME:INSTANCE_NAME) to get the triggers for a specific instance. Would it be possible to add a wildcard so that GetTriggers(PLUGIN_NAME:*) retreive all the triggers for the plugin regardless of the instance?

          Comment


            #50
            GetTriggers retrieves all of the triggers for a plug-in and does not have an argument of the instance name, but I think we should add that!

            TriggerMatches uses the plug-in name, trigger ID and subtrigger, so that is the more precise one to use when you are looking for a specific type of trigger.

            I will add the instance (probably new calls with similar names). We won't need to add the wildcard because GetTriggers and TriggerMatches already return all of them.
            Regards,

            Rick Tinker (a.k.a. "Tink")

            Comment


              #51
              Oh, and regarding the Instance - HS3 keeps track of this internally, so it is not a part of strTrigActInfo. The idea is that the instance name would be tacked on to the data that you pass (DataIn/DataOut) so that you can keep track of the instance yourself, but if it does not break anything, I will look at adding that to strTrigActInfo to make it easier.
              Regards,

              Rick Tinker (a.k.a. "Tink")

              Comment


                #52
                Originally posted by Rick Tinker View Post
                We won't need to add the wildcard because GetTriggers and TriggerMatches already return all of them.
                I don't think so, I tested this extensively for my Kinect plugin, and at least TriggerMatches only returns the triggers for the main instance (i.e the one without any instance name)
                If you want the triggers for a specific instance you have to append ":instance_name" to the name of the plugin and pass this as the first parameter.

                Comment


                  #53
                  Originally posted by mrhappy View Post
                  I suspect I should be de-serializing the DataIn() in the strTrigActInfo from TriggerMatches but I can't work out the method for actually de-serializing it. The in built DeSerializeObject returns false when called as bteIn is nothing.
                  For simplicity I will refer to just Triggers, but it is the same whether triggers or actions.

                  If DataIn is nothing or an array of 0 bytes, then you never gave anything to HS to store in DataOut, so I would expect deserialize to fail.

                  Here is how it works: When somebody changes something in TriggerBuildUI it causes TriggerProcessPostUI to be called. Let's say the user configured a trigger by entering into fields you put on the UI the values 'Widget' and 12345. You need to save those values because it is your trigger, so you have two ways you can do it. You can create YOUR own storage mechanism and use the information in strTrigActInfo such as the UID, the evRef, trigger number and sub trigger number as an index... or you can have HS3 store those values for you. To have HS3 store the values, you create some sort of object that is serializeable to hold the values the user entered, like this:
                  Code:
                  <Serializable()> _
                  Friend Class MyTriggerData
                      Friend ProductName As String = ""
                      Friend ProductSKU As Integer
                  End Class
                  Then, you put those values in the object like this:
                  Code:
                          Dim MyData As New MyTriggerData
                          MyData.ProductName = "Widget"
                          MyData.ProductSKU = 12345
                  Then you serialize that object like this:
                  Code:
                          Dim bteArray() As Byte = Nothing
                          If Not SerializeObject(MyData, bteArray) Then Throw New Exception("Dag Nabbit, another error.")
                  Then you put the serialized object into the DataOut parameter of strMultiReturn like this:
                  Code:
                          Dim Ret As New strMultiReturn
                          Ret.sResult = ""                ' Empty return indicates success!
                          Ret.TrigActInfo = TrigInfoIn    ' Trig info does not change, just pass through what we received...
                          Ret.DataOut = bteArray
                  
                          Return Ret

                  And now, each time BuildUI, TriggerFormatUI, and TriggerProcessPostUI are called, the DataIN will be populated with that byte array you stored. In TriggerProcessPostUI you can update/change it by again passing it as DataOut, but in the other functions you would deserialize it just so that you have the data to use in the function.

                  Make sense?

                  FYI... One other twist to deserialization which is commented in the procedure... In order for deserialization to know that the structure or object that the data is going into matches where it came from, you have to pass a non-null object TO deserialization, even though the purpose of calling that is to get an object back filled with information.

                  So you would think that you could call it like this:
                  Code:
                          Dim MyData As MyTriggerData
                          If Not DeSerializeObject(TrigInfoIn.DataIn, MyData) Then Throw New Exception("Oh Poo!")
                  but the way you REALLY need to call it is like this:
                  Code:
                          Dim MyData As [COLOR="Red"][B]New[/B][/COLOR] MyTriggerData
                          If Not DeSerializeObject(TrigInfoIn.DataIn, MyData) Then Throw New Exception("Oh Poo!")
                  Regards,

                  Rick Tinker (a.k.a. "Tink")

                  Comment


                    #54
                    Originally posted by spud View Post
                    I don't think so, I tested this extensively for my Kinect plugin, and at least TriggerMatches only returns the triggers for the main instance (i.e the one without any instance name)
                    If you want the triggers for a specific instance you have to append ":instance_name" to the name of the plugin and pass this as the first parameter.
                    OK (Grrr) Rich made changes to support the instance name and he did it that way rather than adding another parameter. I *hate* concatenating and splitting strings!!!

                    He probably did that to not break things, but a separate call with the added parameter would not have broken anything either.
                    Regards,

                    Rick Tinker (a.k.a. "Tink")

                    Comment


                      #55
                      Originally posted by Rick Tinker View Post
                      OK (Grrr) Rich made changes to support the instance name and he did it that way rather than adding another parameter. I *hate* concatenating and splitting strings!!!

                      He probably did that to not break things, but a separate call with the added parameter would not have broken anything either.
                      So my question is still valid: Would it be possible to add a wildcard so that GetTriggers(PLUGIN_NAME:*) retreive all the triggers for the plugin regardless of the instance?

                      Comment


                        #56
                        Originally posted by spud View Post
                        So my question is still valid: Would it be possible to add a wildcard so that GetTriggers(PLUGIN_NAME:*) retreive all the triggers for the plugin regardless of the instance?
                        No, I am going to completely change that back and add new calls. After the change, the plug-in name will ignore any instance added to it, and it will return ALL triggers from ALL instances (or non instances) of that plug-in, and if you want the triggers just for a specific instance, there will be a new call.

                        I will also add the instance to the return value so that when you get all of the triggers or actions, you can see which ones are for instances.

                        I am under the impression here that I can make all of these changes without breaking (exception breaking that is) existing plug-ins, but you will definitely have to make a change at your end for any multi-instance plug-ins.
                        Regards,

                        Rick Tinker (a.k.a. "Tink")

                        Comment


                          #57
                          Rick...I am VERY grateful for that information, very informative and comprehensive. Suddenly a eureka moment hit after reading and I have managed to get my triggers working correctly. Thanks.

                          Comment


                            #58
                            Last question before I leave people alone (promise), it concerns group actions.

                            I have an action in a plug in that works without a problem. It is a very simple action with a couple of text boxes, it processes correctly in normal events appears is handled correctly and I have tested it a fair bit.

                            When I come instead to add a group action I cannot get it to add, the interface will appear so ActionBuildUI is definitely called. ActionConfigured is then called but no matter if I return true/false from that it does not appear to get any further.

                            I've checked the responses into ActionConfigured and evref is always -1 (special code for a group action? or like the old when the event/device does not exist then report -1), I try and trick it into returning true from ActionConfigured (commenting out the error checking) and then it stays there, it formats without any of the data that should be in the text boxes so I know ActionFormatUI is called. I test strTrigActInfo.DataIn and it is marked as nothing.

                            I've put debug statements in all of the procedures and it looks like ActionProcessPostUI is never called (jumping straight to ActionFormatUI), I've searched and this has been reported here http://forums.homeseer.com/showthread.php?p=1084908 but I don't know if it is an issue that is caused by me or just me not understanding.
                            Last edited by mrhappy; May 29, 2014, 04:34 PM.

                            Comment


                              #59
                              Sounds like a bug, but let me look into it. Did anybody report it in Bugzilla? If not, definitely do that because if Rich or I are not subscribed to threads where people report things we do not always see them.
                              Regards,

                              Rick Tinker (a.k.a. "Tink")

                              Comment


                                #60
                                Looks like http://www.homeseer.com/bugzilla/show_bug.cgi?id=1129 if i'm not mistaken - which i submitted sometime ago.

                                Comment

                                Working...
                                X