Access Keys:
Skip to content (Access Key - 0)

Developer How-To: Add Your Own Protocol to OpenRemote 2.0 Controller

This how-to explains the steps necessary to add your own protocol implementation into OpenRemote 2.0 Controller codebase.

1. Protocol Implementation

In OpenRemote 2.0, protocol implementations must be written in Java. Create your Java classes in org.openremote.controller.protocol.* package. For this, you will need the following:

CommandBuilder Interface

The CommandBuilder interface is responsible for taking the XML definition from the controller.xml file and turning it into Java object instances (which must in turn implement the Command interface).

The generic structure of all command XML definitions is following:

  <command protocol = "protocol-id" >
    <property name = "argname1" value = "..."/>
    <property name = "argname2" value = "..."/>
    <property name = "argnameX" value = "..."/>
  </command>
Listing 1: Generic XML structure of a protocol command in OpenRemote 2.0 Controller

Where each command is represented by its own element with an arbitrary number of property elements as its children. Properties are defined as name, value pairs.

The Java interface to implement is simply defined as:

public interface CommandBuilder
{
  Command build(Element element);
}
Listing 2: CommandBuilder interface

As a response from the CommandBuilder build(Element element) method, you should return a concrete, protocol specific command implementation. The command instance should implement network or other media based communication for reading or writing to a device. See more details below in the "Command Interface" section.

XML Parsing

The command definition is stored in Controller's controller.xml configuration file (normally generated by the OpenRemote 2.0 Designer tool). This XML definition must be turned into a concrete Java implementation in the CommandBuilder implementation.

Each command is stored as a list of name and property values (see Listing 1 above). These properties can be used to instruct the CommandBuilder implementation on how to construct and initialize its concrete Command instances.

The XML API library used is JDOM. A simple parsing of command properties from the JDOM Element instance passed as an argument to CommandBuilder's build(Element element) method can be achieved as follows:

public class MyCommandBuilder implements CommandBuilder
{

  ...

  public Command build(Element element)
  {
    // Get the list of properties from XML. XML_ELEMENT_PROPERTY is defined to
    // match the "property" element name in the XML snippet.

    List<Element> propertyElements =
        element.getChildren(CommandBuilder.XML_ELEMENT_PROPERTY, element.getNamespace());

    // Iterate through each command property...

    for (Element el : propertyElements)
    {
      // XML_ATTRIBUTENAME_NAME defines the "name" attribute of "property" element in
      // the XML snippet, i.e. <property name = "foo" ... />

      String propertyName = el.getAttributeValue(CommandBuilder.XML_ATTRIBUTENAME_NAME);

      // XML_ATTRIBUTENAME_VALUE defines the "value" attribute of "property" element
      // in the XML snippet, i.e. <property name = "foo" value = "bar"/>

      String propertyValue = el.getAttributeValue(CommandBuilder.XML_ATTRIBUTENAME_VALUE);

      // Store your command properties for configuring/initializing your Command instances...

      ...
    }

    return new MyCommand(myProperties);
  }
}
Listing 3: Example of XML parsing Command's properties

Lifecycle

Command builders are instantiated by the Spring service container which is configured with the controller's applicationContext.xml file (see later). Under normal circumstances command builders should be considered as singletons and instantiated only once during the controller's lifecycle. This is the default bean lifecycle unless specified otherwise.

Should you choose a non-singleton command builder model, it is advisable to consider the cost of initializing/constructing the command builder instance, especially if it is directly tied to incoming request frequency.

Command Interface

The Command interface is a tagging interface with no methods to implement. However, it's sub-interfaces are ExecutableCommand and StatusCommand. Your concrete protocol should implement either one of these (or both).

The ExecutableCommand interface is intended for "write" commands toward the device (setting values, invoking commands). It defines a simple send() method.

public interface ExecutableCommand extends Command
{
    public void send();
}
Listing 4: ExecutableCommand Interface

The StatusCommand interface is intended for "read" commands. It is used to read device state, configuration or property values.

public interface StatusCommand extends Command
{
   public String read(EnumSensorType sensorType, Map<String, String> stateMap);
}
Listing 5: StatusCommand Interface

Read commands are used by sensors to poll data from devices on a given interval. Both read and write commands can be invoked through the controller's HTTP REST interface.

The enum sensorType gives you an indication what type of return value the sensor expects from the read command. The return values are encoded as String values. Fixed sensor types are:

  • Switch - strings "on" or "off" are valid return values
  • Level - integer value in the range [0-100] as a string is a valid return value
  • Range - integer as a string is a valid return value

Lifecycle

Command instances are usually created per request. The constructors should be relatively light-weight to avoid performance impact. It is also a good idea to attempt to design your Command implementations as immutable instances where possible, to prevent possible race conditions.

For sophisticated use-cases, it would be possible to implement a Command Builder that re-uses command instances, especially if they are implemented as immutable classes. The design considerations of this would have to be considered carefully, though.

Examples

You can study existing protocol implementations for more detailed samples of CommandBuilder, ExecutableCommand and StatusCommand interfaces:


2. Controller Configuration

Once your protocol implementation is complete, you need to configure to add it to the controller's startup script. This is the applicationContext.xml file. It can be found under the 'config' directory of the Subversion checkout.

The relevant section is the "commandFactory" bean in the file, shown below


  ...

  <bean id = "commandFactory" class = "org.openremote.controller.command.CommandFactory">
    <property name = "commandBuilders">
      <props>
        <prop key = "ir">irCommandBuilder</prop>
        <prop key = "knx">knxCommandBuilder</prop>
        <prop key = "x10">x10CommandBuilder</prop>
        <prop key = "tcpSocket">tcpSocketCommandBuilder</prop>
        <prop key = "telnet">telnetCommandBuilder</prop>
        <prop key = "httpGet">httpGetCommandBuilder</prop>
        <prop key = "upnp">upnpCommandBuilder</prop>
        <prop key = "mine">myCommandBuilder</prop>
      </props>
    </property>
  </bean>

  ...

Listing 6: Command Factory builders in Controller's applicationContext.xml file

Give your protocol a unique ID (the "mine" key attribute in the above XML) and a bean name that you will use to instantiate your protocol implementation CommandBuilder ("myCommandBuilder" in the above listing).

Next, locate the relevant section in the applicationContext.xml to add the command builder instantiation configuration (constructor parameters) as shown below:


...

<!-- COMMAND BUILDERS ========================================================
 |
 | Implementation specific builders for the Event Factory bean. In short, each 
 | distinct  command  type,  as they appear in controller.xml,  will need a 
 | corresponding builder implementation.
 |
 | See the org.openremote.controller.command.CommandBuilder interface for 
 | details if you seek to extend the implementation with additional command 
 | types.
 +-->
	
  <!-- Infrared Command Builder -->
  <bean id = "irCommandBuilder" 
     class = "org.openremote.controller.protocol.infrared.IRCommandBuilder"/>

  ...

  <!-- My Protocol -->
  <bean id = "myCommandBuilder" 
     class = "org.openremote.cotroller.protocol.mine.MyCommandBuilder"/>

  ...

Listing 7: CommandBuilder JavaBeans in Controller's applicationContext.xml

With the above configuration, the expected XML snippet that your command builder implementation needs to parse – which is passed to your implementation as the element argument in CommandBuilder.build(Element element) API – would be:

<command protocol = "mine" >
  <property name = "argname1" value = "..."/>
  <property name = "argname2" value = "..."/>
  <property name = "argnameX" value = "..."/>
</command>
Listing 8: Example protocol command XML snippet in Controller's controller.xml file

With that, your protocol is now hooked into the OpenRemote 2.0 Controller implementation. Continue to add your protocol support into the OpenRemote 2.0 Designer by following the XML configuration steps in Developer How To - Adding Your Own Protocol to OpenRemote Boss 2.0 Designer.


See Also

Added by Juha Lindfors , last edit by Marc Fleury on Oct 07, 2010 15:05

© 2008-2011 OpenRemote Inc. OpenRemote is a trademark of OpenRemote, Inc.
Adaptavist Theme Builder (3.3.3-conf210) Powered by Atlassian Confluence 2.10.3, the Enterprise Wiki.
Free theme builder license