Driver Development Kit (DDK)

Top  Previous  Next

AggreGate Server Driver Development Kit (DDK) is a part of AggreGate SDK that allows to implement custom AggreGate Server Device Drivers in Java programming language.

AggreGate Server Device Driver is a special type of AggreGate Server plugin. Technically, the driver has two mandatory components:

Driver Java class that implements DeviceDriver interface. Most implementations extend AbstractDeviceDriver class to avoid implementing irrelevant methods and preserve their default functionality.
Driver plugin descriptor that defines driver plugin properties and its place in AggreGate Server plugins hierarchy.

note_example-wt

Device Server SDK bundle includes an open-source example of AggreGate Server Device Driver implementation called Demo Device Driver. It is located in examples.driver package and comprises three files:

DemoDeviceDriver.java - source code of the driver
plugin.xml - driver plugin descriptor
build.xml - Ant build file with a single task building driver's JAR archive

To try the driver:

Run build.xml using Ant to build demo.jar
Copy demo.jar to %AggreGate Server Installation Folder/plugins/device when AggreGate Server is not running
Start AggreGate Server
Create new Device account and specify Demo Device as driver type

Creating New Device Driver

To create new device driver from scratch, create new Java class inherited from AbstractDeviceDriver. You will need to override at least some of the methods to provide driver functionality.

Global and Per-account Configuration

Certain plugins may have global and per-user-account configuration settings.

To add global and per-user settings, implement globalInit() and userInit() methods respectively. Their implementations should call createGlobalConfigContext() and createUserConfigContext() and provide VariableDefinition's of global and per-user settings. These settings will be exposed to system administrators, their values get persisted in the database. The variables must belong to "default" group, available as ContextUtils.GROUP_DEFAULT constant.

To access setting values from any method of the plugin, retrieve global or per-user config contexts using getGlobalConfigContext() or getUserConfigContext(), then call Context.getVariable() to fetch instances of DataTable representing setting values.

Setting Up Device Context

AggreGate Server calls setupDeviceContext() method of the driver when new device account is created or server is started. The method receives an instance of DeviceContext interface that is a Device Context representing this device account. Call super.setupDeviceContext() to store its reference inside AbstractDeviceDriver.  It will be available via getDeviceContext() method.

The main purpose of setupDeviceContext() is adding device-specific communication settings. They are added in the form of context variables belonging to ContextUtils.GROUP_ACCESS variable group. System operator is prompted to edit these settings upon device account creation, and they can be later accessed using Edit Device Properties action.

Communication setting variables should be added to device context using Context.addVariableDefinition() method.

The actual user-specified values can be later fetched from DeviceContext using Context.getVariable(), e.g. from DeviceDriver.startSynchronization() or DeviceDriver.connect().

Starting and Finishing Synchronization

Device driver has two methods that are called in the beginning and in the end of synchronization respectively: startSynchronization() and endSynchronization(). These methods may be used to initialize and clear some driver's internal caches or other data structures.

Handling Connections and Disconnections

DeviceDriver.connect() method should establish a connection with the hardware device. It usually uses communication settings described in Setting Up Device Context (see above). In most cases, connection includes several steps:

Fetch device communication properties by calling getDeviceContext.getVariable(). Use getDeviceContext().getCallerController() as a caller controller in these calls to ensure proper permission level.
Bringing up a link (opening TCP socket, serial port, etc.)
Sending authentication/authorization credentials to the device and processing its reply
Switching the device to "configuration mode", if applicable

The connect() method should throw an exception if connection has failed at any phase. Otherwise, if should call super.connect() method of AbstractDeviceDriver in the end of method body to mark device as connected. AbstractDeviceDriver will then provide a correct result of isConnected() method.

DeviceDriver.disconnect() should correctly shutdown the link to hardware. It's called on server shutdown, account removal, or when reconnection to the device is requested by the system.

note_tip-wt

To force reconnection during driver testing/debugging, use Reset Device Driver action.

Reading Device Metadata

There are three methods that are called by the AggreGate Server core during full synchronization:

readVariableDefinitions() that should examine available device settings (or communication properties if the device protocol does not support self-documentation) and create a VariableDefinition object for every available device setting. Depending to the communication protocol, device settings may be also called I/O channels, tags, configuration items, etc. See variable definition for details.
readFunctionDefinitions() that should provide one FunctionDefinition object per every operation provided by the hardware. In different communication standards, device operations may be also called device methods, functions, actions, procedures, etc. See function definition for details.
readEventDefinitions() that provides one EventDefinition object for every type of event that can be generated by hardware. In some device protocols, events may be also called messages, notifications, etc. See event definition for details.

Definitions of variables, functions and events provided by the driver are added to the Device context and cached. The driver may not be asked to re-read them until the next full synchronization even if the server was restarted.

note_tip-wt

To force re-reading of device metadata during driver testing/debugging, use Reset Device Driver action.

Reading/Writing Device Settings

If the driver has provided a non-empty list of device settings from readVariableDefinitions() method, server core will call readVariableValue() and writeVariableValue() methods of the driver. readVariableValue() should read up-to-date setting value from the hardware and convert it to the form of DataTable matching format defined in its VariableDefinition. On the contrary, writeVariableDefinition() takes value encoded as a DataTable, converts it to the device native format and writes to the hardware.

Setting is being read from the hardware:

During first synchronization, and
During any other synchronization if there are no server-side changes of its value

Setting is being written to the hardware during synchronization if it's writable according to the definition and there were some server-side changes of its value.

Setting values will be cached inside the Device context. The driver may not be asked to re-read them until the next full synchronization even if the server was restarted.

note_tip-wt

To force re-reading of device settings during driver testing/debugging, use Synchronize action.

Executing Device Operations

If the driver has provided a non-empty list of device settings from readFuncitonDefinitions() method, AggreGate Server will add a Call Function action per every device operation. Being executed by system operator, this action prompts to specify input data (according to function input format, and only if it's not "empty"), then calls executeFunction() method of device driver and shows its output to the operator (also only if it's not "empty").

Thus, driver-specific implementation of executeFunction() method should basically:

Convert input Data Table to the device native format
Send input data to the hardware
Trigger device-side operation
Read operation output from the device
Convert device-side output to the Data Table and return it

Working With Device Events

When dealing with events, device driver:

Returns the list of event definitions from readEventDefinitions() method. The list should include every type of event that may be produced by the hardware.
Asynchronously calls DeviceContext.fireEvent() method when new event instance is received from the hardware.

note_warning-wt

Device driver can start firing context events only after the end of first synchronization, i.e. after its finishSynchronization() method was called at least once.

When firing an event, the driver must ensure that format of event's Data Table containing event-specific data matches format stored in corresponding Event Definition.

Any event provided by device driver is persistent. It will be stored in event history if non-zero history storage time is defined for it.

Advanced Features

See javadocs of DeviceDriver, DeviceContext and parent interfaces for description of all their methods.

Modifying Plugin Descriptor

To create a plugin descriptor for your driver, make a copy of demo driver's plugin.xml file and edit the following in it:

Change the last word in id attribute of the <plugin> tag to the ID of new plugin. The ID should contain only lowecase letters, digits and underscores. For example, if your desired plugin ID is xyz, set ID attribute to com.tibbo.linkserver.plugin.device.xyz.
Change class attribute of <plugin> tag to full name of driver's java class.
Enter driver description in the body <doc-text> tag.
Change id attribute of the <extension> tag to the new plugin ID.

Building and Deploying Plugin Archive

Make a copy of demo driver's Ant build file (build.xml)
Change project name and name of destination file (plugin archive)
Run built.xml using Ant to build plugin Java archive
Copy the JAR file to %AggreGate Server Installation Folder/plugins/device when AggreGate Server is not running
Start AggreGate Server
Create new Device account and select new driver as driver type