Autopilot Provider plugins

This document should be read in conjunction with the SERVER PLUGINS document as it contains additional information regarding the development of plugins that implement the Signal K Autopilot API.


Overview

The Signal K Autopilot API defines endpoints under the path /signalk/v2/api/vessels/self/autopilots providing a way for all Signal K clients to perform common autopilot operations independent of the autopilot device in use. The API is defined in an OpenAPI document.

Requests made to the Autopilot API are received by the Signal K Server, where they are validated and an authorisation check performed, before being passed on to a provider plugin to action the request on the autopilot device.

This de-coupling of request handling and autopilot communication provides the flexibility to support a variety of autopilot devices and ensures interoperability and reliabilty.

Autopilot API requests are passed to a provider plugin which will process and action the request facilitating communication with the autopilot device.

The following diagram provides an overview of the Autopilot API architectue.

Autopilot API architecture

Provider Plugins:

An autopilot provider plugin is a Signal K server plugin that implements the Autopilot Provider Interface which:

  • Tells server the autopilot devices provided for by the plugin
  • Registers the methods used to action requests passed from the server to perform autopilot operations.

The AutopilotProvider interface is defined in @signalk/server-api

Multiple providers can be registered and each provider can manage one or more autopilot devices.

Note: An Autopilot Provider plugin MUST:

  • Implement all Autopilot API interface methods.
  • Facilitate communication on the target autopilot device to send commands and retrieve both status and configuration information
  • Ensure the engaged path attribute value is maintained to reflect the operational status of the autopilot.
  • Map the engage and disengage operations to an appropriate autopilot device state.
  • Set the state as off-line if the autopilot device is not connected or unreachable.
  • Set the mode as dodge when the autopilot device is is in dodge mode.

Registering as an Autopilot Provider

A provider plugin must register itself with the Autopilot API during start up by calling the registerAutopilotProvider.

The function has the following signature:

app.registerAutopilotProvider(provider: AutopilotProvider, devices: string[])

where:

  • provider: is a valid AutopilotProvider object
  • devices: is an array of identifiers indicating the autopilot devices managed by the plugin.

Example: Plugin registering as an autopilot provider.

import { AutopilotProvider } from '@signalk/server-api' module.exports = function (app) { const plugin = { id: 'mypluginid', name: 'My autopilot Provider plugin' } const autopilotProvider: AutopilotProvider = { getData: (deviceId) => { return ... }, getState: (deviceId) => { return ... }, setState: (state, deviceId) => { ... }, getMode: (deviceId) => { return ... }, setMode: (mode, deviceId) => { ... }, getTarget: (deviceId) => { return ... }, setTarget(value, deviceId) => { ... }, adjustTarget(value, deviceId) => { ... }, engage: (deviceId) => { ... }, disengage: (deviceId) => { ... }, tack:(direction, deviceId) => { ... }, gybe:(direction, deviceId) => { ... }, dodge:(value, deviceId) => { ... } } const pilots = ['pilot1', 'pilot2'] plugin.start = function(options) { ... try { app.registerAutopilotProvider(autopilotProvider, pilots) } catch (error) { // handle error } } return plugin }

Sending Updates and Notifications from Autopilot device

The Autopilot API is responsible for sending both update and notification deltas to Signal K clients.

Data received from an autopilot device, regardless of the communications protocol (NMEA2000, etc), should be sent to the Autopilot API by calling the autopilotUpdate interface method.

This will ensure:

  • Default pilot status is correctly maintained
  • steering.autopilot.* both V1 and V2 deltas are sent

Important! The values provided via autopilotUpdate will be sent in the relevant delta message, so ensure they are in the correct units (e.g. angles in radians, etc).

The function has the following signature:

app.autopilotUpdate(deviceID: string, apInfo: {[key:string]: Value})

where:

  • deviceId: is the autopilot device identifier
  • appInfo: object containing values keyed by attributes (as defined in @signalk/server-api)

Example Update:

app.autopilotUpdate('my-pilot', { target: 1.52789, mode: 'compass' })

Notifications / Alarms are sent using one of the normalised alarm names below as the path and a Notification as the value.

  • waypointAdvance
  • waypointArrival
  • routeComplete
  • xte
  • heading
  • wind

Example Notification:

app.autopilotUpdate('my-pilot', { alarm: { path: 'waypointAdvance', value: { state: 'alert' method: ['sound'] message: 'Waypoint Advance' } } })

Provider Methods:

getData(deviceId): This method returns an AutopilotInfo object containing the current data values and valid options for the supplied autopilot device identifier.

  • deviceId: identifier of the autopilot device to query.

returns: Promise<{AutopilotInfo}>

Note: It is the responsibility of the autopilot provider plugin to map the value of engaged to the current state.

Example:

// API request GET /signalk/v2/api/vessels/self/autopilots/mypilot1 // AutopilotProvider method invocation getData('mypilot1'); // Returns: { options: { states: [ { name: 'auto' // autopilot state name engaged: true // actively steering }, { name: 'standby' // autopilot state name engaged: false // not actively steering } ] modes: ['compass', 'gps', 'wind'] }, target: 0.326 mode: 'compass' state: 'auto' engaged: true }

getState(deviceId): This method returns the current state of the supplied autopilot device identifier. If the autopilot device is not connected or unreachable then off-line should be returned.

  • deviceId: identifier of the autopilot device to query.

returns: Promise<{string}>

Example:

// API request GET /signalk/v2/api/vessels/self/autopilots/mypilot1/state // AutopilotProvider method invocation getState('mypilot1'); // Returns: 'auto'

setState(state, deviceId?): This method sets the autopilot device with the supplied identifier to the supplied state value.

  • state: state value to set. Must be a valid state value.
  • deviceId: identifier of the autopilot device to query.

returns: Promise<{void}>

throws on error or if supplied state value is invalid.

Example:

// API request PUT /signalk/v2/api/vessels/self/autopilots/mypilot1/state {value: "standby"} // AutopilotProvider method invocation setState('standby', 'mypilot1');

getMode(deviceId): This method returns the current mode of the supplied autopilot device identifier.

  • deviceId: identifier of the autopilot device to query.

returns: Promise<{string}>

Example:

// API request GET /signalk/v2/api/vessels/self/autopilots/mypilot1/mode // AutopilotProvider method invocation getMode('mypilot1'); // Returns: 'compass'

setMode(mode, deviceId): This method sets the autopilot device with the supplied identifier to the supplied mode value.

  • mode: mode value to set. Must be a valid mode value.
  • deviceId: identifier of the autopilot device to query.

returns: Promise<{void}>

throws on error or if supplied mode value is invalid.

Example:

// API request PUT /signalk/v2/api/vessels/self/autopilots/mypilot1/mode {value: "gps"} // AutopilotProvider method invocation setMode('gps', 'mypilot1');

setTarget(value, deviceId): This method sets target for the autopilot device with the supplied identifier to the supplied value.

  • value: target value in radians.
  • deviceId: identifier of the autopilot device to query.

returns: Promise<{void}>

throws on error or if supplied target value is outside the valid range.

Example:

// API request PUT /signalk/v2/api/vessels/self/autopilots/mypilot1/target {value: 129} // AutopilotProvider method invocation setTarget(129, 'mypilot1');

adjustTarget(value, deviceId): This method adjusts target for the autopilot device with the supplied identifier by the supplied value.

  • value: value in radians to add to current target value.
  • deviceId: identifier of the autopilot device to query.

returns: Promise<{void}>

throws on error or if supplied target value is outside the valid range.

Example:

// API request PUT /signalk/v2/api/vessels/self/autopilots/mypilot1/target {value: 2} // AutopilotProvider method invocation adjustTarget(2, 'mypilot1');

engage(deviceId): This method sets the state of the autopilot device with the supplied identifier to a state that is actively steering the vessel.

  • deviceId: identifier of the autopilot device to query.

returns: Promise<{void}>

throws on error.

Example:

// API request POST /signalk/v2/api/vessels/self/autopilots/mypilot1/engage // AutopilotProvider method invocation engage('mypilot1');

disengage(deviceId): This method sets the state of the autopilot device with the supplied identifier to a state that is NOT actively steering the vessel.

  • deviceId: identifier of the autopilot device to query.

returns: Promise<{void}>

throws on error.

Example:

// API request POST /signalk/v2/api/vessels/self/autopilots/mypilot1/disengage // AutopilotProvider method invocation disengage('mypilot1');

tack(direction, deviceId): This method instructs the autopilot device with the supplied identifier to perform a tack in the supplied direction.

  • direction: 'port' or 'starboard'
  • deviceId: identifier of the autopilot device to query.

returns: Promise<{void}>

throws on error.

Example:

// API request POST /signalk/v2/api/vessels/self/autopilots/mypilot1/tack/port // AutopilotProvider method invocation tack('port', 'mypilot1');

gybe(direction, deviceId): This method instructs the autopilot device with the supplied identifier to perform a gybe in the supplied direction.

  • direction: 'port' or 'starboard'
  • deviceId: identifier of the autopilot device to query.

returns: Promise<{void}>

throws on error.

Example:

// API request POST /signalk/v2/api/vessels/self/autopilots/mypilot1/gybe/starboard // AutopilotProvider method invocation gybe('starboard', 'mypilot1');

dodge(value, deviceId): This method instructs the autopilot device with the supplied identifier to enter / exit dodge mode and alter the current course by the supplied value (radians) direction.

  • value: +/- value in radians 'port (-ive)' or 'starboard' to change direction. Setting the value to null indicates exit of dodge mode.
  • deviceId: identifier of the autopilot device to query.

returns: Promise<{void}>

throws on error.

To address different pilot behaviour, the dodge function can be used in the following ways:

1. Enter dodge mode at the current course

// API request POST /signalk/v2/api/vessels/self/autopilots/mypilot1/dodge // _AutopilotProvider method invocation dodge(0, 'mypilot1');

2. Enter dodge mode and change course

// API request PUT /signalk/v2/api/vessels/self/autopilots/mypilot1/dodge {"value": 5} // AutopilotProvider method invocation dodge(5, 'mypilot1');

3. Cancel dodge mode

// API request DELETE /signalk/v2/api/vessels/self/autopilots/mypilot1/dodge // AutopilotProvider method invocation dodge(null, 'mypilot1');

Unhandled Operations

A provider plugin MUST implement ALL Autopilot API interface methods, regardless of whether the operation is supported or not.

For an operation that is not supported by the autopilot device, then the plugin should throw an exception.

Example:

{ // unsupported operation method definition gybe: async (d, id) => { throw new Error('Unsupprted operation!) } }