From b5912ff7195f424c3cd5269962d77d40a14da7d8 Mon Sep 17 00:00:00 2001 From: panaaj <38519157+panaaj@users.noreply.github.com> Date: Mon, 25 Nov 2024 15:39:03 +1030 Subject: [PATCH] Dodge operations --- .../plugins/autopilot_provider_plugins.md | 275 +++++++++--------- docs/src/develop/rest-api/autopilot_api.md | 115 +++++--- docs/src/develop/rest-api/open_api.md | 2 +- packages/server-api/src/autopilotapi.ts | 23 +- src/api/autopilot/index.ts | 258 +++++++++------- src/api/autopilot/openApi.json | 90 +++--- src/api/autopilot/openApi.ts | 2 +- src/api/index.ts | 5 + src/interfaces/plugins.ts | 20 +- 9 files changed, 431 insertions(+), 359 deletions(-) diff --git a/docs/src/develop/plugins/autopilot_provider_plugins.md b/docs/src/develop/plugins/autopilot_provider_plugins.md index 0332262e1..8f794ccfa 100644 --- a/docs/src/develop/plugins/autopilot_provider_plugins.md +++ b/docs/src/develop/plugins/autopilot_provider_plugins.md @@ -6,7 +6,7 @@ _This document should be read in conjunction with the [SERVER PLUGINS](./server_ ## Overview -The Signal K Autopilot API defines endpoints under the path `/signalk/v2/api/vessels/self/steering/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](/doc/openapi/?urls.primaryName=autopilot) document. +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](/doc/openapi/?urls.primaryName=autopilot) 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. @@ -27,27 +27,10 @@ An autopilot provider plugin is a Signal K server plugin that implements the **A - 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. -Note: multiple providers can be registered and each provider can manage one or more autopilot devices. +The `AutopilotProvider` interface is defined in _`@signalk/server-api`_ -The `AutopilotProvider` interface is defined as follows in _`@signalk/server-api`_: +Multiple providers can be registered and each provider can manage one or more autopilot devices. -```typescript -interface AutopilotProvider { - getData(deviceId: string): Promise - getState(deviceId: string): Promise - setState(state: string, deviceId: string): Promise - getMode(deviceId: string): Promise - setMode(mode: string, deviceId: string): Promise - getTarget(deviceId: string): Promise - setTarget(value: number, deviceId: string): Promise - adjustTarget(value: number, deviceId: string): Promise - engage(deviceId: string): Promise - disengage(deviceId: string): Promise - tack(direction: TackGybeDirection, deviceId: string): Promise - gybe(direction: TackGybeDirection, deviceId: string): Promise - dodge(direction: TackGybeDirection, deviceId: string): Promise -} -``` **Note: An Autopilot Provider plugin MUST:** - Implement all Autopilot API interface methods. @@ -55,6 +38,7 @@ interface AutopilotProvider { - 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 @@ -69,9 +53,9 @@ app.registerAutopilotProvider(provider: AutopilotProvider, devices: string[]) where: - `provider`: is a valid **AutopilotProvider** object -- `devices`: is an array of identifiers for the autopilot devices managed by the plugin. +- `devices`: is an array of identifiers indicating the autopilot devices managed by the plugin. -_Example: Plugin registering as a routes & waypoints provider._ +_Example: Plugin registering as an autopilot provider._ ```javascript import { AutopilotProvider } from '@signalk/server-api' @@ -83,18 +67,19 @@ module.exports = function (app) { } const autopilotProvider: AutopilotProvider = { - getData: (deviceId: string) => { return ... }, - getState: (deviceId: string) => { return ... }, - setState: (state: string, deviceId: string) => { return true }, - getMode: (deviceId: string) => { return ... }, - setMode: (mode: string, deviceId: string) => { ... }, - getTarget: (deviceId: string) => { return ... }, - setTarget(value: number, deviceId: string) => { ... }, - adjustTarget(value: number, deviceId: string) => { ... }, - engage: (deviceId: string) => { ... }, - disengage: (deviceId: string) => { ... }, - tack:(direction: TackGybeDirection, deviceId: string) => { ... }, - gybe:(direction: TackGybeDirection, deviceId: string) => { ... } + 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'] @@ -113,63 +98,56 @@ module.exports = function (app) { } ``` -### Updates from Autopilot device +### Sending Updates and Notifications from Autopilot device -Updates from an autopilot device are sent to the Autopillot API via the `autopilotUpdate` interface method. +The Autopilot API is responsible for sending both update and notification `deltas` to Signal K clients. -Typically an autopilot provider plugin will call `autopilotUpdate` when receiving data from the autopilot device. +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. -_Note: All updates originating from the autopilot device, regardless of the communications protocol (NMEA2000, etc) should be sent to the Autopilot API using `autopilotUpdate`._ +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: ```typescript -app.autopilotUpdate(deviceID: string, attrib: AutopilotUpdateAttrib, value: Value) +app.autopilotUpdate(deviceID: string, apInfo: {[key:string]: Value}) ``` where: - `deviceId`: is the autopilot device identifier -- `attrib`: is the attribute / path being updated -- `value`: the new value. +- `appInfo`: object containing values keyed by attributes _(as defined in @signalk/server-api)_ -_Example:_ +_Example Update:_ ```javascript -app.autopilotUpdate('my-pilot', 'target', 1.52789) -app.autopilotUpdate('my-pilot', 'mode', 'compass') +app.autopilotUpdate('my-pilot', { + target: 1.52789, + mode: 'compass' +}) ``` -### Alarms from Autopilot device - -Alarms from an autopilot device are sent to the Autopillot API via the `autopilotAlarm` interface method. - -An autopilot provider plugin will call `autopilotAlarm` when the data received data from the autopilot device is an alarm. - -_Note: A set of normalised alarm names are defined and alarm messages from the autopilot device should be mapped to one of the following:_ +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` +- waypointAdvance +- waypointArrival +- routeComplete +- xte +- heading +- wind -The function has the following signature: - -```typescript -app.autopilotAlarm(deviceID: string, alarmName: AutopilotAlarm, value: Notification) -``` -where: - -- `deviceId`: is the autopilot device identifier -- `alarmName`: string containing a normalised alarm name. -- `value`: is a Signal K Notification object. - -_Example:_ +_Example Notification:_ ```javascript -app.autopilotAlarm('my-pilot', 'waypointAdvance', { - state: 'alert' - method: ['sound'] - message: 'Waypoint Advance' +app.autopilotUpdate('my-pilot', { + alarm: { + path: 'waypointAdvance', + value: { + state: 'alert' + method: ['sound'] + message: 'Waypoint Advance' + } + } }) ``` @@ -186,16 +164,14 @@ _Note: It is the responsibility of the autopilot provider plugin to map the valu _Example:_ -``` -GET signalk/v2/api/vessels/self/steering/autopilots/mypilot1 -``` -_AutopilotProvider method invocation:_ ```javascript +// API request +GET /signalk/v2/api/vessels/self/autopilots/mypilot1 + +// AutopilotProvider method invocation getData('mypilot1'); -``` -_Returns:_ -```javascript +// Returns: { options: { states: [ @@ -225,16 +201,14 @@ _Returns:_ returns: `Promise<{string}>` _Example:_ -``` -GET signalk/v2/api/vessels/self/steering/autopilots/mypilot1/state -``` -_AutopilotProvider method invocation:_ ```javascript +// API request +GET /signalk/v2/api/vessels/self/autopilots/mypilot1/state + +// AutopilotProvider method invocation getState('mypilot1'); -``` -_Returns:_ -```javascript +// Returns: 'auto' ``` @@ -244,22 +218,17 @@ _Returns:_ - `state:` state value to set. Must be a valid state value. - `deviceId:` identifier of the autopilot device to query. -returns: `Promise<{boolean}>` indicating the new value of `engaged`. +returns: `Promise<{void}>` throws on error or if supplied state value is invalid. _Example:_ ```javascript -PUT signalk/v2/api/vessels/self/steering/autopilots/mypilot1/state {value: "standby"} -``` -_AutopilotProvider method invocation:_ -```javascript -setState('standby', 'mypilot1'); -``` +// API request +PUT /signalk/v2/api/vessels/self/autopilots/mypilot1/state {value: "standby"} -_Returns:_ -```javascript -false +// AutopilotProvider method invocation +setState('standby', 'mypilot1'); ``` --- @@ -270,16 +239,14 @@ false returns: `Promise<{string}>` _Example:_ -``` -GET signalk/v2/api/vessels/self/steering/autopilots/mypilot1/mode -``` -_AutopilotProvider method invocation:_ ```javascript +// API request +GET /signalk/v2/api/vessels/self/autopilots/mypilot1/mode + +// AutopilotProvider method invocation getMode('mypilot1'); -``` -_Returns:_ -```javascript +// Returns: 'compass' ``` @@ -295,17 +262,17 @@ throws on error or if supplied mode value is invalid. _Example:_ ```javascript -PUT signalk/v2/api/vessels/self/steering/autopilots/mypilot1/mode {value: "gps"} -``` -_AutopilotProvider method invocation:_ -```javascript +// 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. +- `value:` target value in degrees. - `deviceId:` identifier of the autopilot device to query. returns: `Promise<{void}>` @@ -314,17 +281,17 @@ throws on error or if supplied target value is outside the valid range. _Example:_ ```javascript -PUT signalk/v2/api/vessels/self/steering/autopilots/mypilot1/target {value: 0.361} -``` -_AutopilotProvider method invocation:_ -```javascript -setTarget(0.361, 'mypilot1'); +// 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. +- `value:` value in degrees to add to current target value. - `deviceId:` identifier of the autopilot device to query. returns: `Promise<{void}>` @@ -333,11 +300,11 @@ throws on error or if supplied target value is outside the valid range. _Example:_ ```javascript -PUT signalk/v2/api/vessels/self/steering/autopilots/mypilot1/target {value: 0.361} -``` -_AutopilotProvider method invocation:_ -```javascript -adjustTarget(0.0276, 'mypilot1'); +// API request +PUT /signalk/v2/api/vessels/self/autopilots/mypilot1/target {value: 2} + +// AutopilotProvider method invocation +adjustTarget(2, 'mypilot1'); ``` --- @@ -351,10 +318,10 @@ throws on error. _Example:_ ```javascript -POST signalk/v2/api/vessels/self/steering/autopilots/mypilot1/engage -``` -_AutopilotProvider method invocation:_ -```javascript +// API request +POST /signalk/v2/api/vessels/self/autopilots/mypilot1/engage + +// AutopilotProvider method invocation engage('mypilot1'); ``` @@ -369,10 +336,10 @@ throws on error. _Example:_ ```javascript -POST signalk/v2/api/vessels/self/steering/autopilots/mypilot1/disengage -``` -_AutopilotProvider method invocation:_ -```javascript +// API request +POST /signalk/v2/api/vessels/self/autopilots/mypilot1/disengage + +// AutopilotProvider method invocation disengage('mypilot1'); ``` @@ -388,10 +355,10 @@ throws on error. _Example:_ ```javascript -POST signalk/v2/api/vessels/self/steering/autopilots/mypilot1/tack/port -``` -_AutopilotProvider method invocation:_ -```javascript +// API request +POST /signalk/v2/api/vessels/self/autopilots/mypilot1/tack/port + +// AutopilotProvider method invocation tack('port', 'mypilot1'); ``` @@ -407,32 +374,56 @@ throws on error. _Example:_ ```javascript -POST signalk/v2/api/vessels/self/steering/autopilots/mypilot1/gybe/starboard -``` -_AutopilotProvider method invocation:_ -```javascript +// API request +POST /signalk/v2/api/vessels/self/autopilots/mypilot1/gybe/starboard + +// AutopilotProvider method invocation gybe('starboard', 'mypilot1'); ``` --- -**`dodge(direction, deviceId)`**: This method instructs the autopilot device with the supplied identifier to manually override the rudder position by two (2) degrees in the supplied direction. +**`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 (degrees) direction. -- `direction`: 'port' or 'starboard' +- `value`: +/- value indicating the number of degrees 'port (-ive)' or 'starboard' to alter 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. -_Example:_ + +To address different pilot behaviour, the `dodge` function can be used in the following ways: + + + +**1. Enter dodge mode at the current course** ```javascript -POST signalk/v2/api/vessels/self/steering/autopilots/mypilot1/dodge/starboard +// API request +POST /signalk/v2/api/vessels/self/autopilots/mypilot1/dodge + +// _AutopilotProvider method invocation +dodge(0, 'mypilot1'); ``` -_AutopilotProvider method invocation:_ + +**2. Enter dodge mode and change course** ```javascript -dodge('starboard', 'mypilot1'); +// API request +PUT /signalk/v2/api/vessels/self/autopilots/mypilot1/dodge {"value": 5} + +// AutopilotProvider method invocation +dodge(5, 'mypilot1'); ``` +**3. Cancel dodge mode** +```javascript +// API request +DELETE /signalk/v2/api/vessels/self/autopilots/mypilot1/dodge + +// AutopilotProvider method invocation +dodge(null, 'mypilot1'); +``` + +--- ### Unhandled Operations diff --git a/docs/src/develop/rest-api/autopilot_api.md b/docs/src/develop/rest-api/autopilot_api.md index 35a5cfcba..656e35a1d 100644 --- a/docs/src/develop/rest-api/autopilot_api.md +++ b/docs/src/develop/rest-api/autopilot_api.md @@ -3,15 +3,26 @@ ## Overview -The Autopilot API defines the `autopilots` path under the `steering` schema group _(e.g. `/signalk/v2/api/vessels/self/steering/autopilots`)_ for representing information from one or more autopilot devices. +The Autopilot API defines the `autopilots` path under `self` _(e.g. `/signalk/v2/api/vessels/self/autopilots`)_ for representing information from one or more autopilot devices. The Autopilot API provides a mechanism for applications to issue requests to autopilot devices to perform common operations. Additionally, when multiple autopilot devices are present, each autopilot device is individually addressable. _Note: Autopilot provider plugins are required to enable the API operation and provide communication with autopilot devices. See [Autopilot Provider Plugins](../plugins/autopilot_provider_plugins.md) for details._ + +## Common Operations + +The following operations are supported: +- Setting the operating mode +- Engaging / Disengaging the pilot +- Setting / adjusting the course +- Dodging port / starboard +- Tacking / Gybing + + ## The _Default_ Autopilot -To ensure a consistent API calling profile and to simplify client operations, the Autopilot API will assign a _default_ autopilot device which is accessible using the path `./steering/autopilots/_default`. +To ensure a consistent API calling profile and to simplify client operations, the Autopilot API will assign a _default_ autopilot device which is accessible using the path `/signalk/v2/api/vessels/self/autopilots/_default`. - When only one autopilot is present, it will be automatically assigned as the _default_. @@ -23,11 +34,11 @@ To ensure a consistent API calling profile and to simplify client operations, th ### Getting the Default Autopilot Identifier -To get the id of the _default_ autopilot, submit an HTTP `GET` request to `/signalk/v2/api/vessels/self/steering/autopilots/_providers/_default`. +To get the id of the _default_ autopilot, submit an HTTP `GET` request to `/signalk/v2/api/vessels/self/autopilots/_providers/_default`. _Example:_ ```typescript -HTTP GET "/signalk/v2/api/vessels/self/steering/autopilots/_providers/_default" +HTTP GET "/signalk/v2/api/vessels/self/autopilots/_providers/_default" ``` _Response:_ @@ -39,24 +50,24 @@ _Response:_ ### Setting an Autopilot as the Default -To set / change the _default_ autopilot, submit an HTTP `POST` request to `/signalk/v2/api/vessels/self/steering/autopilots/_providers/_default/{id}` where `{id}` is the identifier of the autopilot to use as the _default_. +To set / change the _default_ autopilot, submit an HTTP `POST` request to `/signalk/v2/api/vessels/self/autopilots/_providers/_default/{id}` where `{id}` is the identifier of the autopilot to use as the _default_. _Example:_ ```typescript -HTTP POST "/signalk/v2/api/vessels/self/steering/autopilots/_providers/_default/raymarine-id" +HTTP POST "/signalk/v2/api/vessels/self/autopilots/_providers/_default/raymarine-id" ``` -The autopilot with the supplied id will now be the target of requests made to `./steering/autopilots/_default/*`. +The autopilot with the supplied id will now be the target of requests made to `/signalk/v2/api/vessels/self/autopilots/_default/*`. ## Listing the available Autopilots -To retrieve a list of installed autopilot devices, submit an HTTP `GET` request to `/signalk/v2/api/vessels/self/steering/autopilots`. +To retrieve a list of installed autopilot devices, submit an HTTP `GET` request to `/signalk/v2/api/vessels/self/autopilots`. The response will be an object containing all the registered autopilot devices, keyed by their identifier, detailing the `provider` it is registered by and whether it is assigned as the _default_. ```typescript -HTTP GET "/signalk/v2/api/vessels/self/steering/autopilots" +HTTP GET "/signalk/v2/api/vessels/self/autopilots" ``` _Example: List of registered autopilots showing that `pypilot-id` is assigned as the default._ @@ -146,29 +157,29 @@ If an autopilot device is not connected or unreachable, the provider for that au ## Autopilot Operations All API operations are invoked by issuing requests to: -1. `/signalk/v2/api/vessels/self/steering/autopilots/_default/*` +1. `/signalk/v2/api/vessels/self/autopilots/_default/*` Targets the default autopilot device. OR -2. `/signalk/v2/api/vessels/self/steering/autopilots/{id}/*` +2. `/signalk/v2/api/vessels/self/autopilots/{id}/*` Target the autopilot with the supplied `{id}` _Example:_ ```typescript -HTTP GET "/signalk/v2/api/vessels/self/steering/autopilots/_default/state" +HTTP GET "/signalk/v2/api/vessels/self/autopilots/_default/state" -HTTP GET "/signalk/v2/api/vessels/self/steering/autopilots/pypilot-id/mode" +HTTP GET "/signalk/v2/api/vessels/self/autopilots/pypilot-id/mode" ``` ### Retrieving Autopilot Status -To retrieve the current autopilot configuration as well as a list of available options for `state` and `mode` selections, submit an HTTP `GET` request to `/signalk/v2/api/vessels/self/steering/autopilots/{id}`. +To retrieve the current autopilot configuration as well as a list of available options for `state` and `mode` selections, submit an HTTP `GET` request to `/signalk/v2/api/vessels/self/autopilots/{id}`. ```typescript -HTTP GET "/signalk/v2/api/vessels/self/steering/autopilots/{id}" +HTTP GET "/signalk/v2/api/vessels/self/autopilots/{id}" ``` _Response:_ @@ -195,18 +206,18 @@ Where: ### Setting the Autopilot State -Autopilot state can be set by submitting an HTTP `PUT` request to the `state` endpoint containing a value from the list of available states. +Autopilot state can be set by submitting an HTTP `PUT` request to the `/signalk/v2/api/vessels/self/autopilots/{id}/state` endpoint containing a value from the list of available states. ```typescript -HTTP PUT "/signalk/v2/api/vessels/self/steering/autopilots/{id}/state" {"value": "disabled"} +HTTP PUT "/signalk/v2/api/vessels/self/autopilots/{id}/state" {"value": "disabled"} ``` ### Getting the Autopilot State -The current autopilot state can be retrieved by submitting an HTTP `GET` request to the `state` endpoint. +The current autopilot state can be retrieved by submitting an HTTP `GET` request to the `/signalk/v2/api/vessels/self/autopilots/{id}/state` endpoint. ```typescript -HTTP GET "/signalk/v2/api/vessels/self/steering/autopilots/{id}/state" +HTTP GET "/signalk/v2/api/vessels/self/autopilots/{id}/state" ``` _Response:_ @@ -219,10 +230,10 @@ _Response:_ ### Setting the Autopilot Mode -Autopilot mode can be set by submitting an HTTP `PUT` request to the `mode` endpoint containing a value from the list of available modes. +Autopilot mode can be set by submitting an HTTP `PUT` request to the `/signalk/v2/api/vessels/self/autopilots/{id}/mode` endpoint containing a value from the list of available modes. ```typescript -HTTP PUT "/signalk/v2/api/vessels/self/steering/autopilots/{id}/mode" {"value": "gps"} +HTTP PUT "/signalk/v2/api/vessels/self/autopilots/{id}/mode" {"value": "gps"} ``` ### Getting the Autopilot Mode @@ -230,7 +241,7 @@ HTTP PUT "/signalk/v2/api/vessels/self/steering/autopilots/{id}/mode" {"value": The current autopilot mode can be retrieved by submitting an HTTP `GET` request to the `mode` endpoint. ```typescript -HTTP GET "/signalk/v2/api/vessels/self/steering/autopilots/{id}/mode" +HTTP GET "/signalk/v2/api/vessels/self/autopilots/{id}/mode" ``` _Response:_ @@ -243,26 +254,26 @@ _Response:_ ### Setting the Target value -Autopilot target value can be set by submitting an HTTP `PUT` request to the `target` endpoint containing the desired value in radians. +Autopilot target value can be set by submitting an HTTP `PUT` request to the `/signalk/v2/api/vessels/self/autopilots/{id}/target` endpoint containing the desired value in degrees. _Note: The value supplied should be a number within the valid range for the selected `mode`._ ```typescript -HTTP PUT "signalk/v2/api/vessels/self/steering/autopilots/{id}/target" {"value": 1.1412} +HTTP PUT "signalk/v2/api/vessels/self/autopilots/{id}/target" {"value": 129} ``` -The target value can be adjusted a +/- value by submitting an HTTP `PUT` request to the `target/adjust` endpoint with the value to add to the current `target` value in radians. +The target value can be adjusted a +/- value by submitting an HTTP `PUT` request to the `/signalk/v2/api/vessels/self/autopilots/{id}/target/adjust` endpoint with the value to add to the current `target` value in degrees. ```typescript -HTTP PUT "signalk/v2/api/vessels/self/steering/autopilots/{id}/target/adjust" {"value": -0.1412} +HTTP PUT "signalk/v2/api/vessels/self/autopilots/{id}/target/adjust" {"value": -2} ``` ### Getting the current Target value -The current autopilot target value _(in radians)_ can be retrieved by submitting an HTTP `GET` request to the `target` endpoint. +The current autopilot target value _(in degrees)_ can be retrieved by submitting an HTTP `GET` request to the `target` endpoint. ```typescript -HTTP GET "/signalk/v2/api/vessels/self/steering/autopilots/{id}/target" +HTTP GET "/signalk/v2/api/vessels/self/autopilots/{id}/target" ``` _Response:_ @@ -277,66 +288,76 @@ _Response:_ #### Engaging the autopilot -An autopilot can be engaged by [setting it to a speciifc `state`](#setting-the-state) but it can also be engaged more generically by submitting an HTTP `POST` request to the `engage` endpoint. +An autopilot can be engaged by [setting it to a speciifc `state`](#setting-the-state) but it can also be engaged more generically by submitting an HTTP `POST` request to the `/signalk/v2/api/vessels/self/autopilots/{id}/engage` endpoint. ```typescript -HTTP POST "/signalk/v2/api/vessels/self/steering/autopilots/{id}/engage" +HTTP POST "/signalk/v2/api/vessels/self/autopilots/{id}/engage" ``` _Note: The resultant `state` into which the autopilot is placed will be determined by the **provider plugin** and the autopilot device it is communicating with._ #### Disengaging the autopilot -An autopilot can be disengaged by [setting it to a speciifc `state`](#setting-the-state) but it can also be disengaged more generically by submitting an HTTP `POST` request to the `disengage` endpoint. +An autopilot can be disengaged by [setting it to a speciifc `state`](#setting-the-state) but it can also be disengaged more generically by submitting an HTTP `POST` request to the `/signalk/v2/api/vessels/self/autopilots/{id}/disengage` endpoint. ```typescript -HTTP POST "/signalk/v2/api/vessels/self/steering/autopilots/{id}/disengage" +HTTP POST "/signalk/v2/api/vessels/self/autopilots/{id}/disengage" ``` _Note: The resultant `state` into which the autopilot is placed will be determined by the **provider plugin** and the autopilot device it is communicating with._ ### Perform a Tack -To send a command to the autopilot to perform a tack in the required direction, submit an HTTP `POST` request to `/tack/{direction}` where _direction_ is either `port` or `starboard`. +To send a command to the autopilot to perform a tack in the required direction, submit an HTTP `POST` request to `./autopilots/{id}/tack/{direction}` where _direction_ is either `port` or `starboard`. _Example: Tack to Port_ ```typescript -HTTP POST "/signalk/v2/api/vessels/self/steering/autopilots/{id}/tack/port" +HTTP POST "/signalk/v2/api/vessels/self/autopilots/{id}/tack/port" ``` _Example: Tack to Starboard_ ```typescript -HTTP POST "/signalk/v2/api/vessels/self/steering/autopilots/{id}/tack/starboard" +HTTP POST "/signalk/v2/api/vessels/self/autopilots/{id}/tack/starboard" ``` ### Perform a Gybe -To send a command to the autopilot to perform a gybe in the required direction, submit an HTTP `POST` request to `/gybe/{direction}` where _direction_ is either `port` or `starboard`. +To send a command to the autopilot to perform a gybe in the required direction, submit an HTTP `POST` request to `/signalk/v2/api/vessels/self/autopilots/{id}/gybe/{direction}` where _direction_ is either `port` or `starboard`. _Example: Gybe to Port_ ```typescript -HTTP POST "/signalk/v2/api/vessels/self/steering/autopilots/{id}/gybe/port" +HTTP POST "/signalk/v2/api/vessels/self/autopilots/{id}/gybe/port" ``` _Example: Gybe to Starboard_ ```typescript -HTTP POST "/signalk/v2/api/vessels/self/steering/autopilots/{id}/gybe/starboard" +HTTP POST "/signalk/v2/api/vessels/self/autopilots/{id}/gybe/starboard" ``` -### Dodging / overriding +### Dodging Obstacles -To send a command to the autopilot to manually override the rudder position two (2) degrees in the requested direction in order to avoid an obstacle, -submit an HTTP `POST` request to `/dodge/{direction}` where _direction_ is either `port` or `starboard`. +To address the various methods that the `dodge` function could be invoked on pilot devices, the API provides the following endpoints to provide the widest coverage possible: -_Example: Dodge to Port_ -```typescript -HTTP POST "/signalk/v2/api/vessels/self/steering/autopilots/{id}/dodge/port" + +**To enter dodge mode at the current course** +```javascript +POST /signalk/v2/api/vessels/self/autopilots/{id}/dodge ``` -_Example: Gybe to Starboard_ -```typescript -HTTP POST "/signalk/v2/api/vessels/self/steering/autopilots/{id}/dodge/starboard" +**To enter dodge mode and change course by 5 degrees starboard** +```javascript +PUT /signalk/v2/api/vessels/self/autopilots/{id}/dodge {"value": 5} +``` + +**To enter dodge mode and change course by 5 degrees port** +```javascript +PUT /signalk/v2/api/vessels/self/autopilots/{id}/dodge {"value": -5} +``` + +**To cancel dodge mode** +```javascript +DELETE /signalk/v2/api/vessels/self/autopilots/{id}/dodge ``` \ No newline at end of file diff --git a/docs/src/develop/rest-api/open_api.md b/docs/src/develop/rest-api/open_api.md index 82f5c6f02..661cf6425 100644 --- a/docs/src/develop/rest-api/open_api.md +++ b/docs/src/develop/rest-api/open_api.md @@ -13,6 +13,7 @@ APIs are available via `/signalk/v2/api/` |--- |--- |--- | | [Course](./course_api.md) | Set a course, follow a route, advance to next point, etc. | `vessels/self/navigation/course` | | [Resources](./resources_api.md) | Create, view, update and delete waypoints, routes, etc. | `resources` | +| [`Autopilot`](./autopilot_api.md) | Provide the ability to send common commands to an autopilot via a provider plugin. | `vessels/self/autopilot` | --- @@ -23,7 +24,6 @@ APIs are available via `/signalk/v2/api/` | Proposed API | Description | Endpoint | |--- |--- |--- | | _[`Notifications`](notifications_api.md)_ | Provide the ability to raise, update and clear notifications from multiple sources. _[View PR](https://github.com/SignalK/signalk-server/pull/1560)_| `notifications` | -| _[`Autopilot`](./autopilot_api.md)_ | Provide the ability to send common commands to an autopilot via a provider plugin. _[View PR](https://github.com/SignalK/signalk-server/pull/1596)_ | `vessels/self/steering/autopilot` | | _[`Anchor`](./anchor_api.md)_ | Provide endpoints to perform operations and facilitate an anchor alarm. | `vessels/self/navigation/anchor` | --- diff --git a/packages/server-api/src/autopilotapi.ts b/packages/server-api/src/autopilotapi.ts index cf8c28d8a..cf3823c40 100644 --- a/packages/server-api/src/autopilotapi.ts +++ b/packages/server-api/src/autopilotapi.ts @@ -1,4 +1,4 @@ -import { Notification, Value } from './deltas' +import { Value } from './deltas' export type AutopilotUpdateAttrib = | 'mode' @@ -48,14 +48,7 @@ export interface AutopilotApi { apUpdate( pluginId: string, deviceId: string, - attrib: AutopilotUpdateAttrib, - value: Value - ): void - apAlarm( - pluginId: string, - deviceId: string, - alarmName: AutopilotAlarm, - value: Notification + apInfo: {[path:string]: Value} ): void } @@ -63,7 +56,7 @@ export interface AutopilotApi { export interface AutopilotProvider { getData(deviceId: string): Promise getState(deviceId: string): Promise - setState(state: string, deviceId: string): Promise + setState(state: string, deviceId: string): Promise getMode(deviceId: string): Promise setMode(mode: string, deviceId: string): Promise getTarget(deviceId: string): Promise @@ -73,7 +66,7 @@ export interface AutopilotProvider { disengage(deviceId: string): Promise tack(direction: TackGybeDirection, deviceId: string): Promise gybe(direction: TackGybeDirection, deviceId: string): Promise - dodge(direction: TackGybeDirection, deviceId: string): Promise + dodge(value: number | null, deviceId: string): Promise } export interface AutopilotStateDef { @@ -101,12 +94,6 @@ export interface AutopilotProviderRegistry { ): void autopilotUpdate( deviceId: string, - attrib: AutopilotUpdateAttrib, - value: Value - ): void - autopilotAlarm( - deviceId: string, - alarmName: AutopilotAlarm, - value: Notification + apInfo: {[path:string]: Value} ): void } diff --git a/src/api/autopilot/index.ts b/src/api/autopilot/index.ts index ba4114dfe..24aa5d472 100644 --- a/src/api/autopilot/index.ts +++ b/src/api/autopilot/index.ts @@ -14,16 +14,15 @@ import { SKVersion, Path, Value, - Notification, Delta, isAutopilotProvider, - AutopilotUpdateAttrib, isAutopilotUpdateAttrib, - AutopilotAlarm, - isAutopilotAlarm + isAutopilotAlarm, + PathValue, + SourceRef } from '@signalk/server-api' -const AUTOPILOT_API_PATH = `/signalk/v2/api/vessels/self/steering/autopilots` +const AUTOPILOT_API_PATH = `/signalk/v2/api/vessels/self/autopilots` const DEFAULTIDPATH = '_default' interface AutopilotApplication @@ -35,6 +34,10 @@ interface AutopilotList { [id: string]: { provider: string; isDefault: boolean } } +interface AutopilotApiSettings { + maxTurn: number // maximum course adjust / steer angle value (degrees) +} + export class AutopilotApi { private autopilotProviders: Map = new Map() @@ -42,6 +45,10 @@ export class AutopilotApi { private defaultDeviceId?: string private deviceToProvider: Map = new Map() + private settings: AutopilotApiSettings = { + maxTurn: 20 + } + constructor(private server: AutopilotApplication) {} async start() { @@ -53,7 +60,7 @@ export class AutopilotApi { // Register plugin as provider. register(pluginId: string, provider: AutopilotProvider, devices: string[]) { - debug(`** Registering provider(s)....${pluginId} ${provider}`) + debug(`** Registering provider(s)....${pluginId}`) if (!provider) { throw new Error(`Error registering provider ${pluginId}!`) @@ -109,7 +116,16 @@ export class AutopilotApi { debug(`** Resetting defaults .....`) this.defaultDeviceId = undefined this.defaultProviderId = undefined - this.emitDeltaMsg('defaultPilot', this.defaultDeviceId, 'autopilotApi') + this.initDefaults() + /*this.emitUpdates( + [ + this.buildPathValue( + 'defaultPilot' as Path, + this.defaultDeviceId ?? null + ) + ], + 'autopilotApi' as SourceRef + )*/ } debug( @@ -120,54 +136,49 @@ export class AutopilotApi { ) } - // Pass changed attribute / value from autopilot. + /** Emit updates from autopilot device as `steering.autopilot.*` deltas. + * This should be used by provider plugins to: + * - Ensure API state is consistant + * - trigger the sending of deltas. + */ apUpdate( pluginId: string, - deviceId: string = pluginId + '.default', - attrib: AutopilotUpdateAttrib, - value: Value + deviceId: SourceRef = pluginId as SourceRef, + apInfo: { [path: string]: Value } ) { - if (deviceId && !this.deviceToProvider.has(deviceId)) { - this.deviceToProvider.set(deviceId, pluginId) - } - if (isAutopilotUpdateAttrib(attrib)) { - try { - if (!this.defaultDeviceId) { - this.initDefaults(deviceId) - } - this.emitDeltaMsg(attrib, value, deviceId) - } catch (err) { - debug(`ERROR apUpdate(): ${pluginId}->${deviceId}`, err) + try { + if (deviceId && !this.deviceToProvider.has(deviceId)) { + this.deviceToProvider.set(deviceId, pluginId) } - } else { - debug( - `ERROR apUpdate(): ${pluginId}->${deviceId}`, - `${attrib} is NOT an AutopilotUpdateAttrib!` - ) + if (!this.defaultDeviceId) { + this.initDefaults(deviceId) + } + } catch (err) { + debug(`ERROR apUpdate(): ${pluginId}->${deviceId}`, err) + return } - } - // Pass alarm / notification from autopilot. - apAlarm( - pluginId: string, - deviceId: string = pluginId + '.default', - alarmName: AutopilotAlarm, - value: Notification - ) { - if (isAutopilotAlarm(alarmName)) { - debug(`Alarm -> ${deviceId}:`, value) - this.server.handleMessage(deviceId, { - updates: [ - { - values: [ - { - path: `notifications.steering.autopilot.${alarmName}` as Path, - value: value - } - ] + const values: any[] = [] + Object.keys(apInfo).forEach((attrib: string) => { + if (isAutopilotUpdateAttrib(attrib) && attrib !== 'options') { + if (attrib === 'alarm') { + const alarm: PathValue = apInfo[attrib] as PathValue + if (isAutopilotAlarm(alarm.path)) { + values.push({ + path: `notifications.steering.autopilot.${alarm.path}` as Path, + value: alarm.value + }) } - ] - }) + } else { + values.push({ + path: `steering.autopilot.${attrib}`, + value: apInfo[attrib] + }) + } + } + }) + if (values.length !== 0) { + this.emitUpdates(values, deviceId) } } @@ -178,7 +189,7 @@ export class AutopilotApi { request, 'vessels.self', null, - 'steering.autopilot' + 'autopilot' ) } @@ -345,16 +356,15 @@ export class AutopilotApi { } this.useProvider(req) .setState(req.body.value, req.params.id) - .then((r: boolean) => { - debug('engaged =', r) - this.emitDeltaMsg('engaged', r, req.params.id) - if (req.params.id === this.defaultDeviceId) { - this.emitDeltaMsg('engaged', r, DEFAULTIDPATH) - } + .then(() => { res.status(Responses.ok.statusCode).json(Responses.ok) }) - .catch(() => { - res.status(Responses.invalid.statusCode).json(Responses.invalid) + .catch((err) => { + res.status(err.statusCode ?? 500).json({ + state: err.state ?? 'FAILED', + statusCode: err.statusCode ?? 500, + message: err.message ?? 'No autopilots available!' + }) }) } ) @@ -391,8 +401,12 @@ export class AutopilotApi { .then(() => { res.status(Responses.ok.statusCode).json(Responses.ok) }) - .catch(() => { - res.status(Responses.invalid.statusCode).json(Responses.invalid) + .catch((err) => { + res.status(err.statusCode ?? 500).json({ + state: err.state ?? 'FAILED', + statusCode: err.statusCode ?? 500, + message: err.message ?? 'No autopilots available!' + }) }) } ) @@ -424,21 +438,22 @@ export class AutopilotApi { res.status(Responses.invalid.statusCode).json(Responses.invalid) return } - if (req.body.value < 0 - Math.PI || req.body.value > 2 * Math.PI) { - res.status(400).json({ - state: 'FAILED', - statusCode: 400, - message: `Error: Value supplied is outside of the valid range (-PI < value < 2*PI radians).` - }) - return - } + const v = + req.body.value < -180 + ? Math.max(...[-180, req.body.value]) + : Math.min(...[360, req.body.value]) + this.useProvider(req) - .setTarget(req.body.value, req.params.id) + .setTarget(v, req.params.id) .then(() => { res.status(Responses.ok.statusCode).json(Responses.ok) }) - .catch(() => { - res.status(Responses.invalid.statusCode).json(Responses.invalid) + .catch((err) => { + res.status(err.statusCode ?? 500).json({ + state: err.state ?? 'FAILED', + statusCode: err.statusCode ?? 500, + message: err.message ?? 'No autopilots available!' + }) }) } ) @@ -451,13 +466,23 @@ export class AutopilotApi { res.status(Responses.invalid.statusCode).json(Responses.invalid) return } + + const v = + req.body.value < 0 + ? Math.max(...[0 - this.settings.maxTurn, req.body.value]) + : Math.min(...[this.settings.maxTurn, req.body.value]) + this.useProvider(req) - .adjustTarget(req.body.value, req.params.id) + .adjustTarget(v, req.params.id) .then(() => { res.status(Responses.ok.statusCode).json(Responses.ok) }) - .catch(() => { - res.status(Responses.invalid.statusCode).json(Responses.invalid) + .catch((err) => { + res.status(err.statusCode ?? 500).json({ + state: err.state ?? 'FAILED', + statusCode: err.statusCode ?? 500, + message: err.message ?? 'No autopilots available!' + }) }) } ) @@ -538,12 +563,12 @@ export class AutopilotApi { } ) - // dodge to port + // dodge mode ON this.server.post( - `${AUTOPILOT_API_PATH}/:id/dodge/port`, + `${AUTOPILOT_API_PATH}/:id/dodge`, (req: Request, res: Response) => { this.useProvider(req) - .dodge('port', req.params.id) + .dodge(0, req.params.id) .then(() => { res.status(Responses.ok.statusCode).json(Responses.ok) }) @@ -557,12 +582,41 @@ export class AutopilotApi { } ) - // dodge to starboard - this.server.post( - `${AUTOPILOT_API_PATH}/:id/dodge/starboard`, + // dodge mode OFF + this.server.delete( + `${AUTOPILOT_API_PATH}/:id/dodge`, + (req: Request, res: Response) => { + this.useProvider(req) + .dodge(null, req.params.id) + .then(() => { + res.status(Responses.ok.statusCode).json(Responses.ok) + }) + .catch((err) => { + res.status(err.statusCode ?? 500).json({ + state: err.state ?? 'FAILED', + statusCode: err.statusCode ?? 500, + message: err.message ?? 'No autopilots available!' + }) + }) + } + ) + + /** dodge port (-ive) / starboard (+ive) degrees */ + this.server.put( + `${AUTOPILOT_API_PATH}/:id/dodge`, (req: Request, res: Response) => { + if (typeof req.body.value !== 'number') { + res.status(Responses.invalid.statusCode).json(Responses.invalid) + return + } + + const v = + req.body.value < 0 + ? Math.max(...[0 - this.settings.maxTurn, req.body.value]) + : Math.min(...[this.settings.maxTurn, req.body.value]) + this.useProvider(req) - .dodge('starboard', req.params.id) + .dodge(v, req.params.id) .then(() => { res.status(Responses.ok.statusCode).json(Responses.ok) }) @@ -650,41 +704,45 @@ export class AutopilotApi { this.defaultProviderId = this.deviceToProvider.get( this.defaultDeviceId ) as string - this.emitDeltaMsg('defaultPilot', this.defaultDeviceId, 'autopilotApi') - debug(`Default Device = ${this.defaultDeviceId}`) - debug(`Default Provider = ${this.defaultProviderId}`) - return } - // else set to first AP device registered - if (this.deviceToProvider.size !== 0) { + else if (this.deviceToProvider.size !== 0) { const k = this.deviceToProvider.keys() this.defaultDeviceId = k.next().value as string this.defaultProviderId = this.deviceToProvider.get( this.defaultDeviceId ) as string - this.emitDeltaMsg('defaultPilot', this.defaultDeviceId, 'autopilotApi') - debug(`Default Device = ${this.defaultDeviceId}`) - debug(`Default Provider = ${this.defaultProviderId}`) - return } else { - throw new Error( - 'Cannot set defaultDevice....No autopilot devices registered!' - ) + this.defaultDeviceId = undefined + this.defaultProviderId = undefined + } + this.emitUpdates( + [ + this.buildPathValue( + 'defaultPilot' as Path, + this.defaultDeviceId ?? null + ) + ], + 'autopilotApi' as SourceRef + ) + debug(`Default Device = ${this.defaultDeviceId}`) + debug(`Default Provider = ${this.defaultProviderId}`) + } + + // build autopilot delta PathValue + private buildPathValue(path: Path, value: Value): PathValue { + return { + path: `steering.autopilot${path ? '.' + path : ''}` as Path, + value: value } } // emit delta updates on operation success - private emitDeltaMsg(path: string, value: any, source: string) { + private emitUpdates(values: PathValue[], source: SourceRef) { const msg: Delta = { updates: [ { - values: [ - { - path: `steering.autopilot${path ? '.' + path : ''}` as Path, - value: value - } - ] + values: values } ] } diff --git a/src/api/autopilot/openApi.json b/src/api/autopilot/openApi.json index d871c7d88..01925f337 100644 --- a/src/api/autopilot/openApi.json +++ b/src/api/autopilot/openApi.json @@ -15,7 +15,7 @@ }, "servers": [ { - "url": "/signalk/v2/api/vessels/self/steering/autopilots" + "url": "/signalk/v2/api/vessels/self/autopilots" } ], "tags": [ @@ -268,9 +268,9 @@ "example": "compass" }, "target": { - "description": "Current target value (radians)", + "description": "Current target value (degrees)", "type": "number", - "example": 1.25643 + "example": 75.2 }, "options": { "$ref": "#/components/schemas/autopilotOptions" @@ -492,8 +492,8 @@ ], "get": { "tags": ["autopilot"], - "summary": "Retrieve the current target value (radians).", - "description": "Value in radians of the current target value.", + "summary": "Retrieve the current target value (degrees).", + "description": "Value in degrees of the current target value.", "responses": { "default": { "description": "Autopilot value response", @@ -505,10 +505,8 @@ "properties": { "value": { "type": "number", - "description": "Value in radians", - "min": -3.141592653589793, - "max": 6.283185307179586, - "example": -1.23789 + "description": "Value in degrees", + "example": 129 } } } @@ -522,10 +520,10 @@ }, "put": { "tags": ["autopilot"], - "summary": "Set autopilot `target` value (radians).", - "description": "Value supplied must be in the valid range between -PI & 2*PI.", + "summary": "Set autopilot `target` value (degrees).", + "description": "Value supplied must be in the valid range between -180 & 360.", "requestBody": { - "description": "Value in radians within the bounds of the current autopilot mode. (i.e. compass: 0 to 2*Pi, wind angle: -Pi to Pi)", + "description": "Value in degrees within the bounds of the current autopilot mode. (i.e. compass: 0 to 360, wind angle: -180 to 180)", "required": true, "content": { "application/json": { @@ -534,10 +532,10 @@ "properties": { "value": { "type": "number", - "description": "Value in radians", - "min": -3.141592653589793, - "max": 6.283185307179586, - "example": -1.23789 + "description": "Value in degrees", + "min": -180, + "max": 360, + "example": 129 } } } @@ -562,10 +560,10 @@ ], "put": { "tags": ["autopilot"], - "summary": "Adjust autopilot target value by +/- radians.", + "summary": "Adjust autopilot target value by +/- degrees.", "description": "Value supplied will be added to the current target value. The result must be in the valid range between -PI & 2*PI.", "requestBody": { - "description": "A value in radians to add to the current `target` value.", + "description": "A value in degrees to add to the current `target` value.", "required": true, "content": { "application/json": { @@ -574,10 +572,8 @@ "properties": { "value": { "type": "number", - "description": "Value in radians.", - "min": -0.1745, - "max": 0.1745, - "example": -0.23789 + "description": "Value in degrees (-ive = port).", + "example": -2 } } } @@ -674,7 +670,7 @@ } } }, - "/{id}/dodge/port": { + "/{id}/dodge": { "parameters": [ { "$ref": "#/components/parameters/AutopilotIdParam" @@ -682,8 +678,8 @@ ], "post": { "tags": ["autopilot"], - "summary": "Turn to port.", - "description": "Manual override turn to port.", + "summary": "Turn on dodge mode.", + "description": "Enter dodge mode at the current course setting.", "responses": { "200ActionResponse": { "$ref": "#/components/responses/200ActionResponse" @@ -692,18 +688,42 @@ "$ref": "#/components/responses/ErrorResponse" } } - } - }, - "/{id}/dodge/starboard": { - "parameters": [ - { - "$ref": "#/components/parameters/AutopilotIdParam" + }, + "delete": { + "tags": ["autopilot"], + "summary": "Turn Off dodge mode.", + "description": "Resume steering original course.", + "responses": { + "200ActionResponse": { + "$ref": "#/components/responses/200ActionResponse" + }, + "default": { + "$ref": "#/components/responses/ErrorResponse" + } } - ], - "post": { + }, + "put": { "tags": ["autopilot"], - "summary": "Turn to starboard.", - "description": "Manual override turn to starboard.", + "summary": "Steer port / starboard to dodge obstacles.", + "description": "Override the current course to change direction the supplied number of degrees.", + "requestBody": { + "description": "+/- value in degrees to turn (-ive = port).", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "number", + "description": "Value in degrees.", + "example": -2 + } + } + } + } + } + }, "responses": { "200ActionResponse": { "$ref": "#/components/responses/200ActionResponse" diff --git a/src/api/autopilot/openApi.ts b/src/api/autopilot/openApi.ts index e8425c96d..be4532ad4 100644 --- a/src/api/autopilot/openApi.ts +++ b/src/api/autopilot/openApi.ts @@ -3,6 +3,6 @@ import autopilotApiDoc from './openApi.json' export const autopilotApiRecord = { name: 'autopilot', - path: '/signalk/v2/api/vessels/self/steering/autopilot', + path: '/signalk/v2/api/vessels/self/autopilot', apiDoc: autopilotApiDoc as unknown as OpenApiDescription } diff --git a/src/api/index.ts b/src/api/index.ts index c629ccb39..a68515464 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -36,6 +36,11 @@ export const Responses = { state: 'FAILED', statusCode: 404, message: 'Resource not found.' + }, + notImplemented: { + state: 'FAILED', + statusCode: 500, + message: 'Not implemented.' } } diff --git a/src/interfaces/plugins.ts b/src/interfaces/plugins.ts index 7ea8f06e3..e15531505 100644 --- a/src/interfaces/plugins.ts +++ b/src/interfaces/plugins.ts @@ -24,11 +24,9 @@ import { AutopilotProvider, ServerAPI, RouteDestination, - AutopilotUpdateAttrib, - AutopilotAlarm, Value, - Notification, - SignalKApiId + SignalKApiId, + SourceRef } from '@signalk/server-api' // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore @@ -576,18 +574,10 @@ module.exports = (theApp: any) => { autopilotApi.register(plugin.id, provider, devices) } appCopy.autopilotUpdate = ( - deviceId: string, - attrib: AutopilotUpdateAttrib, - value: Value + deviceId: SourceRef, + apInfo: { [k: string]: Value } ) => { - autopilotApi.apUpdate(plugin.id, deviceId, attrib, value) - } - appCopy.autopilotAlarm = ( - deviceId: string, - alarmName: AutopilotAlarm, - value: Notification - ) => { - autopilotApi.apAlarm(plugin.id, deviceId, alarmName, value) + autopilotApi.apUpdate(plugin.id, deviceId, apInfo) } _.omit(appCopy, 'apiList') // don't expose the actual apiList