Announcement

Collapse
No announcement yet.

HS3 Plugin Samples

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

  • rjh
    started a topic HS3 Plugin Samples

    HS3 Plugin Samples

    [UPDATED 5/14/15]

    Here are 3 plug-in samples that show the 3 ways to configure a plugin. One is a standard sample, one is a more basic sample that has simple actions/triggers, and the third shows how to create a multi-instance plugin.

    http://homeseer.com/updates3/hs3_plugin_samples.zip

    10/19/13 Changes:

    * Modified multi-instance sample so it supports both single and multiple EXE modes properly

  • mulu
    replied
    Failed Getting InterfaceStatus

    I compiled the samples without changing any code and then copy the executable to the HS3 folder. When I restart HS3 and go to the plugin manager I get the following warnings for the two samples I installed:

    WARNING: Failed getting InterfaceStatus from Sample Plugin - the interface was not found in the list of active interfaces, the list may need to be refreshed.

    What causes this and how do I avoid that.

    Also the Sample-BasicMI under "Instance" shows "See plug-in config" but the plugin has not configuration website (the plug-in name is not an URL and the plug-in is not listed under the menu "PLUG-INS").

    Leave a comment:


  • Moskus
    replied
    Mine has been available for a while, but not in C#.
    http://board.homeseer.com/showthread.php?t=177339

    Leave a comment:


  • aXis
    replied
    Sorry Moskus, I couldn't wait any longer and ended up make my own barebones C# sample plugin. It really only addresses instantiating and connecting the plugin to Homeseer HS3, but it is far simpler (and I hope more sensible) than the official samples.

    Thread here: http://board.homeseer.com/showthread.php?t=178122

    Leave a comment:


  • Moskus
    replied
    If you are talking about mine, then:
    "Very soon", I hope. I've just discovered some parts I want to rewrite, but it is soon ready for first release.

    Leave a comment:


  • HaPe
    replied
    Any updates regarding the re-worked sample plugins?

    Leave a comment:


  • aXis
    replied
    Hi Moskus, I'm keen to see your simplified base plugin as I have several HS2 plugins of my own to port across.

    I thought I was a pretty reasonable hobby programmer but the new SDK and sample projects scare me. They seem really convoluted, there is an awful lot of glue code to tie all of the classes together and I would have though that could be abstracted away in the SDK rather than being reproduced in every plugin.

    Anything that simplifies them will be a huge help.

    Leave a comment:


  • Moskus
    replied
    Originally posted by beerygaz View Post
    The other sample plugin has two "helper" procedures which I find useful. Note that they also "remove" the current object before adding it to ensure it's replaced and not added to all the time. These could easily be modified for unnamed objects too.
    Yeah, I've been meaning to ask about that.
    Why are they serializing it before adding? Shouldn't the class handle that itself?

    Leave a comment:


  • beerygaz
    replied
    The other sample plugin has two "helper" procedures which I find useful. Note that they also "remove" the current object before adding it to ensure it's replaced and not added to all the time. These could easily be modified for unnamed objects too.

    Code:
    Sub PEDAdd(ByRef PED As clsPlugExtraData, ByVal PEDName As String, ByVal PEDValue As Object)
            Dim ByteObject() As Byte = Nothing
            If PED Is Nothing Then PED = New clsPlugExtraData
            SerializeObject(PEDValue, ByteObject)
            If Not PED.AddNamed(PEDName, ByteObject) Then
                PED.RemoveNamed(PEDName)
                PED.AddNamed(PEDName, ByteObject)
            End If
        End Sub
    
    Function PEDGet(ByRef PED As clsPlugExtraData, ByVal PEDName As String) As Object
            Dim ByteObject() As Byte
            Dim ReturnValue As New Object
            ByteObject = PED.GetNamed(PEDName)
            If ByteObject Is Nothing Then Return Nothing
            DeSerializeObject(ByteObject, ReturnValue)
            Return ReturnValue
    End Function
    These two rely on these other helper functions:

    Code:
     Public Function SerializeObject(ByRef ObjIn As Object, ByRef bteOut() As Byte) As Boolean
            If ObjIn Is Nothing Then Return False
            Dim str As New MemoryStream
            Dim sf As New Binary.BinaryFormatter
    
            Try
                sf.Serialize(str, ObjIn)
                ReDim bteOut(CInt(str.Length - 1))
                bteOut = str.ToArray
                Return True
            Catch ex As Exception
                Log.Error(IFACE_NAME + " Error: Serializing object " + ObjIn.ToString + " :" + ex.Message, ex)
                Return False
            End Try
    
        End Function
    
        Public Function DeSerializeObject(ByRef bteIn() As Byte, ByRef ObjOut As Object) As Boolean
            ' Almost immediately there is a test to see if ObjOut is NOTHING.  The reason for this
            '   when the ObjOut is suppose to be where the deserialized object is stored, is that 
            '   I could find no way to test to see if the deserialized object and the variable to 
            '   hold it was of the same type.  If you try to get the type of a null object, you get
            '   only a null reference exception!  If I do not test the object type beforehand and 
            '   there is a difference, then the InvalidCastException is thrown back in the CALLING
            '   procedure, not here, because the cast is made when the ByRef object is cast when this
            '   procedure returns, not earlier.  In order to prevent a cast exception in the calling
            '   procedure that may or may not be handled, I made it so that you have to at least 
            '   provide an initialized ObjOut when you call this - ObjOut is set to nothing after it 
            '   is typed.
            If bteIn Is Nothing Then Return False
            If bteIn.Length < 1 Then Return False
            If ObjOut Is Nothing Then Return False
            Dim str As MemoryStream
            Dim sf As New Binary.BinaryFormatter
            Dim ObjTest As Object
            Dim TType As System.Type
            Dim OType As System.Type
            Try
                OType = ObjOut.GetType
                ObjOut = Nothing
                str = New MemoryStream(bteIn)
                ObjTest = sf.Deserialize(str)
                If ObjTest Is Nothing Then Return False
                TType = ObjTest.GetType
                'If Not TType.Equals(OType) Then Return False
                ObjOut = ObjTest
                If ObjOut Is Nothing Then Return False
                Return True
            Catch exIC As InvalidCastException
                Return False
            Catch ex As Exception
                Log.Error(IFACE_NAME + " Error: DeSerializing object: " + ex.Message, ex)
                Return False
            End Try
        End Function
    This is heady stuff for me, managing serialization of objects across interfaces is out of my hobbyist-coding wheelhouse. To be honest, it's something I would have expected HST to abstract a little further from the developer in the API, but perhaps that's not possible?

    Leave a comment:


  • happnatious1
    replied
    I don't think the CObj is necessary in your case, you could probably remove it and it would still work. (maybe). but you did get me thinking, since it's being sent to homeseer over HSCF maybe a complex object needs to be serialized.

    This appears to work.

    Code:
      'set the EDO for device amp1
                        Dim EDO As New HomeSeerAPI.clsPlugExtraData
                        dv.PlugExtraData_Set(hs) = EDO
                        'Dim HW As String = "a1"
                        Dim HW As New MyDeviceData()
                        HW.mydevice = MyDeviceData.mydevices.Amp1
                        Dim bteArray() As Byte = Nothing
                        If Not SerializeObject(HW, bteArray) Then Throw New Exception("Not able to Serialize myaction data in actionbuildui.")
    
                        'Dim Ret As New IPlugInAPI.strMultiReturn
                        'Ret.sResult = ""                ' Empty return indicates success!
                        'Ret.TrigActInfo = ActInfoIN    ' Trig info does not change, just pass through what we received...
                        ' Ret.DataOut = bteArray
                        If EDO.GetNamed("My Device Object") IsNot Nothing Then
                            EDO.RemoveNamed("My Device Object")
                        End If
                        EDO.AddNamed("My Device Object", bteArray)
                        ' Need to re-save it.
                        dv.PlugExtraData_Set(hs) = EDO
                        hs.SaveEventsDevices()
    Originally posted by mrhappy View Post
    This is what I did but no idea whether or not it is the correct approach, it works though.

    Code:
    Select Case k
                        Case 1 To 4
                            With EDO
                                .AddNamed("enAPIDirection", CObj("Consumed"))
                                .AddNamed("enAPIDevice", CObj("Meter_Service"))
                                .AddNamed("enAPILog", CObj("True"))
                            End With
                            'use this opportunity to do some Energy API work
                            hs.Energy_SetEnergyDevice(dv.Ref(hs), enumEnergyDevice.Meter_Service)
                    End Select
    
                    dv.PlugExtraData_Set(hs) = EDO

    Leave a comment:


  • Moskus
    replied
    This is a problem with the SDK and plugin development in general, and with PlugExtraData specific. The more people you ask, the more options you get...

    I just have to sort out some SubTriggers, and I'll revisit the PlugExtraData issue as I've been meaing to look into it again. (I don't fully understand it, and that club is getting bigger every day it seems).

    Leave a comment:


  • mrhappy
    replied
    Originally posted by happnatious1 View Post
    Below is what I ended up with, It's basically right out of the sample_plugin. If someone can point me to a sample using an object I'd be appreciative.

    Code:
     'set the EDO for device amp1
                        Dim EDO As New HomeSeerAPI.clsPlugExtraData
                        dv.PlugExtraData_Set(hs) = EDO
                        Dim HW As String = "a1"
                        If EDO.GetNamed("My Device Object") IsNot Nothing Then
                            EDO.RemoveNamed("My Device Object")
                        End If
                        EDO.AddNamed("My Device Object", HW)
                        ' Need to re-save it.
                        dv.PlugExtraData_Set(hs) = EDO
                        hs.SaveEventsDevices()
    As soon as I make HW an object or enum the plugin cant send EDO back to homeseer. I'm writing my plugin by connecting from one windows machine to my homeseer windows machine remotely. Maybe it would behave differently if the plugin were running locally.

    The good news is I now have a partially functioning plugin for my monoprice 6 zone amplifier. Truth be told I never thought I'd make it this far. The only thing left is triggers and a lot of typing to add the rest of my functionality.
    This is what I did but no idea whether or not it is the correct approach, it works though.

    Code:
    Select Case k
                        Case 1 To 4
                            With EDO
                                .AddNamed("enAPIDirection", CObj("Consumed"))
                                .AddNamed("enAPIDevice", CObj("Meter_Service"))
                                .AddNamed("enAPILog", CObj("True"))
                            End With
                            'use this opportunity to do some Energy API work
                            hs.Energy_SetEnergyDevice(dv.Ref(hs), enumEnergyDevice.Meter_Service)
                    End Select
    
                    dv.PlugExtraData_Set(hs) = EDO

    Leave a comment:


  • happnatious1
    replied
    Originally posted by Moskus View Post
    ... and the plugin samples are storing custom classes...

    Did changing type solve your problem?
    Below is what I ended up with, It's basically right out of the sample_plugin. If someone can point me to a sample using an object I'd be appreciative.

    Code:
     'set the EDO for device amp1
                        Dim EDO As New HomeSeerAPI.clsPlugExtraData
                        dv.PlugExtraData_Set(hs) = EDO
                        Dim HW As String = "a1"
                        If EDO.GetNamed("My Device Object") IsNot Nothing Then
                            EDO.RemoveNamed("My Device Object")
                        End If
                        EDO.AddNamed("My Device Object", HW)
                        ' Need to re-save it.
                        dv.PlugExtraData_Set(hs) = EDO
                        hs.SaveEventsDevices()
    As soon as I make HW an object or enum the plugin cant send EDO back to homeseer. I'm writing my plugin by connecting from one windows machine to my homeseer windows machine remotely. Maybe it would behave differently if the plugin were running locally.

    The good news is I now have a partially functioning plugin for my monoprice 6 zone amplifier. Truth be told I never thought I'd make it this far. The only thing left is triggers and a lot of typing to add the rest of my functionality.

    Leave a comment:


  • Moskus
    replied
    Originally posted by SteveMSJ View Post
    I wish I was as organised as you. I found it a long learning curve working through the basic plugin samples to understand how things work when writing my own plugin. Whilst I cracked most of it, or at least the bits I needed, I suspect that when I start another plugin project after a few months gap I will have forgotten most of what I learnt

    Your work will be very useful to us all.
    Thanks,
    Steve
    Thansk, Steve!

    I've already exeeded my own requirements for the first couple of plugins I want to make, but I know I will hit the wall just after that, so I keep testing and developing my sample project.

    Keep in mind that it is based on the basic sample, so the very advanced stuff won't be coverede (at least not at first).

    I'm hoping to make it a more living sample, updating it while I code.


    And the downside is that is that it's based on my interpretation of the SDK. Just being a hobby-developer might cause me to make mistakes. Hopefully others will find them and correct me.

    Together I'm sure we can make a good sample plugin.

    Leave a comment:


  • SteveMSJ
    replied
    I wish I was as organised as you. I found it a long learning curve working through the basic plugin samples to understand how things work when writing my own plugin. Whilst I cracked most of it, or at least the bits I needed, I suspect that when I start another plugin project after a few months gap I will have forgotten most of what I learnt

    Your work will be very useful to us all.
    Thanks,
    Steve

    Originally posted by Moskus View Post
    Right now I'm taking the basic plugin sample and simplifies it a little more. I'm adding comments and renaming variables so that the code is easier to read, so that we stand a chance of understanding what's going on.

    I really admire HomeSeer for what they have done, and what they enable for plugin developers. The posiblilites are really endless!

    But the code structure of the samples are... uhm... unstructured in my opinion. I'm used to reading SDKs (for Steam, Fitbit, Universal apps for Windows 10, etc), and while the possiblities are many in HomeSeer, the sample code and the code base is also somewhat messy and confusing.

    Examples:
    Hungarian notation. It's now abandoned by everyone (except old VB coders) at least 10 years ago. Hungarian notation is when you put the string type in front of the variable, so that it's easier to get the variable you want and the idea is that it makes the code easier to read.

    That might well be before .NET, but now it's not a problem. Now the recommendation is that if you really have to include the variable type, then add it to the end of the name. So "strName" becomes "NameString".

    The main problem is when variables, especially global variables, changes types. This is not uncommon when you start coding. You create a variable called "strLocation" because it is the name of a location and it's a string. As you keep coding, you see that you are not only passing the location name around, but also the GPS location with latitude and longitude, so you create your own class to pass all of this information around:

    Code:
    Public Class Location
        Public Property Name As String
        Public Property Latitude As Double
        Public Property Longitude As Double
    End Class
    ... but you now are used to the variable name "strLocation" you keep using that, even if the variable is now an instance of the Location class, not a String.

    I've used Hungarian notation myself. And now when I have to update my old programs, I can see that even my own code, which I am very familiar with, is pretty darn hard to understand sometimes.


    Abbreviations. Again something from the "good, old days" before Visual Studio had proper IntelliSense (auto completion) and people coded in Notepad or whatnot. Typing long words was "a vaste of time".

    But that results in classes named such as strActTrigInfo that perpahs started out as a string holding Action and/or Trigger information? I have no idea.


    Commenting. Perhaps the most important part of any programming project. Escpecially when you are to show your work others. Like in a SDK!

    There's no magic way to make a fellow programmer understand how you think. You need to tell him/her. One way is to avoid abbreviations and don't use Hungarian notation, but comments are even more important.

    The sample projects have almost no comments!

    Some statistics:
    - The main sample has 596 lines containing comment marks ( ' ).
    - The basic sample has 150 lines containing comment marks.
    - My basic sample has 816 lines containing comment marks, and I'm not even done yet!

    I'm going through the basic sample line for line, adding comments from the SDK on the web directly and adding comments on my own so that I better understand what's going on.

    I understand commenting on a sample plugin is way down on HSTs priority list. I just wish they had done it when they were coding it, it would have made it so much easier to understand.

    I want to understand the SDK. That's why I do this. But I don't see why I shouldn't help others getting started with plugins as well. Ultrajones made a similar sample for HS2, and I wouldn't have gotten into plugins at all if it weren't for him. I'm just paying it forward.

    Leave a comment:

Working...
X