Announcement

Collapse
No announcement yet.

Yet another HSPI plugin library

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

    Yet another HSPI plugin library

    .
    .
    Yet another library I created to simplify HS plugin development HSPI_AKTemplate. [Edit - moved to bitbucket.org]

    I created this library while developing AK Smart Device plugin after spending many days (and nights) trying to make sense of example code available. The code was based on famous Moskus sample plugin (and C# ports) and great work of alexdresko . And many any other publicly available source examples I could find in Google.

    The main part is the HSPI library, and there's also an example plugin using this lib. Noticeable improvements/extensions and some description:

    1. Included base classes in the library which should be extended in the plugin project to provide your plugin specific functionality:
    .
    Derived plugin class Library base class Comments
    HSPI HSPIBase2 Main class responsible for communication between HS and the plugin
    Your device class DeviceBase Base device class wrapper provides cleaner implementation (OO) of Scheduler.Classes.DeviceClass
    Your controller class ControllerBase Plugin control code - usually included in HSPI class itself - to keep HSPI class cleaner
    Your config pages PageBuilder Extends PageBuilderAndMenu.clsPageBuilder to simplify creating config pages (see notes below)
    .
    2. Improved HS connection logic (in HspiBase.cs) - especially important for remote plugins, it doesn't just silently die if there's some connection issue, it will try to reconnect. But it still dies gracefully when HS is shutdown (ShutdownIO)

    3. DeviceBase class provides cleaner object oriented (OO) interface for HS Scheduler.Classes.DeviceClass for setting/getting usual properties (i.e. Name, Value, Address, Type, Location/Location2, etc.). Also provided functions for managing Plugin Extra Data (PED) i.e. SavePED<T>, GetPED<T>, DeletePED, etc.

    4. Also a lot of code dedicated to using VSPairs and CAPIControl - in StatusPairsDict and DeviceBase class

    5. Class TableBuilder - separates all HTML functionality required to build tables from plugin logic. I really dislike (to be polite) the way HTML code is mixed up with plugin logic and C# code, and this bad practice was copied from one plugin to another. With the TableBuilder class developer doesn't need to be concerned about html required to build the table. He (or she) can concentrate on creating plugin logic. Lots of tables in AK Smart Device plugin are built using this class with just a few lines of code.
    Useful features:
    a. Creating tables in collapse-able slider control
    b. Making tables sort-able by clicking on the column header (see My Devices Device List page in my plugin)
    c. Two ways to use the class (two examples provided below)
    - using TableBuilder directly provides most flexible control over building the table
    - using TableData class to create data list for the table and then passing it to static TableBuilder.BuildTable

    6. Class PageBuilder - extension of popular class provides some enhancements, i.e.
    a. RegisterWebPage - now when building the config page it registers itself with HS and then GetPagePlugin (see example code) uses PageBuilder.findRegisteredPage(page)
    b. Some useful helper functions i.e. RadioButtonEnum to Generate jqRadioButton for given Enum type (see post #60, #61 for example code)
    c. Sets UsesJqAll = false to avoid importing JS code for all clsJQuery controls by default and then enabling JS only for each used control.

    7. Class VariableMap - mapping controls to variable names for ProcessPostUI - for config pages and Triggers/Actions. This mapping links UI controls to corresponding variables to automatically update the variable when control value changes. This mostly eliminates the need for ProcessPostUI functions. See post #35, #36 and #60, #61

    8. Some other helper classes, i.e. StopwatchEx, DeviceIdList, MyPairT, etc.

    #2
    Forked it. I'm very interested.

    Comment


      #3
      Using my template all you need is

      1. VisualStudio 2017 (i.e. Express if you want free).
      2. Download my code
      3. You need set references to HS dlls (HomeSeerAPI.dll, HSCF.dll and Scheduler.dll) - either copy them from your HS installation to the project root, or set project references to point to the dll locations.
      4. and it should compile and run.

      Just need make changes related to your plugin (things that Alex Dresko automated in his template):
      1. rename the project,
      2. adjust AssemblyInfo.cs, i.e. AssemblyTitle, AssemblyProduct
      3. change project settings, i.e. "Assembly name" and "Default namespace"
      4. in app.config change <probing privatePath="bin/youplugin"/> (that's the folder where all your dependencies dlls will be moved)
      5. and finally change the plugin name in HSPI.cs GetName() function

      Comment


        #4
        Any upcoming documentation or examples?

        Examples are always a big help as it makes things "real" and provides a nice way of following through the process.... when I started with the MoskusSample base that was a huge help in making sense of how everything fit together.

        Comment


          #5
          Example code of sort-able table:

          Click image for larger version  Name:	Capture.PNG Views:	1 Size:	194.8 KB ID:	1289539


          Code:
                  public static void BuildTable_Info(StringBuilder stb,
                                                  DeviceDict UsedDevices,
                                                  string title = null,
                                                  string tt = null,
                                                  string page_name = null,
                                                  bool sorthdr = true,
                                                  string sortby = null,
                                                  string sortorder = null,
                                                  bool? inSlider = null,
                                                  string tableID = null,
                                                  bool initiallyOpen = true,
                                                  bool noempty = false
                                                  )
                  {
                      List<string> hdr = new List<string>(){ "Ref",
                          PageBuilder.LocationLabels.Item1, PageBuilder.LocationLabels.Item2,
                          "Name", "Plugin", "Type", "Timer", "PowerFail", "States", "Changed", "Log", "Triggers"};
          
                      // Don't show state device if already on the state device page
                      if (stateDevice == null)
                      {
                          hdr.Add("State Device");
                          hdr.Add("Changed");
                      }
          
                      // Prepare TableData
                      TableBuilder.TableData data = new TableBuilder.TableData();
          
                      foreach (SmartDevice device in UsedDevices.Values)
                      {
                          var row = data.AddRow();
          
                          row.Add(device.RefId.ToString());
          
                          if (PageBuilder.bLocationFirst)
                              row.Add(device.Location);
                          row.Add(device.Location2);
                          if (!PageBuilder.bLocationFirst)
                              row.Add(device.Location);
          
                          row.Add(device.GetURL());
                          row.Add(device.Interface);
                          row.Add(device.Type);
                          row.Add(BoolToImg(device.use_cntdwn_timer));
                          row.Add(Utils.ToString(device.AfterDelay));
                          row.Add(String.Join(", ", device.vspsListStr(ePairStatusControl.Both)));
                          row.Add(device.LastChange);
                          row.Add(BoolToImg(device.log_enable));
                          row.Add(device.ListOfTriggerIds());
          
                          row.Add(device.StateDeviceURL);
                          row.Add(device.StateDeviceId != 0 ? device.StateDevice.LastChange : "");
                      }
          
                      string html = TableBuilder.BuildTable( data,
                                                             hdr: hdr.ToArray(),
                                                             title: title,
                                                             tooltip: tt,
                                                             page_name: page_name,
                                                             sorthdr: sorthdr,
                                                             sortby: sortby,
                                                             sortorder: sortorder,
                                                             noempty: noempty,
                                                             inSlider: inSlider,
                                                             tableID: tableID,
                                                             initiallyOpen: initiallyOpen);
                      stb.Append(html);
                  }

          Comment


            #6
            Originally posted by Simplex Technology View Post
            Any upcoming documentation or examples?
            Example project is included, very basic though

            Comment


              #7
              Collapsible tables:

              Click image for larger version

Name:	Capture1.PNG
Views:	692
Size:	203.7 KB
ID:	1289543

              Comment


                #8
                And the code for the example above:

                Code:
                        private void BiuldTriggerGroup(StringBuilder stb, TriggerGroup group)
                        {
                            string[] hdr =
                            {
                                AddBtn(group.MakeIdStr("adddev"), "Add device to trigger group", small: true),
                                "",
                                LocationLabels.Item1,
                                LocationLabels.Item2,
                                "Device",
                                "Trigger State"
                            };
                
                            TableBuilder table = new TableBuilder( GroupTitle(group),
                                                                  ncols: hdr.Length,
                                                                  tableID: group.MakeIdStr("table_group"),
                                                                  page_name: PageName
                                                                  );
                            // Edit Name/Description
                            BuildGroupEdit(table, group);
                
                            // Row for group options
                            BuildGroupOptions(table, group, in_table: false);
                
                            table.AddBlankRow();
                            table.AddRowHeader(hdr);
                
                            // Add rows for devices in group.groupSettings.deviceIDs
                            for (int i = 0; i < group.groupSettings.deviceIDs.Count; i++)
                            {
                                TableBuilder.TableRow row = table.AddRow();
                                BuildDeviceRow(row, i, group);
                            }
                
                            string html = table.Build( initiallyOpen: GetSlideOpen(table.tableID) || group.editMode ,
                                                       titleAlt: GroupTitle(group, alt: true));
                            stb.Append( html );
                        }
                
                        public void BuildDeviceRow(TableBuilder.TableRow row, int ind, TriggerGroup group)
                        {
                            int devID = group.groupSettings.deviceIDs[ind];
                            DeviceBase dev = ((HSPI)plugin).controller.GetDevice(devID);
                
                            var del_btn = DeleteBtn(group.MakeIdStr("deldev", ind), "Remove device from group", value: devID.ToString(), small: true);
                            row.AddCell(del_btn, attrs: " style='padding-left: 5px;' ");
                
                            // Selector ID for btn_change_device is unique for this group/device
                            // i.e. "grp_1_device_0" - update device 0 in grp 1 to selected device ID
                            // exclude - devices already in group, and device itself, Except for current device id
                            BuildDeviceSelector( row,
                                                 dev,
                                                 selectorID: group.MakeIdStr("setdev", ind),
                                                 devices: ((HSPI)plugin).controller.devices,
                                                 exclude: group.ExcludeList(ind));
                
                            // Build list of Status states for trigger device
                            row.AddCell(BuildVSVGPairsDropList( dev,
                                                                name: group.MakeIdStr("setstate", devID),
                                                                selectedValue: group.TriggerStateStr(devID), // TEMP - TODO: ADD PREFIX/SUFFIX!
                                                                StatusControl: ePairStatusControl.Status,
                                                                selectedPair: out MyPair selectedPair,
                                                                AddBlankRow: true, // By default don't select any state
                                                                AddRange: true //Add range pair in addition to split range pairs
                                                                ) );
                        }

                Comment


                  #9
                  And I said many times already - this kind of "SDK" should be provided by HST, they know better how to use their code. And they also could use it internally in HS.
                  It's hard to imagine how many man*hours was spent by each plugin developer for reinventing the code which was done already by hundreds of other developers.
                  My code is based on great works of alexdresko : alexdresko/HSPI - but I prefer to put most of the code in the dll and reuse it instead of using VS template project.

                  Comment


                    #10
                    Originally posted by alexbk66 View Post
                    And I said many times already - this kind of "SDK" should be provided by HST, they know better how to use their code. And they also could use it internally in HS.
                    It's hard to imagine how many man*hours was spent by each plugin developer for reinventing the code which was done already by hundreds of other developers.
                    My code is based on great works of alexdresko : alexdresko/HSPI - but I prefer to put most of the code in the dll and reuse it instead of using VS template project.
                    You should have seen the older forum with the years of history of the same complaints. The current "SDK" documentation is... to be more polite "lacking" and plugin development is very experimental trial-error. I also know that sirmeili has been working on a inclusive SDK wrapper so I think things are going to get greatly improved with the new developments.

                    Comment


                      #11
                      Originally posted by Simplex Technology View Post
                      The current "SDK" documentation is... to be more polite "lacking" and plugin development is very experimental trial-error
                      That's kind of disrespectful to the paying clients, given HST get their 30% cut too.

                      Comment


                        #12
                        Originally posted by alexbk66 View Post
                        That's kind of disrespectful to the paying clients, given HST get their 30% cut too.
                        I couldn't agree more. The SDK documentation is poor and not written in a decent programming language.

                        Thanks for your effort alexbk66 , will have a look at it next time I write a plugin.

                        Comment


                          #13
                          Interessting.
                          HSPro 3.0.0.458, Z-NET with Z-wave plugin 3.0.1.190, RFXCOM + 2x RFXtrx433E, HSTouch, Squeezebox plugin, iTach IP/WF2IR & GC-100-6 with UltraGCIR, BLDenon, NetcamStudio, Jon00s Webpage builder, Harmony Hub plugin, SCSIP (with FreePBX), Arduino plugin, IFTTT, Pushalot plugin, Device History plugin.
                          Running on Windows 10 (64) virtualized
                          on ESXi (Fujitsu Primergy TX150 S8).
                          WinSeer (for Win10) - TextSeer - FitbitSeer - HSPI_MoskusSample

                          Are you Norwegian (or Scandinavian) and getting started with HomeSeer? Read the "HomeSeer School"!

                          Comment


                            #14
                            Originally posted by alexbk66 View Post
                            That's kind of disrespectful to the paying clients, given HST get their 30% cut too.
                            I'm not disrepecting anyone by saying the HS documentation and SDK are lacking in documentation or direction. This is a long standing complaint by many.

                            Comment


                              #15
                              Originally posted by Simplex Technology View Post

                              I'm not disrepecting anyone by saying the HS documentation and SDK are lacking in documentation or direction. This is a long standing complaint by many.
                              I think his comments were directed at HST and not you, given that HST receive their percentage of the sales.

                              Comment

                              Working...
                              X