The drivers provided by the library are derived from a common base class. This supports connection to the Edge Agent and communication with the user-provided handler class.
The basic structure of any driver using this library looks like this:
/* Import an appropriate subclass */
import { Driver } from "@amrc-factoryplus/edge-driver";
/* This implements the driver functionality */
class Handler {
/* This is called to construct a handler */
static create (driver, conf) { }
/* This method is required */
connect () { }
/* These properties and methods are optional */
static validAddrs;
parseAddr (addr) { }
async subscribe (specs) { }
async close () { }
}
/* Don't use Driver directly, use a subclass */
const drv = new Driver({
env: process.env,
handler: Handler,
});
drv.run();
A handler class is required; this implements the driver functionality
and must support the interface required by the Driver subclass in use.
Then a generic driver object is created passing the handler class. Every
time the Edge Agent sends a new config, the library will destroy the
current handler and create a new one. The driver will then call the
connect
method on the handler which should attempt to connect to the
southbound device. The handler reports connection status and received
data by calling methods on the driver.
The driver object needs access to the process environment to communicate with the Edge Agent; this assumes the standard environment variables are being used.
The documented API is detailed below. Any other methods or properties are not documented and must not be relied on.
A Driver
object represents the whole driver process, and handles
communication with the Edge Agent. The class Driver itself should be
considered abstract; create instances of subclasses. Methods documented
below can be called from the handler class.
const driver = new Driver({
env: process.env,
handler: HandlerClass,
});
The env
property should be process.env
, or a suitable substitute.
The keys EDGE_MQTT
, EDGE_USERNAME
and EDGE_PASSWORD
will be used
to initiate communication with the Edge Agent. The key VERBOSE
will be
used to configure the logger.
The handler
property specifies the handler class to implement the
functionality of this driver. This must support the interface required
by the Driver subclass in use, which will be a subinterface of the
Handler
interface below.
driver.debug.log(channel, message);
This property is a Debug object configured from the environment. The handler class should use this for logging.
driver.run();
This method starts the communication with the Edge Agent. It does not return.
driver.connUp();
This should be called by the handler to report that the connection to
the southbound device has been successfully established. If the handler
connect
method returns a Promise then this method should not be used.
driver.connFailed();
This should be called by the handler to report that the connection to
the southbound device has failed. The handler should not call this
unless it has previously returned UP
from the connect
method. The
handler should not attempt to reconnect or produce any more data until
the driver has reconnected.
driver.connUnauth();
This should be called by the handler to report an authentication problem
with the southbound device. This should only be called in the same
circumstances as connFailed
.
driver.reconnect = 5000;
This property can be set by the handler to adjust the the reconnection delay. The default is 5000 (5 seconds).
The handlers required by Driver subclasses all need to implement this interface, in addition to any further requirement imposed by the subclass.
const handler = HandlerClass.create(driver, conf);
This is a static method called to construct a handler object. The method
is passed the driver object this handler belongs to and the
configuration received from the Edge Agent. The method should validate
the configuration and return undefined
if it is invalid. Otherwise it
should construct and return a handler object.
This method should not attempt to connect to the southbound device.
handler.connect();
const status = await handler.connect();
This is called by the driver to initiate connection to the southbound
device. This method may either return undefined
or a Promise to a
string.
An undefined return value requests use of the callback API; the connect
method must subsequently call one of the conn...
method on the Driver
to report the connection status. A Promise return value must resolve to
a string, one of "UP"
, "CONN"
, or "AUTH"
, to report the connection
status directly.
If the connection is reported as having failed the driver will call
connect
again after a delay. The handler is responsible for ensuring
any previous connection is cleaned up properly.
const valid = HandlerClass.validAddrs.get(addr);
This property is optional.
If a handler class has this property, it should be a Set of strings
indicating valid addresses. This is only suitable for drivers which have
a fixed set of constant addresses, but can be used instead of a
parseAddr
method which only validates.
const spec = handler.parseAddr(addr);
This method is optional.
This method parses an address string and returns a data structure suitable for the handler's internal purposes. This will be passed to the driver later in place of the address. This method may be called at any time; in particular it may be called before the handler has connected.
The string should be validated for syntax, but no IO can be performed. This method should be a pure function: it should produce the same result every time for the same argument. If this method is not provided then address strings are passed through as-is.
await handler.subscribe(specs);
This method is optional.
If this method exists it will be called whenever the Edge Agent has
changed the list of addresses it is interested in. The method is passed
an Array of specs as returned from parseAddr
. The handler can use this
to set up subscriptions to the southbound device.
await handler.close();
handler.close(done);
This method is optional.
If this method exists it is called when a new configuration is received, just before the old handler object will be unreferenced. The method should perform any cleanup (closing connections, etc.) needed before reconnecting.
The method supports both Promise-based and callback-based APIs. The method is passed a callback, which can be called to indicate cleanup is finished. Alternatively the method can return a Promise.