Walkthrough - Writing An Examplar Device Plugin
This tutorial will walk you through creating an examplar device plugin. You will need the following:
1. A working installation of MakeAffinity Client (setup here)
2. Visual C# Express (it's nice and free).
The tutorial assumes that you are familiar with MakeAffinity and C#. The tutorial uses Visual C# Express 2005. Instructions and screen shots may be slightly different from other versions of Visual C# Express but are just as applicable.
The tutorial should take you less than 50 minutes.
Visual C# Express will be referred to as VCE for the sake of brevity. MakeAffinity Client will be referred to as the client for the same reason.
The VCE project for this walkthrough can be downloaded from the Developer Center under Downloads.
The complete colour-coded source code for this walkthrough is shown here.
The main steps of writing a plugin are:
Step 1: Create a new class library project in VCE.
Step 2: Add a reference to the client's MAFFDevice.dll.
Step 3: Set the output path of your plugin project to your client's plugin folder.
Step 4: Add client Start & Stop build events to your plugin project.
Step 5: Create a MyManager class that inherits from MakeAffinity.Plugin.Manager.Manager.
Step 6: Create a MyRelay class that inherits from MakeAffinity.Plugin.Devices.Relay.
Step 7: Write code for the methods in MyRelay.
Step 8: Write code for the methods in MyManager.
Step 9: Compile and test your plugin.
Step 10: A debugging scenario.
Step 1: Create a new class library project in VCE
In VCE, go to File -> New Project -> choose Class Library -> use MyExemplarPlugin as name -> click OK.
When VCE completes creating your new project, it will display your source file.
Step 2: Add a reference to MakeAffinity Client's MAFFDevice.dll.
A) Go to Project -> Add Reference to bring up the Add Reference dialog box.
B) Click on the Browse tab, locate MakeAffinity Client's MAFFDevice.dll and click OK.
MAFFDevice.dll contains the device types you need to inherit from in your plugin.
The file should be located in C:\Program Files\MakeAffinity\makeaffinity\bin
Once added, MAFFDevice.dll will be listed under References in Solution Explorer.
Step 3: Set the output path of your plugin project to the Client's plugin folder
A) Go to Project -> MyExemplarPlugin Properties to bring up the project properties dialog page.
B) Click on the Build tab.
C) Click on the Browse button under Output path to bring up the Select Output Path dialog box.
D) Locate and choose MakeAffinity Client's plugin folder.
This will make VCE copy the project's compiled output to the folder so the client will
always be able to use the latest compiled version.
The folder should be located at C:\Program Files\MakeAffinity\makeaffinity\DevicePlugins
Step 4: Add client Start & Stop build events to your plugin project
A) Go to Project -> MyExemplarPlugin Properties to bring up the project properties dialog page.
B) Click on the Build Events tab.
C) Add this to the Pre-build event command line (including the double-quotes):
"C:\Program Files\MakeAffinity\bin\ClientStop.exe"
D) Add this to the Post-build event command line (including the double-quotes):
"C:\Program Files\MakeAffinity\bin\ClientStart.exe"
The steps above are to stop the client each time VCE begins any compilation activities, and restart the client when compilation completes so you can see any new code changes in action.
Step 5: Create a MyManager class that inherits from MakeAffinity.Plugin.Manager.Manager
The original code in Class1.cs should look like this:
using System;
using System.Collections.Generic;
using System.Text;
namespace MyExemplarPlugin
{
public class Class1
{
}
}
|
A) Replace all of the code in the Class1.cs with the following:
|
using System;
using System.Collections.Generic;
using System.Text;
using MakeAffinity.Plugin;
namespace MyExemplarPlugin
{
public class MyManager: MakeAffinity.Plugin.Manager.Manager
{
}
}
|
The following is how the new code is different:
1) Added the directive: using MakeAffinity.Plugin;
2) Deleted Class1.
3) Added a MyManager class which inherits from MakeAffinity.Plugin.Manager.Manager.
B) Implement abstract class MakeAffinity.Plugin.Manager.Manager using IntelliSense.
In the code, click on MakeAffinity.Plugin.Manager.Manager. The first letter will then appear underlined.
Click the smart tag under MakeAffinity,
and click Implement abstract class 'MakeAffinity.Plugin.Manager.Manager'.
IntelliSense adds two override methods from the Manager class to the
MyManager class: Initialise and Shutdown.
Step 6: Create a MyRelay class that inherits from a MakeAffinity device type
A) Add a MyRelay class to the code so that the end result looks like the following.
|
using System;
using System.Collections.Generic;
using System.Text;
using MakeAffinity.Plugin;
namespace MyExemplarPlugin
{
public class MyManager: MakeAffinity.Plugin.Manager.Manager
{
public override void Shutdown()
{
throw new Exception("The method or operation is not implemented.");
}
public override void Initialise()
{
throw new Exception("The method or operation is not implemented.");
}
}
public class MyRelay : MakeAffinity.Plugin.Devices.Relay
{
}
}
|
B) Like before, implement abstract class MakeAffinity.Plugin.Devices.Relay using IntelliSense.
In the code, click on MakeAffinity.Plugin.Devices.Relay. The first letter will then appear underlined.
Click the smart tag under MakeAffinity,
and click Implement abstract class 'MakeAffinity.Plugin.Devices.Relay'.
IntelliSense adds nine override methods from the Relay class to the MyRelay class:
BrandName, ModelName, SerialNumber, Initialise, Shutdown, MakeSafeAll, OutputCount, GetState, SetState
Step 7: Write code for the methods in MyRelay
IntelliSense has helped us to create the method stubs. We can now write the code for them. We will focus on MyRelay first. Implement the methods in MyRelay as shown below.
A) Implement the common device identification methods (BrandName, ModelName, SerialNumber) so the client will know how to identify our device. We'll use example values for the brand name, model name, and serial number.
|
public override string BrandName
{
get { return "MyExemplarRelayBrand"; }
}
public override string ModelName
{
get { return "MyExemplarRelayModel"; }
}
public override int SerialNumber
{
get { return 99999; }
}
|
B) Implement the common device management methods (Initialise, Shutdown, MakeSafeAll) so the client can manage our device. We'll just make the methods write some messages to the client's status box so we can see what goes on when the client talks to our device plugin.
|
public override void Initialise()
{
// write a message to the client's status screen
ReportErrorMessage(this, "MyRelay.Initialise Invoked");
}
public override void Shutdown()
{
// write a message to the client's status screen
ReportErrorMessage(this, "MyRelay.Shutdown Invoked");
}
public override void MakeSafeAll()
{
// write a message to the client's status screen
ReportErrorMessage(this, "MyRelay.MakeSafeAll Invoked");
}
|
C) Implement the methods that are specific to relay plugins (GetState, SetState, OutputCount). We'll just make the methods write messages to the client's status box so we can see when they are invoked by the client.
|
public override bool GetState(int index)
{
// write a message to the client's status screen
ReportErrorMessage(this, "MyRelay.GetState: index=" + index);
// return an example value
return true;
}
public override int OutputCount
{
get
{
// write a message to the client's status screen
ReportErrorMessage(this, "MyRelay.OutputCount Invoked");
// return an example value
return 4;
}
}
public override void SetState(int index, bool value)
{
// write a message to the client's status screen
ReportErrorMessage(this, "MyRelay.SetState: index=" + index + " value=" + value);
}
|
Step 8: Write code for the methods in MyManager
A) Implement MyManager's Initialise method.
|
public override void Initialise()
{
//During development: display a message so we know what's going on
ReportErrorMessage(this, "MyManager.Initialise Invoked");
//create an instance of MyRelay
MakeAffinity.Plugin.Devices.Device myPlugin = new MyRelay();
//initialise the instance of MyRelay so it is in a ready state
myPlugin.Initialise();
//add the instance to MyManager's MAFFDevices collection
//so the client can use it
MAFFDevices.Add(myPlugin as MakeAffinity.Plugin.Devices.Device);
}
|
B) Implement MyManager's Shutdown method
|
public override void Shutdown()
{
//During development: display a message so we know what's going on
ReportErrorMessage(this, "Shutdown: ExampleManager1");
//shutdown all the devices in MAFFDevices
foreach (MakeAffinity.Plugin.Devices.Device dev in MAFFDevices)
{
dev.Shutdown();
}
//clear all MAFFDevices
MAFFDevices.Clear();
}
|
Step 9: Compile and test your plugin
The code is now complete and is here for your reference (Code Listing 1).
A) Compile your project: Go to Build -> Build Solution
VCE will launch the MakeAffinity Client when compilation completes without errors. If you encounter errors, compare your code to Code Listing 1.
B) At the client, click on Status button to see the status messages.
You should see messages indicating that your plugin is working, similar to the following:
Device message: (Code 0) MyManager.Initialise Invoked
Plugin Manager initialised for MyExemplarPlugin.dll
Plugin device loaded: MyExemplarRelayBrand MyExemplarRelayModel 99999
Device message: (Code 0) MyRelay.Initialise Invoked
Device message: (Code 0) MyRelay.OutputCount Invoked |
C) See your plugin in action at the website:
Go to www.makeaffinity.com and log into your account.
Go to Make -> Constructs tab -> Select any construct.
Go to Actions tab -> Add Action -> Show My Devices.
Your plugin device should show up in the Device dropdownlist with the serial number, brand name, and model name that you have specified in your code:
(99999) MyExemplarRelayBrand MyExemplarRelayModel
You can now use this relay plugin as you would any relay plugin. It does not do anything physical but it can show you what happens at your client when you test an Action from the Make Editor.
Choose MyExemplarRelay device in the Device dropdownlist.and click Test. The client will receive the action and display messages similar to the following:
Device message: (Code 0) MyRelay.Initialise Invoked
Device message: (Code 0) MyRelay.Initialise Invoked
Device message: (Code 0) MyRelay.SetState: index=0 value=False |
Change the Switch No. and On/Off state at the Make Editor and click Test again and observe the client displaying similar messages to the above but with different action properties.
Step 10: A debugging scenario
Here, we will create errors in your plugin and show you how you can debug it.
A) Introduce an exception. Add the following code at the top of MyManager.Initialise:
throw new Exception("Exception 1");
B) Compile your project: Go to VCE -> Build -> Build Solution
VCE will launch the client when compilation completes.
C) Click on Client -> Status button to see status messages. You will the following:
ERROR: Unable to load plugin in MyExemplarPlugin.dll, Message: Exception 1
D) More detailed information about the error is in the client's log file at C:\Program Files\MakeAffinity\makeaffinity\Logs\log.txt:
ERROR: Unable to load plugin in MyExemplarPlugin.dll, Message: Exception 1
Exception generated:
Message: Exception 1
Source: MyExemplarPlugin
Method: Void Initialise()
Stack Trace: at MyExemplarPlugin.MyManager.Initialise() in path\MyExemplarPlugin\MyExemplarPlugin\Class1.cs:line 28
at v.c() |
The detailed error message includes useful information such as the error message itself, the source assembly, namespace, class, method, and line number, as well as a stack trace.
The stack trace indicates that the fault is around line 28 in the source code. This is where we deliberately introduced the exception for our test scenario.
Right now, the plugin device will not appear in your Make Editor because it has failed to load successfully. Removing the erroneous line and rebuilding the project will remedy this.
End of tutorial