Announcement

Collapse
No announcement yet.

First attempt at a plugin and need help with settings page

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    First attempt at a plugin and need help with settings page

    I've been going over the sample plug in and it's helped me to get familiarized with how things work. I would like to setup my settings page to have the ability to add a group of fields that would correspond to a device. But I haven't been able to find an example. Does anyone know where I could find an example of what I'm looking to accomplish?

    The settings would only need to be a name and a key and possibly a delete button. I'm thinking that once the "add" button is clicked it could change a bool from false to true and that onSettingsChange could check the bool and call a method to create the device associated with that name and key. Does this seem like a reasonable way to do this?

    Any help would be greatly appreciated!

    Loren

    #2
    Here is an example from a Config Device page where a toggle is used as a "Delete" button and is acted upon after the "Save" button is clicked. Same approach is used for the Settings page.

    Click image for larger version

Name:	Capture.PNG
Views:	536
Size:	29.2 KB
ID:	1379683

    Code:
        Public Function ConfigFeature(refDevice As Integer, user As String, userRights As Integer, newDevice As Boolean) As String
            'this is called because we set a boolean flag for it (SupportsConfigDevice)
            'This builds a tab on the device specific to the plugin
            Dim hsdevice As HsDevice = hs.GetDeviceWithFeaturesByRef(refDevice)
            Dim pageID As String = "deviceconfig"
    
            Try
                Dim pf As HomeSeer.Jui.Views.Page = HomeSeer.Jui.Views.PageFactory.CreateDeviceConfigPage(pageID, "Device Settings").Page
                Dim featureList As Generic.List(Of Integer) = GetFeatureList(refDevice)
                If featureList Is Nothing Then Return ""
                For Each iFeatureRef As Integer In featureList
    
                    Dim PED As HomeSeer.PluginSdk.Devices.PlugExtraData = hs.GetPropertyByRef(iFeatureRef, HomeSeer.PluginSdk.Devices.EProperty.PlugExtraData) 'Dim PED As clsPlugExtraData = dv.PlugExtraData_Get(hs)
                    Dim KNXPairList As New List(Of KNXGroupAddresPair)
                    KNXPairList = PEDGet(PED, PEDName)
                    If KNXPairList Is Nothing OrElse KNXPairList.Count = 0 Then
                        'nothing yet configured about this feature, use default
                        Dim TempEntry As New KNXGroupAddresPair
                        TempEntry.dvRef = iFeatureRef
                        TempEntry.Name = "New Feature"
                        TempEntry.Action = enumKNXActions.Default 'Unknown
                        TempEntry.DPT = enumDataPointTypes.Not_Set
                        KNXPairList = New List(Of KNXGroupAddresPair)
                        KNXPairList.Add(TempEntry)
                    End If
    
                    Dim i As Integer = 0
                    Dim viewList As New List(Of HomeSeer.Jui.Views.ViewGroup)
                    For Each Entry In KNXPairList
                        viewList.Add(BuildSingleActionPair(Entry, i, iFeatureRef))
                        i += 1
                    Next
    
                    'blank line to add additional entry
                    Dim newPair As New KNXGroupAddresPair
                    newPair.Action = enumKNXActions.Default
                    newPair.DPT = enumDataPointTypes.Not_Set
                    newPair.Name = " New Group Address"
                    newPair.GroupAddress = ""
                    newPair.dvRef = iFeatureRef
                    newPair.PollMe = False
                    viewList.Add(BuildSingleActionPair(newPair, i, iFeatureRef))
                    pf.AddViews(viewList)
                Next
    
                Return pf.ToJsonString
    
            Catch ex As Exception
                WriteLog(ErrorLog, ex.Message, 0)
                Return "" 'Err.Description
            End Try
        End Function
    
    
    
    Friend Function BuildSingleActionPair(ByVal ThisPair As KNXGroupAddresPair, ByVal Idx As Integer, ByVal iRef As Integer) As HomeSeer.Jui.Views.ViewGroup
            Dim sID As String = iRef.ToString & "-" & Idx.ToString
    
            Dim i As Integer = 0
            Dim iSelected As Integer = 0
            Dim dropList As New List(Of String)
            Dim dropListKeys As New List(Of String)
            For Each kvp As KeyValuePair(Of String, GAXML) In GAXMLDictionary
                If kvp.Key = " " Then
                    dropList.Add(kvp.Key)
                Else
                    dropList.Add(kvp.Key & " " & kvp.Value.Name & " " & "DPT " & kvp.Value.DPT & "    " & DPTtoTypeDisplay(kvp.Value.DPT))
                End If
                dropListKeys.Add(kvp.Key)
                If kvp.Key = ThisPair.GroupAddress Then
                    iSelected = i
                End If
                i += 1
            Next
            Dim vGroupAddress As New HomeSeer.Jui.Views.SelectListView("GroupAddressId-" & sID, "Group Address", dropList, dropListKeys, HomeSeer.Jui.Types.ESelectListType.DropDown, iSelected)
    
            'Dim vDPT As New HomeSeer.Jui.Views.LabelView("DPTId" & sID, "Data Point Type: " & DPTtoTypeDisplay(ThisPair.DPT))
    
    
            i = 0
            iSelected = 0
            Dim dropList2 As New List(Of String)
            Dim dropListKeys2 As New List(Of String)
    
            For Each Entry In ActionPairTable
                'If Entry.Value <> enumKNXActions.Default Then
                dropList2.Add(Entry.Key)
                dropListKeys2.Add(Entry.Value)
                'If Val(Entry.Value) = ThisPair.Action Then
                'iSelected = i
                'End If
                If Entry.Value = enumKNXActions.Control AndAlso ThisPair.Action > 0 Then
                    iSelected = i
                ElseIf Entry.Value = enumKNXActions.Status AndAlso ThisPair.Action < 0 Then
                    iSelected = i
                End If
                i += 1
                'End If
    
            Next
    
            Dim vAction As New HomeSeer.Jui.Views.SelectListView("ActionId-" & sID, "Action:", dropList2, dropListKeys2, HomeSeer.Jui.Types.ESelectListType.DropDown, iSelected)
    
            Dim vPoll As New HomeSeer.Jui.Views.ToggleView("PollId-" & sID, "Enable Polling", ThisPair.PollMe)
    
            Dim vDelete As New HomeSeer.Jui.Views.ToggleView("DeleteId-" & sID, "Delete this record", False)
    
            Dim vGroup As New HomeSeer.Jui.Views.ViewGroup("GroupId-" & sID, "Feature " & iRef.ToString & "&nbsp;&nbsp;" & ThisPair.Name)
            vGroup.AddView(vGroupAddress)
            'vGroup.AddView(vName)
            vGroup.AddView(vAction)
    
            vGroup.AddView(vPoll)
            vGroup.AddView(vDelete)
    
            Return vGroup
        End Function
    The postback after user selection

    Code:
    Public Function OnDeviceConfigChange(configPage As HomeSeer.Jui.Views.Page, Ref As Integer) As Boolean
            Dim featureList As Generic.List(Of Integer) = GetFeatureList(Ref)
            Dim ViewDictionary As New Generic.Dictionary(Of String, String)
    
            For Each sKey As String In configPage.ViewIds 'viewKeyList
                If sKey.Length > 2 Then
                    Select Case sKey.Substring(0, 3)
                        Case "Act" ' "ActionId" & sViewKey
                            Dim vSelectView As HomeSeer.Jui.Views.SelectListView = CType(configPage.GetViewById(sKey), HomeSeer.Jui.Views.SelectListView)
                            ViewDictionary.Add(sKey, vSelectView.Selection.ToString())
                        Case "Gro" ' "GroupAddressId" & sViewKey
                            Dim vSelectView As HomeSeer.Jui.Views.SelectListView = CType(configPage.GetViewById(sKey), HomeSeer.Jui.Views.SelectListView)
                            Dim iIndex As Integer = vSelectView.Selection
                            Dim i As Integer = 0
                            For Each sGA As String In GAXMLDictionary.Keys
                                If iIndex = i Then
                                    ViewDictionary.Add(sKey, sGA)
                                    Exit For
                                End If
                                i += 1
                            Next
                        Case "Pol" ' "PollId" & sViewKey
                            Dim vToggleView As HomeSeer.Jui.Views.ToggleView = CType(configPage.GetViewById(sKey), HomeSeer.Jui.Views.ToggleView)
                            ViewDictionary.Add(sKey, vToggleView.IsEnabled.ToString())
                        Case "Del" ' "DeleteId" & sViewKey
                            Dim vToggleView As HomeSeer.Jui.Views.ToggleView = CType(configPage.GetViewById(sKey), HomeSeer.Jui.Views.ToggleView)
                            ViewDictionary.Add(sKey, vToggleView.IsEnabled.ToString())
                    End Select
                End If
            Next
    
            Try
                For Each featureRef As Integer In featureList
                    Dim PED As New HomeSeer.PluginSdk.Devices.PlugExtraData 'Dim PED As New clsPlugExtraData
                    Dim ActionPairs As New List(Of KNXGroupAddresPair)
                    ActionPairs = ExtractActionPairs(featureRef, ViewDictionary) ' Data)
    
                    ' Check data are OK before saving, otherwise exit out
                    ' Check no GroupAddress is used twice
                    Dim NoDuplicates = ActionPairs.Distinct(New ActionPairGAComparer)
                    If NoDuplicates.Count <> ActionPairs.Count Then
                        Throw New ConfigDeviceException("Duplicate GroupAddress entries exist")
                    End If
    
                    ' Check Polling is only switched on for max one device
                    Dim PollExist As Boolean = False
                    Dim PollCount As Integer = 0
                    For Each Pair In ActionPairs
                        If Pair.PollMe = True Then
                            PollExist = True
                            PollCount += 1
                        End If
                    Next
                    If PollCount > 1 Then
                        ' Exit as you can only have max One poll per HS3 device
                        Throw New ConfigDeviceException("Polling can only be setup on one GroupAddress entry per device")
                    End If
    
                    DefineFeatureProperties(Ref, ActionPairs)
    
                    PEDAdd(PED, PEDName, ActionPairs)
                    hs.UpdatePropertyByRef(featureRef, HomeSeer.PluginSdk.Devices.EProperty.PlugExtraData, PED) 'dv.PlugExtraData_Set(hs) = PED
                    'hs.SaveEventsDevices()
    
                    Dim ExistingReadVS As HomeSeer.PluginSdk.Devices.Controls.StatusControl = hs.GetStatusControlForValue(Ref, enumActions.Poll)
                    If PollExist Then
                        'Dim ExistingReadVS As VSPair = hs.DeviceVSP_Get(ref, enumActions.Poll, ePairStatusControl.Control)
                        'Dim vspCollection As System.Collections.Generic.List(Of HomeSeer.PluginSdk.Devices.Controls.StatusControl) = hs.GetPropertyByRef(ref, HomeSeer.PluginSdk.Devices.EProperty.StatusControls)
                        'Dim vsCollection As HomeSeer.PluginSdk.Devices.Controls.StatusControlCollection = hs.GetStatusControlCollectionByRef(ref)
                        If ExistingReadVS Is Nothing Then
                            'Dim TotalCAPIButton As Integer = hs.GetStatusControlCountByRef(ref) 'hs.DeviceVSP_CountControl(ref)
                            'Dim Row As Integer = Int(TotalCAPIButton / 3) + 1
                            'Dim Col As Integer = TotalCAPIButton - (Row - 1) * 3 + 1
                            'AddVSPairs(ref, ePairStatusControl.Control, enumActions.Poll, enumActions.Poll.ToString, Row, Col)
                            Dim Pair As New HomeSeer.PluginSdk.Devices.Controls.StatusControl(Devices.Controls.EControlType.Button)
                            Pair.ControlUse = HomeSeer.PluginSdk.Devices.Controls.EControlUse.NotSpecified
                            Pair.TargetValue = enumActions.Poll
                            Pair.Label = enumActions.Poll.ToString
                            hs.AddStatusControlToFeature(featureRef, Pair)
                        End If
                    Else
                        If ExistingReadVS IsNot Nothing Then
                            hs.ClearStatusControlsByRef(featureRef) 'hs.DeviceVSP_ClearControl(ref, enumActions.Poll)
                        End If
                    End If
                Next
    
                'If _RebuildOnSave Then GroupAddressTable = BuildGATable()
                Return True
    
            Catch ex As Exception
                WriteLog(ErrorLog, "OnDeviceConfigChange Ref" & Ref.ToString & " " & ex.Message, 0)
                Throw New ConfigDeviceException(ex.Message)
            End Try
    
            Return True
    
        End Function
    
    
    
      Friend Function ExtractActionPairs(ByVal CurrentRef As Integer, ByVal ViewDictionary As Generic.Dictionary(Of String, String)) As List(Of KNXGroupAddresPair)
            'Dim parts As Collections.Specialized.NameValueCollection
            Dim PairCount As Integer = 4 'CurrentPair.Length
            Dim Pairs As New List(Of KNXGroupAddresPair)
            Dim SinglePair As New KNXGroupAddresPair 'New
    
            'parts = HttpUtility.ParseQueryString(Data)
    
            'get the current definition of GAPairs before user edits made
            Dim KNXPairList As New List(Of KNXGroupAddresPair)
            Dim PED As HomeSeer.PluginSdk.Devices.PlugExtraData = hs.GetPropertyByRef(CurrentRef, HomeSeer.PluginSdk.Devices.EProperty.PlugExtraData)
            KNXPairList = PEDGet(PED, PEDName)
            Dim CurrentDictionary As New Generic.Dictionary(Of String, KNXGroupAddresPair)
            Dim i As Integer = 0
            If KNXPairList IsNot Nothing Then
                For Each currentPair As KNXGroupAddresPair In KNXPairList
                    If currentPair.DPT <> enumDataPointTypes.Not_Set Then
                        CurrentDictionary.Add(i.ToString, currentPair)
                        i += 1
                    End If
                Next
            End If
    
            Dim DeleteList As New Generic.List(Of String)
            For iPass As Integer = 0 To 1 ' assure Group Address is selected before Control/Status selection is processed
                For Each kvp As KeyValuePair(Of String, String) In ViewDictionary
                    Dim arrKey As String() = kvp.Key.Split("-")
                    Dim sIndex As String = arrKey(arrKey.Length - 1) '0-based index of the view setup on the feature.  Each feature starts at 0
                    Dim sRef As String = arrKey(arrKey.Length - 2) 'feature ref
                    If IsNumeric(sRef) AndAlso CType(sRef, Integer) = CurrentRef Then 'make certain it is the ref of interest because view returns all features changes
                        If CurrentDictionary.ContainsKey(sIndex) Then
                            SinglePair = CurrentDictionary(sIndex)
                        Else
                            SinglePair = New KNXGroupAddresPair
                            SinglePair.dvRef = CurrentRef
                            CurrentDictionary.Add(sIndex, SinglePair)
                        End If
                        If kvp.Key.Length > 2 Then
                            Select Case kvp.Key.Substring(0, 3)
                                Case "Act" ' "ActionId" & sViewKey
                                    If iPass = 1 Then
                                        '0 = default, 1 = Control, 2 = status
                                        'merge the action control with the SinglePair.DPT to get the enumKNXAction enumeration
                                        Dim iDPTValue As Integer = SinglePair.DPT
                                        If iDPTValue = enumDataPointTypes.Not_Set Then
                                            iDPTValue = enumKNXActions.Default '  0
                                        ElseIf kvp.Value = enumKNXActions.Status Then  '2 Then
                                            iDPTValue = -iDPTValue
                                        End If
                                        SinglePair.Action = iDPTValue
                                    End If
                                Case "Gro" ' "GroupAddressId" & sViewKey
                                    If iPass = 0 Then
                                        SinglePair.GroupAddress = kvp.Value
                                        SinglePair.Action = enumKNXActions.Default
                                        'SinglePair.DPT = enumDataPointTypes.Not_Set
                                        Dim oGAXML As GAXML = GAXMLDictionary(kvp.Value)
                                        SinglePair.Name = oGAXML.Name
                                        SinglePair.DPT = DPTtoType(oGAXML.DPT)
                                    End If
                                Case "Pol" ' "DPollId" & sViewKey
                                    If iPass = 1 Then
                                        SinglePair.PollMe = kvp.Value = "True" ' parts(key) = "True"
                                    End If
                                Case "Del" ' "DeleteId" & sViewKey
                                    If iPass = 1 Then
                                        If kvp.Value = "True" Then 'parts(key) = "True" Then
                                            DeleteList.Add(sIndex)
                                        End If
                                    End If
                            End Select
                        End If
                    End If
                Next
            Next
            For Each sIndex As String In DeleteList
                'if GroupAddressTable has the deleted pair then remove it from the table
                Dim Pair As KNXGroupAddresPair
                Dim GA As String = CurrentDictionary(sIndex).GroupAddress
                If GA <> "" Then
                    Pair = GroupAddressTable.Find(Function(p) p.GroupAddress = GA)
                    If Pair IsNot Nothing Then
                        GroupAddressTable.Remove(Pair)
                    End If
                End If
                CurrentDictionary.Remove(sIndex)
            Next
            For Each SinglePair In CurrentDictionary.Values
                Pairs.Add(SinglePair)
            Next
            Return Pairs
    
        End Function

    Comment


      #3
      Michael McSharry Thank you for the example. I think it's exactly what I was looking for and I'm about to dig into it. However, one my hurdles right now is reading ini data into strings and parse them into fields. I've been referencing this post of yours today to try and read from my ini file. I'm probably making a noob mistake. Whenever I try and read from my ini file like this:

      Code:
      apiToken = HomeSeerSystem.GetINISetting("Settings", "tokenInput", "defaultVal", SettingsFileName);
      Homeseer throws this error:
      Exception has been thrown by the target of an invocation.->Object reference not set to an instance of an object.Startup Complete, 1 errors detected, check the log for more information.
      Do I need to include that line in a class other than the HSPI class or how should I proceed?

      Comment


        #4
        It looks like the only object being used is HomeSeerSystem. How did you expose this object to the method that is using it? HomeSeerSystem is visible in HSPI so it needs to be put in something global. Here is what I did in that same plugin. I have used different techniques in different pluigins

        Code:
            Protected Overrides Sub Initialize()
                hs = HomeSeerSystem
                Dim sPath As String = hs.GetAppPath 'My.Application.Info.DirectoryPath
                If InStr(sPath, "\") = 0 Then
                    slash = "/"
                Else
                    slash = "\"
                End If
        
                oPlugin.InitIO() 'port)
            End Sub
        
        Module utils
            Public plugin As New HSPI
            Public IFACE_NAME As String = "mcsKNX"
            'Public callback As HomeSeerAPI.IAppCallbackAPI
            Public hs As HomeSeer.PluginSdk.IHsController 'HomeSeerAPI.IHSApplication
            Public slash As String
        :
        :L

        Comment


          #5
          The one thing that I failed to mention is that I've been writing everything in C#. This is vb correct? If so does anyone have any insight into declaring the object in c#?

          Thanks again
          Loren

          Comment


            #6
            Do a google search for c# vb .net converter. Just paste one language statement into the browser page and it will return the other language. C# puts the type first and then the variable name vs. vb that does dim/private/friend/public followed by varaiabe As type and no semicolon.

            Comment


              #7
              I've circled back around to saving info from a feature page and am still having a few issues. I've based a feature page save button off of the sample plugin button. When Information is changed in a few text boxes and the save button is clicked this error is returned:

              Unable to save changes : Invalid action type or malformed data
              This is an example of the data from the feature page that I've put together:

              Code:
              {"plugid":"LorenFirstPushover","buttonId":"jui-button-save","changes":[{"PageId":"settings-page1","Id":"Alias0","Type":4,"Value":"Alias"},{"PageId":"settings-page1","Id":"APIKey0","Type":4,"Value":"My API"}]}
              This is an example of data from the sample plugin:

              Code:
              {"plugid":"HomeSeerSamplePlugin","buttonId":"save_plugin_settings","changes":[{"PageId":"settings-page1","Id":"settings-page1-yellow","Type":5,"Value":true},{"PageId":"settings-page1","Id":"settings-page1-orange","Type":5,"Value":true},{"PageId":"settings-page1","Id":"settings-page1-green","Type":5,"Value":false}]}
              I appreciate all of the help everyone has been giving. Any insights would be great.

              Thank you!

              Comment

              Working...
              X