Create a Plugin Guide

From Open Source Automation Wiki
Jump to: navigation, search

Contents

Introduction

Developing a plugin for Open Source Automation is simple. If you have any experience with .NET and Visual Studio you will probably find it very easy to get a plugin up and running. To help with that process we have compiled this documentation to guide you through the process of creating a very basic plugin. To help illustrate the process we will be using the Network Monitor plugin that comes with base package in OSA as an example. The source can be found in the Github repository.

Defining Object Types

Before we jump right into coding we need to define which object types we will manage. There are two main parts to any plugin. The DLL that gets loaded when OSA starts and the object types that the plugin uses. The first thing we will do is create the object type that will represent the plugin. In our example this is the NETWORK MONITOR object type, with base type PLUGIN and label Network Monitor Plugin. This is the object type that is used when the service initially creates the plugin object for the first time. When creating your object type be sure to add any properties that your plugin will need when it is loaded. This could be things like port for plugin that interface with serial port hardware, or zip/postal code if your plugin needs to know a users location, like the weather plugin. These properties will be loaded into the code when the plugin is loaded.

Next, depending on what kind of plugin you are creating, you may need to define additional object types to represent other objects in the system. If you are creating a Device Source plugin, you will need to define types for each distinct type of device your plugin will recognize. For example, the Z-Wave plugin uses a few object types to represent all of the hardware on the Z-Wave network, like dimmers, relays, remotes, etc.

These types will be added to the database in your plugin's install.sql file. (You can get the SQL for each type by clicking Export on the Object Type in the WebUI.) See tips below for setting the Ownership of these device Object Types.

Coding

If you use the plugin template discussed here the following steps will already be completed for you.

Once we have all the object types that we need for our plugin we can start actually coding it. Run Visual Studio and create a new project. Select the Class Library template and enter a name (MyPlugin) for your project. Visual Studio creates your project and opens Class1.cs. Rename this class to something useful (MyPlugin.cs). Press OK when VS asks you to update the project with the new name.

For a working plugin, we need to do a few things to set up the structure. First, we need to add a reference: OSAE.API. To do this right click on the project in the solution explorer and choose "Add reference". Go to the Browse tab and locate the OSA output folder after you have compiled the API project. There you will find the OSAE.API.dll assembly. Add it to your project.

Change your MyPlugin.cs file to the following:

using System;

namespace MyPlugin
{
    public class myPlugin : OSAEPluginBase
    {
    }
}

Right click OSAEPluginBase and select "Implement Abstract Class". This will create all of the necessary methods your plugin needs. We will go through each one to explain what they do.

Continue here if you used the plugin template

Additional Note: If developing a plugin for a new device, in many cases, you will also need to obtain the "Software Development Kit" (SDK) or any API that is available for that device. For example: Most of the X-10 plugin's (CM15A and CM11A) require the ActiveHome SDK to be installed. You can see the other SDK dlls used by the OSA plugins here, other software OSA is built upon. As above, you may need to add a reference to the SDK dll files before your plug in will operate correctly. Refer to any SDK examples included, to properly understand how to use the commands available and communicate with your new device.


RunInterface

This method is called once when the plugin is started. It contains all for the logic that initializes variables and makes initial connections to other devices such as opening a serial port or making a Ethernet socket connections to a remote device. The RunInterface routine is also used to start any timers that will be used to poll devices. For example, in the Weather plugin this is where a timer is created to check for weather updates. The Network Monitor plugin creates a timer in this method to ping all Computer objects every 5 minutes.


ProcessCommand

This function is called whenever the service finds a method in the queue that is associated with the plugin. Your plugin will presumably then do something with this command. For example with the Z-Wave plugin, any time a light needs to be turned on a method is placed in the queue, the service then retrieves it and passes it along to the Z-Wave plugin. Once it is received the plugin reads it and sends the command to the light to turn on. Our example of the Network Monitor plugin, this method is not used since it doesn't process any commands.


Shutdown

This method is called when a plugin is disabled or when the service is stopped. The purpose of it is to have the plugin properly dispose of any timers, threads, etc.


When you compile your plugin you will get a .dll file as a result and this is what the OSA service will load. In order for it to load properly it will need to be in its own directory in the OSA/Plugins directory and have a .osapd file with it...

Other Tips

Getting device status into OSA objects

Generally there are two types of remote devices a plugin can handle. Those that need to be polled on a regular bases and those that send a message to the plugin when an event in the device occurs such as a change in state. The event type that sends an unsolicited message are preferred because they can notify the plugin of a change with less delay. They also reduce the polling overhead on the system and communication link.

Regardless of the device type there are two general ways to handle the messages from the device. A timer can be set up to check the connection for new data/message. This could be checking for new data in a serial port buffer or an Ethernet socket buffer. The other method is to configure an interrupt to have the system tell the plugin there is new data/message. If the device requires polling then usually the plugin will send a message to the device requesting data then wait for the response message from the device. Regardless of which method is used, the timer or interrupt should be set up and initiated in the RunInterface routine.

After receiving a message from the remote device the plugin code should parse the message and determine if anything has changed about the device. If the state has changed the plugin should update the state with:

OSAEObjectStateManager.ObjectStateSet("Object", "State", pName)

If a property has changed then it should be updated with:

OSAEObjectPropertyManager.ObjectPropertySet("Object", "PropertyName", "PropertyValue", pName)


Trigger Events

If you need to trigger an event of the object you can do it with:

OSAEObjectManager.EventTrigger("Object", "Event")

Owned Object Types Your plugin knows which Methods to handle by setting its Object as the Owner of certain Object Types. This can be set and changed manually by users, but every plugin that processes methods for certain object types should always make sure that it owns any un-owned relevant object types. Here is a code example in VB:

   Public Sub OwnTypes()
       Dim oType As OSAEObjectType
       'Added the follow to automatically own relevant Base types that have no owner.
       oType = OSAEObjectTypeManager.ObjectTypeLoad("PHIDGET ANALOG INPUT")
       Log.Info("Checking on the PHIDGET ANALOG INPUT Object Type.")
       If oType.OwnedBy = "" Then
           OSAEObjectTypeManager.ObjectTypeUpdate(oType.Name, oType.Name, oType.Description, pName, oType.BaseType, 0, 0, 0, IIf(oType.HideRedundant, 1, 0))
           Log.Info(pName & " Plugin took ownership of the PHIDGET ANALOG INPUT Object Type.")
       End If
   End Sub


Creating the .osapd File

Every plug needs to have a .osapd (OSA Plugin Description) file to tell the service all the necessary information about it so it can load it properly. Find the Plugin Description Editor in your OSA installation directory and run it. Enter the following information:

Name: MyPlugin ID: press Generate ID

First, let's save the description file to your plugin folder. The name should be MyPlugin.osapd. Then, enter all other settings: versions: 0.1 Alpha Under the tab Installation destination folder: MyPlugin mainfile: MyPlugin.dll

Save the .osapd file and close the Description Editor.

You should now have your plugin DLL and a .osapd file in its own directory under OSA\Plugins. You are now ready to test it out by starting the service and enabling it with the Manager.

Packaging Your Plugin

If you wish to share you plugin with the rest of the world (that is the point of a community project, right?) you will need to package it up. This is done with the Plugin Description Editor. Simply open your plugin's .osapd file and select File->Create Package. This will take all of the files in the directory with the .osapd file and package this into a .osapp file. This should include the .dll, a image called 'Screenshot.jpg'(make sure the first S is capitalized), a file containing the sql to create the necessary objects (called 'install.sql') and any additional assemblies your plugin requires. The image file is used when you upload your plugin package to the plugin repository on the OSA website. It will be displayed next to your plugin. The install.sql file is to make sure any user that installs your plugin will have any object types necessary to use the plugin.

If your plugin needs different files for 32 and 64 bit OS see the following post for details on include both versions of the files http://www.opensourceautomation.com/phpBB3/update-to-plugin-installer-and-plugin-description-editor-t352.html

Test and Debug your Plugin

After installing the plugin, new development versions of the plugin can be tested by copying a new DLL to the OSA\Plugins\PluginName directory. Make sure the OSA Service is stopped or the plugin is stopped when trying to copy a new version of the DLL over an existing version.