## Introduction

Signal K Server is software designed to be deployed on a vessel to act as a central hub which:

1. Collects data from devices and sensors on board
2. Aggregates and exposes it using the Signal K Data Standard
3. Exposes the collected data via REST APIs and websocket protocols over a standard WiFi, LAN or Internet connection.

Through implementation of the Signal K Data Standard, it enables data exchange between NMEA0183, NMEA2000 and other marine protocols facilitating two way communication between the various onboard systems. In addition it can also act as data hub for additional sensors ensuring their data appears within the single data model. (Visit the Signal K SensESP project for ESP32 for details.).

Data is made available to client applications / connections in JSON format making it widely accessible to Apps on phone / tablet devices and web applications.

Signal K Server is also extensible, providing a plugin framework which allows developers to create solutions that integrate and extend its capabilities. These solutions can be published to npmjs and installed via the App Store in the server's web-based user interface.

# Getting Started

Signal K Server is a NodeJS application which can be installed on a variety of devices and operating systems.

It is available for installation via:

1. NPM package
2. Docker image
3. GitHub repository

See the relevant section below for instructions based on your target system.

### Prerequisites:

Signal K server requires NodeJs version >= 18 be installed on the target system prior to commencing installation.

## Raspberry Pi Installation

Install Signal K Server on Raspberry Pi outlines the process for getting Signal K Server up and running (including supporting services) on Raspberry Pi OS.

## Using Docker

Signal K Server is available as a Docker image on Docker Hub and cr.signalk.io/signalk/signalk-server.

To simply run a Signal K Server with some sample data on a device with docker installed, enter the following into a terminal:

    docker run -it --rm --publish 3000:3000 signalk/signalk-server

This will start an instance of Signal K Server on port 3000 which you can then access via the web based Admin UI by pointing your web browser at `http://localhost:3000`.

If you are wanting to use docker to deploy Signal K Server on your vessel you will need to:

1. Specify a location to persist the server's configuration so it is not lost between restarts
2. Run the instance as a background process

Example: Run as background process and store server configuration in the current folder:

    docker run -d --init --name signalk-server -p 3000:3000 -v $(pwd):/home/node/.signalk signalk/signalk-server

You are ready to now configure your installation and connect data from devices on your boat.

## Installation via NPM

Signal K Server can be installed directly using NPM.

Windows:

- See Installing on Windows below.

Linux / macOS:

    sudo npm install -g signalk-server

Once installation is complete, enter the following in a terminal window, to generate a settings file and configure the server to start automatically:

    sudo signalk-server-setup

If you choose not to use `signalk-server-setup` you can start the server by entering the following in a terminal window:

    signalk-server

## Installing on Windows

Please use the Signal K installer for Windows to install Signal K Server on a Windows device.

## Install using Git

Installation from the GitHub repository is useful when developing plugins and components.

To do this enter the following commands in a terminal window:

    # Copy the files to your device
    git clone https://github.com/SignalK/signalk-server.git

    # change to the folder containing the downloaded files
    cd signalk-server

    # install the dependencies
    npm install

    # build all packages in the repository
    npm run build:all

To start Signal K Server with a sample configuration file and some sample data, enter the following into a terminal: To use NMEA0183 sample data:

    bin/nmea-from-file

To use NMEA2000 sample data:

    bin/n2k-from-file

The server will start playing back data from the specified sample file that can be viewed using the Data Browser in the Admin UI (`http://localhost:3000`) or via REST API / websocket connection.

# Installation on Raspberry Pi

Installation of Signal K server can consists of the following steps:

1. Install the tools and libraries required to run the Signal K server (the dependencies)
2. Install a Signal K Server to process the Signal K data
3. Run the Setup script.

Important: If you are updating a Signal K server installation, especially if upgrading an installed version <= 1.40.0, please check here first.

### Prerequisites:

Raspberry Pi OS is installed on the device.

For instructions on how to install the operating system can be found here..

Note: It is also possible to perform a "headless install" using `Raspberry Pi OS Lite` since the GUI for Signal K is browser based.

Once the OS installation has been completed, you are ready to commence.

## Install the Dependencies

1. Log in to the RPi Desktop and open a terminal.

2. Update the list of install packages.

       sudo apt update

3. Install NodeJS 18 and npm.

   Follow instructions for Ubuntu and Debian based distributions like Raspberry Pi OS at NodeSource Distributions.

4. Ensure that we're using the latest version of npm.

       sudo npm install -g npm@latest

   Use the following command to check the versions of NodeJS and npm installed.

       node -v && npm -v

   Ensure the reported versions are equal to or greater than `v18.15.0, 9.5.0` respectively.

5. Install a Bonjour (mDNS) service for Linux called Avahi, which allows Apps and other network devices to Discover the Signal K server.

       sudo apt install libnss-mdns avahi-utils libavahi-compat-libdnssd-dev

## Install Signal K Server

    sudo npm install -g signalk-server

You can test that installation was successful by starting the server using some sample data.

    signalk-server --sample-nmea0183-data

You should see the terminal output "signalk-server running at 0.0.0.0:3000" as shown below...

    signalk-server --sample-nmea0183-data
    Using sample data from /usr/lib/node_modules/signalk-server/samples/plaka.log
    signalk-server running at 0.0.0.0:3000

The Signal K Node Server is now reading and publishing sample NMEA0183 data from the specified file.

Using a Web browser enter the following URL: `http://127.0.0.1:3000/signalk` which should display the following information indicating the server is up and running.

    {
        "endpoints":{
            "v1":{
                "version":"2.0.0",
                "signalk-http":"http://127.0.0.1:3000/signalk/v1/api/",
                "signalk-ws":"ws://127.0.0.1:3000/signalk/v1/stream",
                "signalk-tcp":"tcp://127.0.0.1:3858"
            }
        },
        "server":{
            "id":"signalk-server-node",
            "version":"2.0.0"
        }
    }

## Run the Setup Script

Now that you have Signal K server installed, you will want to generate a settings file for your vessel and configure your RPi to start the server automatically. To do this run the setup script by entering the following command and follow the prompts.

    sudo signalk-server-setup

You can re-run this command at any time in the future to change the settings.

Note: The setup script will enable security which will require you to `Login`` from the Admin UI. Clicking` Login` for the first time will prompt you to create a user and password.

Signal K server will now be started automatically when your RPi boots up.

If you want to temporarily stop the Signal K server, you can do so by entering the following commands:

    sudo systemctl stop signalk.service
    sudo systemctl stop signalk.socket

To start Signal K server again enter the following commands:

    sudo systemctl start signalk.service
    sudo systemctl start signalk.socket

To stop Signal K server from starting automatically enter the following commands:

    sudo systemctl disable signalk.service
    sudo systemctl disable signalk.socket

You are ready to now configure your installation and connect data from devices on your boat.

# Updating your Installation

Signal K Server is frequently updated to introduce new features and fix issues that have been reported. Sometime these updates require that NodeJS or other supporting software on your device to be upgraded to support the new functionality.

Additionally your device's operating system are constantly evolving to address security issues as well as providing new capabilities.

Regularly updating your installation will reduce both the volume of data download and the time taken to complete the process. Connecting your device to a network with good broadband speed before performing an update is recommended.

Updates fall into four categories:

1. Device Operating system (e.g. RaspberryPi OS)
2. NodeJS / NPM
3. Signal K Server
4. Signal K WebApps and Plugins

## Update Device Operating System

Instructions will vary depending on your device but for linux based systems such as the Raspberry Pi the following instrctions are used to update the OS.

From a terminal window enter the following commands:

    sudo apt update

    sudo apt dist-upgrade

If you have not performed an update for a while these commands may take a while to complete, just be patient and make sure everything completes correctly.

After the process has completed `restart` your device.

## Update NodeJS and NPM

To ensure the version of NodeJS on your device is supported by Signal K Server (see prerequisites), check the installed version by entering the following in a terminal window:

    node -v

    # example response
    v18.17.0

If the version of NodeJS displayed is lower than the version supported by Signal K Server then you can update it with the following command:

    sudo apt upgrade nodejs

It is also recommended to update the version of the Node Package Manager (NPM).

    sudo npm install -g npm@latest

## Update Signal K Server

When an update is available for Signal K Server a visual indication is displayed in the Admin UI.

Important! Before updating please ensure the version of NodeJS on your device is supported by Signal K Server.

If you are updating from Signal K Server version v1.40.0 or earlier please read this first before proceeding.

Click on Server -> Update to display information about the new version.

Click Update to start the installation.

After the installation is complete, click Restart to launch the updated Signal K Server.

### WebApps and Plugins

After updating Signal K Server some plugins and WebApps may also need to be updated.

The AppStore is where WebApps and Plugins can be installed, removed or updated. Those with an update available will be listed in Appstore -> Updates in the Admin UI.

Clicking on the download cloud button next to the WebApp / Plugin you wish to update.

After all installations have been completed, click Restart to activate the updated WebApps and Plugins.

# Runtime Environment & Options

Signal K Server provides the following command line options and environment variables to configure your implementation.

## Command line options

Option | Description
--- | ---
`-s` | Override path to the settings file. (same as `SIGNALK_NODE_SETTINGS` environment variable)
`-c` | Override the path to find server configuration. (same as `SIGNALK_NODE_CONFIG_DIR` environment variable)
`--sample-nmea0183-data` | Starts signalk-server with sample NMEA0183 data.
`--sample-n2k-data` | Starts signalk-server with sample NMEA2000 data.
`--override-timestamps` | Override timestamps in the sample NMEA2000 data with current date and time. Doesn't apply nor makes a difference to NMEA0183 sample data.
`--securityenabled` | Enable security. For a fresh install this makes the Admin UI force the user to create an admin account before he/she can continue further into the UI. See Security for further details.

## Environment variables

Variable | Description
--- | ---
`PORT` | Override the port for http/ws service (default is 3000).
`SSLPORT` | Override the port for https/wss service. If defined forces ssl as default protocol (default port is 3443).
`PROTOCOL` | Override http/https where the server is accessed via https but the server sees http (e.g. when Heroku handles https termination)
`EXTERNALPORT` | The port used in /signalk response and Bonjour advertisement. Has precedence over configuration file.
`EXTERNALHOST` | The host used in /signalk response and Bonjour advertisement. Has precedence over configuration file.
`FILEUPLOADSIZELIMIT` | Override the file upload size limit (default is '10mb').
`NMEA0183PORT` | Override the port for the NMEA 0183 over tcp service (default is 10110).
`TCPSTREAMPORT` | Override the port for the Signal K Streaming (deltas) over TCP.
`TCPSTREAMADDRESS` | Override the address the Signal K Stream (deltas) over TCP is listening on.
`DISABLEPLUGINS` | Disable all plugins so that they can not be enabled (default is false).
`DEFAULTENABLEDPLUGINS` | A comma separated list of plugin ids that are overridden to be enabled by default if no setttings exist. Lower preference than `DISABLEPLUGINS`.
`PLUGINS_WITH_UPDATE_DISABLED` | A comma separated list of plugin that will not be updated.
`SECURITYSTRATEGY` | Override the security strategy module name.
`WSCOMPRESSION` | Compress websocket messages (default is false).
`MAXSENDBUFFERSIZE` | The maximum number of bytes allowed in the server's send buffer of a WebSocket connection. The connection will be terminated if this is exceeded for MAXSENDBUFFERCHECKTIME milliseconds. Guards against slow or dysfunctional clients that can not cope with the message volume (default is 512 * 1024 bytes).
`MAXSENDBUFFERCHECKTIME` | The maximum number of bytes allowed in the server's send buffer of a WebSocket connection. The connection will be terminated if this is exceeded. Guards against slow or dysfunctional clients that can not cope with the message volume (default is 512 * 1024 bytes).
`SIGNALK_SERVER_IS_UPDATABLE` | Allows the server to be updated through the GUI even if it is not installed in the standard paths (default is false). If set to true, the server must have been installed with `npm install -g signalk-server`.
`SIGNALK_DISABLE_SERVER_UPDATES` | Disables server updates in the GUI (default is false).
`DEBUG` | A comma-separated list of tags for debugging the specified module (e.g signalk-server*,signalk-provider-tcp). Can now be defined directly in the graphical interface. More help on how to use the debug here: `https://www.npmjs.com/package/debug#wildcards`
`IS_IN_DOCKER` | Used to tell the server it is in Docker and not normally updateable (default is false).
`NPMREGISTRYTIMEOUT` | How long to wait for the registry when retrieving the App Store listing (default is 20s).
`SECRETKEY` | A secret string used to generate an authentication token (the internal default autogenerated is a string of 512 hex chars like 'ef8307a4c7a4bd7...309d947bca3')
`ALLOW_DEVICE_ACCESS_REQUESTS` | Used when a device needs to gain access to a secured Signal K server (default is true) (https://signalk.org/specification/1.4.0/doc/access_requests.html).
`ALLOW_NEW_USER_REGISTRATION` | (default is true).
`ADMINUSER` | Force an account for admin user (username:password format).
`PRESERIALCOMMAND` | Command to run before opening a serial port.
`SIGNALK_NODE_SETTINGS` | Override the path to the settings file.
`SIGNALK_NODE_CONFIG_DIR` | Override the path to find server configuration. Includes all run-time changing content: configuration files, plugins, plugin configuration files, webapps, and so forth.

# Security

## Introduction

The umbrella term Security in Signal K server refers to the difference between running a server, that any one connected to the network can access and alter at will (unsecured) , and one with restrictions in place (secured).

The available security options relate to:

- authentication: Users and / or connecting devices having to provide a credential to gain access to the server (e.g. username & password, access token, etc.).
- access control: Based on the authentication, access is granted to only specific Signal K data and server configuration.
- communications: Network traffic is encrypted and the identity of the server verified to protect against eavesdropping.
- network services: Control which of the server's services/interfaces are configured and active (e.g. does it allow unsecured read/write over the network).

## Enabling Security

When Signal K Server does not have security enabled, the `Login` option at the top right corner of the Admin UI will not be available.

Security can be enabled in several ways:

1. Using the Admin UI, select Security -> Users and then:

   - Click Add
   - Enter a user id
   - Enter a password and confirm it
   - In Permissions select Admin
   - Click Apply.
   - Restart the Signal K Server.

2. Starting the server with the `--securityenabled` command line option

3. Adding the following section in the settings file

    "security": {
        "strategy": "./tokensecurity",
      }

When security is enabled, the next time you access the Admin UI it will prompt you to create an administrator account.

Security configuration is stored in file called `security.json` which will be located in the server configuration directory.

## Disabling Security / Lost Admin Credentials

In case the administrator user credentials are lost, removing the `security.json` file and restarting the server will restore access to the Admin UI.

## Access Control

Access control lists (acls) allow for fine grained access to specific data in Signal K. They specify the permissions assigned to users for resources within specifc contexts and are defined within the `security.json` file.

The following example defines acls for the self context allowing:

1. Anyone to read the paths `"steering.*"`, `"navigation.*"`, `"name"`, `"design.aisShipType"` and grants the admin user permission to write (update) those paths.

2. The user john to read any data coming from the `actisense.35` $source.

3. For all other paths, only the admin user to read and no one can write.

      "acls": [
        {
          "context": "vessels.self",
          "resources": [
            {
              "paths": ["steering.*", "navigation.*", "name", "design.aisShipType"],
              "permissions": [
                {
                  "subject": "any",
                  "permission": "read"
                },
                {
                  "subject": "admin",
                  "permission": "write"
                }
              ]
            },
            {
              "sources": [ "actisense.35" ],
              "permissions": [
                {
                  "subject": "john",
                  "permission": "read"
                }
              ]
            },
            {
              "paths": ["*"],
              "permissions": [
                {
                  "subject": "admin",
                  "permission": "read"
                }
              ]
            }
          ]
        }
      ]

Note: If there is no match is found for a specific path in the acl list, then permission will be denied to that path!

## Active network services

Signal K Server's main network services are:

- The primary Signal K http / WebSocket interface, with options to use TLS encryption and authentication (read/write)
- NMEA0183 data over TCP on port 10110 (read only)
- Signal K over TCP on port 8375 (read/write)

In addition the user may configure any number of TCP, UDP and Websocket connections, some of which allow write access to the server.

The security implication of these connections is that with no security options turned on devices connected to the network will have both read and write access to practically all of its data and settings.

People often dismiss local network access by saying that their boat's local network is secure enough. But one very common scenario is connecting your Signal K server (e.g. a Raspberry Pi) to a marina wifi. Many wifi networks allow communication between all connected computers, so your Signal K server will be advertising its services over MDNS to all other connected devices.

So in the case that your server has a manually configured connection for NMEA0183 over UDP, NMEA0183 data broadcast by other devices will be received and written into your SIgnal K data.

NMEA0183 connections over TCP and UDP are inherently unsafe. There are no options for authentication and / or secure communication. In comparison Signal K over TLS and HTTP / WebSockets can provide secure, authenticated read and write access to your data.

# Generating Tokens

## Overview

For a device to be able to interact with a Signal K server with security enabled, it is require to pass an access token with each request.

Examples include display / gauge, temperature sensor or client with no user interface.

To get an access token the following methods can be used:

1. The device can submit an Access Request which needs to be actioned via the Signal K Server UI.
2. Generate a token against a user account that has been configured on the Signal K Server.

### Generate Token

To generate a token against a user account that has been configured on the Signal K Server use the `signalk-generate-token` utility.

The `signalk-generate-token` utility is run from a terminal session on the Signal K Server and accepts the following parameters:

- `-u <username>`: The user account against which the token is created.
- `-e <time to live>`: The duration of time for which the token is valid.
  - 1y = 1 year
  - 2h = 2 hours
  - 10m = 10 minutes
  - 5s = 5 seconds
- `-s <path to security.json>`: The path to the Siganl K Server's security.json file (e.g. ~/.signalk/security.json)

Example: Generate a token against the user "TempSensorDevice" that is valid for 1 year.

    signalk-generate-token -u TempSensorDevice -e 1y -s ~/.signalk/security.json

Note: The device using the token will have the same permissions as the user account the token was generated against. It is recommended that you create a specific user with the appropriate permissions for use with the device.

### Access Requests

For information regarding Access Requests, see the Signal K specification.

## Configuring Signal K Server

Signal K Server provides an Admin UI to allow you to easily configure your installation.

Open the Admin UI using a web browser on the device where Signal K server is installed (if the defaults have not been changed) by navigating to `http://localhost:3000`.

### Create an Admin account

It is considered good practise to enable security and create an administrator account to controll access to your server and protect your data.

If you ran the `signalk-server-setup` script, security will be enabled and you will be presented with a login screen when accessing the Admin UI.

If the login screen is not displayed, click `Login` (top right of screen) to display the prompt to create a user and password.

Alternatively, from the menu select Security -> Users and then:

1. Click Add
2. Enter a user id
3. Enter a password and confirm it
4. In Permissions select Admin
5. Click Apply.

After creating the account, the server needs to be restarted.

How you restart the server will depend on the installation type (i.e. installed from NPM, embedded on a commercial device, etc). Power cycling the device that Signal K Server is always an option.

### Set up data connections

To get data into Signal K server you will need to configure one or more data connections via the Server -> Data Connections menu option.

From this screen you can add connections for various data types including:

- NMEA2000
- NMEA0183
- Signal K
- SeaTalk
- File Stream

The options presented will vary based on the data type chosen.

NMEA2000: The processing of NMEA2000 PGNs is done by n2k-signalk via canboatjs.

Please refer to the Canboat PGN database to see what PGNs are supported.

NMEA0183: The processing of NMEA0183 sentences is done by nmea0183-signalk

#### NMEA 0183 Options

- Suppress nmea0183 event - All incoming NMEA0183 data is made available over TCP on port 10110 by default. This happens by incoming data being emitted as nmea0183 events. Selecting this option will prevent data from this connection appearing on the NEMA0183 TCP service.

- Input Event - By default, data received on this connection will cause the nmea0183 event to be emitted. In order to distinguish input from this connection from other NMEA 0183 connections, enter an input event name which will be emitted (in addition to the nmea0183 event) when data is received on this connection.

- Validate checksum - Usually NMEA 0183 sentences contain a checksum that can be used to check that the data is not garbled so that erroneous data is discarded. However some data sources do not include the checksum or it is simply wrong. Unchecking this option will disable validating the checksum.

- Append Checksum - See previous point. Some data sources do not include a checksum, but for example a mobile app you are using may require them. Activating this option will add checksums to the data.

- Remove NULL characters - Some data sources include superfluous NULL characters in the input data stream, making the data invalid for consumption. This option will remove the NULL characters. It causes additional processing, so not on by default.

- Ignored Sentences - NMEA0183 sentences to throw away from the input data. Sometimes you may want to ignore certain sentences from a connection, because the data is invalid or missing or just not needed.

- Override timestamps - NMEA0183 data may include timestamps in tag blocks. These may be off or when playing back captured data you may want to ignore the data and override them with current time when converting to Signal K.

Connection type "File Stream"

Sample files are available which can be set up as input for the server.

Use below command to get the path to a NMEA 2000 file with navigation data and AIS targets.

    sudo find / -name "aava-n2k.data"

Set up according to picture.

To get the path for the sample file, data type NMEA 0183, use below command.

    sudo find / -name "plaka.log"

### Install Plugins and Webapps

Signal K server functionality can be extended through the use of plugins and webapps.

Plugins typically extend data acquisition, data processing or enable operations (i.e. protocol conversion, etc).

Webapps provide a user interface to view / interact with data or perform operations enabling full featured solutions such as a Chartplotter.

To install, update or remove plugins and webapps select Appstore from the menu.

Select:

- `Installed` to view a list of plugins and webapps currently installed.

- `Updates` to view a list of plugins and webapps that have updates available.

- `Available` to view a list of available plugins and webapps that can be filtered by categry.

The entries displayed with a blue icon are webapps, those with a green icon are plugins and those with both blue and green icons are plugins with a webapp providing a user interface.

Note: An internet connection is required for Signal K Server to list, install and update AppStore listings.

To install, click the `download` icon on the right hand side of the entry.

To view a list of Plugins and Webapps directly from the NPM registry select the links below.

- Plugins
- Webapps

Note: A restart of the Signal K server is required after plugins or webapps have been installed or updated.

Click the Restart button at the top right of the screen to restart the server.

After the server has restarted, the installed plugin(s) can be configued by selecting Server -> Plugin Config menu entry.

### Trouble shooting and the Server Log

If things are not working as expected after installing a plugin or webapp, select Server -> Server Log to view the server's log. If the errors logged there are not providing the information required, you can enable debugging for individual components and plugins by toggling the switch to activate them.

Enabling the `Remember debug setting` ensure your selections are remebered after a server restart.

## Landing page

When you access the Signal K server on a web browser you will be redirected to the Admin webapp as the default `landing page`. You can replace this default with your choice by adding the property `landingPage` in your `settings.json`. For example you can redirect the user to Kip or Freeboard.

## Add your Logo

You can change the logo image displayed at the top left of the Admin UI screen. To do this, add an SVG file named `logo.svg` in the settings directory (default: $HOME/.signalk/).

## Seatalk Connections

### Introduction

The Signal K Server supports a variety of data connection types including Seatalk (GPIO) which provides the ability to receive Raymarine Seatalk 1 (ST1) data, via simple DIY hardware connected to a Raspberry Pi GPIO, and convert it to Signal K deltas. This information can then be forwarded by the Signal K Server to a NMEA 0183 or NMEA 2000 network using appropriate hardware and plugins.

A guide to SeaTalk can be found here.

### Hardware

Using an optocoupler as the hardware interface is recommended as it creates electrical isolation from hazardous voltages and avoids ground loops.

The circuit below uses the PC817 optocoupler board but any equivlent product can be used. The LED in the circuit will flicker when there is ST1 traffic.

If you are building the interface yourself use the below circuit instead. If you don't want any flickering just drop the LED at the input.

A simpler, non-electrically isolated, solution is detailed below, using a low signal NPN transistor which inverts and shifts the voltage from 12V DC to 3.3V DC.

If you do not want to build your own circuit, you can get a MacArthur HAT and simply connect it to your Seatalk 1 network following the manual. If you also use OpenPlotter with this HAT, all the software will be installed and ready to go.

### Software

Before setting up the data connection on Signal K Server, you may need to install some associated Python libraries on your system. Here you have two options: gpiod library (Raspberry Pi 3, 4 and 5 models) or pigpio library (Raspberry Pi 3 and 4 models).

#### gpiod (recommended)

Both versions of this library 1.x.x (Debian package) and 2.x.x (Pip package) are supported. It is possible that your system already has one of the two versions of this library installed and some program is already using it, so before installing it we will check if we already have one.

Type this in a terminal:

    python -m pydoc gpiod | tail

If gpiod appears as installed, simply do nothing and go directly to the Data Connection section.

If it is not installed, type this in a terminal to install the latest version from pip:

    sudo pip3 install gpiod

Since Debian 12 (Bookworm) and Ubuntu 24 (Noble), pip packages need to be installed in virtual environments, but we need this library to be installed at the system level, so on these systems we need to type this instead:

    sudo pip3 install gpiod --break-system-packages

Pip will complain that the package is being installed in a non-virtual environment, but you can ignore the warning because it has not been detected to break any system packages.

#### pigpio

Inspired by Read SeaTalk1 from the Raspberry Pi GPIO using pigpio.

Open a terminal and enter the following:

1. Update the package manifest

        sudo apt-get update

2. Install the software

        sudo apt-get install pigpio python-pigpio python3-pigpio

3. Enable and start the pigpio daemon which handles the data connection.

        sudo systemctl enable pigpiod && sudo systemctl restart  pigpiod

4. Check the _pigpio_service is running

        sudo systemctl status pigpiod

Note: The pigpio deamon by default provides a socket interface on port 8888, which may conflict with other software running on your Raspberry Pi. To have the socket interface use another port you will need to change the pigpiod.service file using the Python program with the -p option.

### Data Connection

With the required software installed, you can now add a new data connection using the Signal K Server Admin UI.

Example Data Connection:

- Select Server -> Data Connections from the main menu.

- Click the Add button to create a new connection.

- Select Seatalk (GPIO) in the Data Type dropdown list.

- Set the Enabled to Yes.

- Enter an ID (e.g. Seatalk1).

- In GPIO Library, select the software that is installed on your system as we have seen in the previous section.

- In GPIO Pin, select one of the green GPIO pins from those pictured below (this will be the pin to which you connect your hardware e.g. GPIO04).

- Set Invert Signal based on the hardware interface you have used (e.g. Select No if using the optocoupler hardware setup above. Select Yes if using a hardware interface that inverts the ST1 signal).

- Click Apply to save your data connection settings.

- Restart the Signal K Server.

### Viewing Received Data

Once the server has restarted, confirm that data is being received from the ST1 connection by using the Data Browser in the Admin UI .

The data received via the Seatalk connection will be displayed in the Data Browser with a source value that contains the ID you provided when setting up the connection.

If there is no data displayed in the Data Browser from the Seatalk connection, you can check if there is data available at the selected GPIO using these utilities:

gpiod: https://gist.github.com/astuder/c319cf955f6d651350222d36065981b3

pigpio: https://raw.githubusercontent.com/MatsA/seatalk1-to-NMEA0183/master/STALK_read.py

If the display shows ST1 sentences being received at the GPIO pin then review your data connection settings.

# Feature: Anchor Alarm

## Contents

- Prerequisites
- Configuration
- Using the Anchor Alarm
- Alarms & Notifications
- Alternatives to WilhelmSK

## Introduction

This document describes how to setup an anchor alarm using Signal K Server and the WilhelmSK app that:

- Uses the GPS data from your navigation system, not your phone
- Has a graphical map + satellite view
- Vessel movement is saved and displayed as Track on a map
- Provides the ability to move the anchor location
- Sends push notifications to your iPhone (not Android), both remotely via the Internet and locally on the boat
- Sound an audible alarm on a Fusion stereo or via a common speaker connected to a Yacht Devices N2K device
- Does not depend on your phone having enough battery, GPS reception to wake you up

Image: WilhelmSK App on iPad.

## Prerequisites

- SignalK server installed, for example on a Victron GX device or RaspberryPi. See Installation for details.
- WilhelmSK iOS App

For use with other Apps (Android, web apps, etc) see Alternatives to WilhelmSK.

## Configuration

Step 1. Configure the Vessel data in SignalK server:

Be sure to set:

- Boat length
- GPS Distance from Bow
- GPS Distance from Center.

#### Step 2. Install required Signal K Server plugins:

- Open the Signal K Admin UI and if necessary Login
- Select Appstore -> Available from the menu
- Under Available Apps select All from the dropdown

Locate and install each of the following plugins:

- signalk-anchoralarm-plugin
- signalk-push-notifications
- signalk-alarm-silencer
- @signalk/tracks-plugin

After installation is complete, restart the server.

Note: The Restart button only appears at the upper right of the screen when security has been enabled. (See Enabling Security for details.)

#### Step 3 Configure the plugins:

Each of the plugins you installed in the previous step need to be configured and enabled. To do this:

- Select `Server -> Plugin Config`` from the menu
- Locate the plugin
- Set the appropriate configuration values
- Click Submit.
- Ensure the plugin is Enabled.

Following are details of how to configure each plugin:

Anchor Alarm plugin:

This plugin only needs to be enabled.

No configuration is required as the settings values are populated by WilhelmSK.

Alarm Silencer plugin:

This plugin only needs to be enabled.

No configuration options available.

Push Notifications plugin:

- To send notifications via an Internet connection check Enable Remote Push.

Note: The WilhelmSK app uses an Amazon RDS service to deliver push notifications. No additional accounts, etc are required as they are included with purchase.

- Local Push SSIDs: Enter the SSID(s) of the WiFi network(s) on your boat which the devices that are to receive notifications are connected.

- Local Push Port specifies the port number that WilhelmSK app will receive the local push notifications. The default value is 3001 and only needs to be changed if that port number is already in use by another app / plugin on the Signal K Server.

Note: It is not necessary to set the same value in the WilhelmSK app, it auto configures itself.

Tracks plugin

This plugin keeps track of the position of vessels visible to the Signal K Server. This enables apps to display a track of vessel movements.

The configuration values chosen will determince the amount of resource required run the plugin (and potentially the performance of the Signal K Server) so please consider this when making entries.

The following settings represent conservative values that are suitable for use with an anchor alarm:

- Track resolution: 60000 (60 seconds)
- Points to keep: 240 (4 hours)
- Max idle time: 600 (10 minutes)
- Max Radius: 1 meter (no other vessels).

Note: This plugin stores the track all the time, not only when on anchor. Which comes in handy when you enable the the anchor alarm a while after having dropped the anchor.

Step 4. Connect WilhelmSK to your SignalK server

After installing the WilhelmSK app, go to the iOS settings screen and check that it has network access permissions.

Also ensure that Background App Refresh also enabled as it is required for local push notifications and to raise an alarm while WilhelmSK app in not open on your phone or tablet.

Once network access has been enabled, start the WilhelmSK app and go to the connections menu.

Your boat's name (as entered in the vessel data, in step 1 above) and suffixed with (Discovered) should appear in the list. (If you can’t see it please ensure WilhelmSK has been granted network access permissions.)

Select your boat from the list and the configuration screen is displayed:

- Enter the user name and password that you use when logging into Signal K Server.

- Select AutoConnect On This Network. This will cause WilhelmSK to auto-select this connection when on the currently connected WiFi network.

With regards to the other available config options:

- Request Admin Access provides an alternative to using user name and password using a security token instead. Selecting this option sends an Access Request to the SignalK Server. The request will then need to be approved in the Security -> Access Requests screen of the Signal K Admin UI .
- Port: 3000 is the standard port.
- AutoConnect Default is used for a remote connection, which is out of scope of this manual.

Finally, verify your connection. Swipe left to back to the main menu and select the same connection:

Step 5. Enable WilhelmSK to receive push notifications

From the Settings menu select Notifications.

Note that the actual monitoring of the GPS coordinates is done by Signal K Server itself, not the WilhelmSK app. The app is only used to configure the anchor location, enable the alarm and to receive the alarm notifications.

It is also possible, and highly recommended, to add other notifications. For example via Fusion stereo, if installed, or by using a dry contact with audible alarm. (These are out of scope of this manual.)

Tip: For using the Fusion stereo: search the server plugins with the keyword Fusion.

## Using the Anchor Alarm

Now that the connections have been configured, go to the main screen of the WilhelmSK App where you’ll see something similar to the following screenshot.

If data is being received from the Signal K server, green dots are displayed in the top right of each gauge to indicate that the value displayed is current.

In case of incorrect username and/or password or other connection errors, these will be displayed at the top of the screen as warning.

With an established connection and data being received, swipe to the right a few times to display the anchor watch page.

Clicking the anchor on the top left of screen (next to the menu button), cycles through the sequence of arming / disarming the alarm:

- White anchor indicates disarmed. Click when dropping the anchor and the color will change to yellow.
- Yellow anchor indicates that the rode length is being calculated. Click when you have finished letting out the anchor and the colour will change to green.
- Green anchor means the alarm is armed and ready.

Use the “four arrows icon” on the top left of screen to move the anchor location.

You can also change the alarm radius.

Clicking the green anchor will prompt you to confirm that you want to disarm the alarm / raise the anchor.

TIP: To return to other pages (i.e. COG and AWA gauges) swipe left by holding the Course up/Head up/North up menu.

## Alarms & Notifications

For most use cases, push notifications shouldn’t be the only means of receiving alarms as the phone can decide to hide notifications, etc so additional means of sounding the alarm should be employed.

Following are some alternatives.

### Audible alarms using the Raspberry Pi audio connector

To have the Signal K Server produce audible notifications using a speaker connected directly to the Raspberry Pi audio connector install the signalk-audio-notifications plugin.

### Alarm to NMEA2000 network

To have the Signal K Server forward the alarm to the NMEA2000 network to appear on connected devices, install and configure the signalk-to-nmea2000 plugin.

#### Raymarine alarm compatibility

With the Raymarine options enabled in the signalk-to-nmea2000 plugin, an audible alarm will be generated on the Raymarine SeaTalkNG Auxiliary Alarm Buzzer - A8061 and will display on Raymarine Axiom plotters.

_Note: The anchor alarm will be displayed as a “Shallow anchor alarm” on Raymarine, as that is the most suitable alarm type. Interpret that as just an anchor alarm, which has nothing to do with shallow. Here is how it looks on the Raymarine plotter:

#### Garmin alarm compatibility

Compatible

#### Navico (B&G, Simrad, Lowrance) alarm compatibility

Not compatible

#### Yacht Devices compatibility

The YDAB-01 is a very flexible and configurable device sold by Yacht Devices.

It is connected to the NMEA2000 network and has a 10W audio amplifier which can output sound via a 4 or 8 Ohm speaker which directly connected. It has bank of 28 sound signals can be configured to sound on receipt of the anchor alarm.

#### Additional information

The following post on Panbo is a great resource with regards to the N2K Alert PGNs: Link

### Remote notifications

There are a number of Signal K Server plugins which enable notifications to be sent remotely, following are just a few:

#### signalk-pushover-notification-relay

This plugin listens for a change of state in Signal K notifications and sends the updates to the Pushover App which is available for both Apple and Android phones and tablets.

This is a paid service from Pushover.

Plugin: signalk-pushover-notification-relay

#### signalk-notifications-manager

This plugin also works with Pushover to deliver notifications as push messages on your phone or tablet, but it also:

- Keeps a history of alerts stored in a local database
- Includes a Signal K web app to manage the notifications.

Plugin: signalk-notifications-manager

#### signalk-clicksend-notifications-relay

This plugin forwards notifications via the (paid) Clicksend SMS gateway, which can deliver notifications to your phone.

Plugin: signalk-clicksend-notifications-relay

### Switching a relay

Operating a switch or relay provides a range of options for sounding an alarm but will require diving a bit deeper into the various (and extensive) automation options made available by Signal K Server.

A good place to start is the signalk-switch-automation plugin.

## Alternatives to WilhelmSK

As the data processing to "watch" the anchor and generate the alarm messages is performed by the Signal K Server, client applications, any client application that supports the anchor-alarm plugin can be used to arm / disarm and configure it.

Listed below are some other apps and supported operations:

Client App | Arm / disarm | Set radius | Move location | See track | Plays sound
--- | --- | --- | --- | --- | ---
Wilhelm SK (iOS) | yes | yes | yes | yes | yes
Anchor alarm plugin (web app) | yes | yes | yes | yes | no
Freeboard SK (web app) | yes | yes | yes | yes | yes
Aqua Map (iOS & Android) | ? | ? | ? | ? | ?

### Anchor Alarm Plugin

The anchor alarm plugin provides a web user interface available under WebApps in the Signal K Server Admin UI.

It provides the ability to arm / disarm, set the radius and shift the anchor but does not display the alarm on screen or play a sound.

### Freeboard SK

Freeboard SK provides a "sequence" driven user interface to "step" through the setting of the anchor alarm.

It provides the ability to drop / raise the anchor, set / adjust the alarm radius and shift the anchor position via the Anchor Watch feature in the main menu.

When set, it will:

- Display the alarm radius on the map
- Show the vessel track whilst anchored

When alarm is triggered:

- Display an alarm notification on screen
- Play a sound

It is available under WebApps in the Signal K Server Admin UI.

# Signal K Server as a NMEA0183 Data Server

## Introduction

This document details how to setup Signal K Server to read AIS and navigation data from a NMEA2000 (or any other) network and make it available on a WiFi network for use with popular phone / tablet apps like:

- Navionics
- iSailor
- iNavX
- Aqua Map
- WilhelmSK.

The Signal K Server does this by passing the data received from the configured Data Connections, through two plugins which transform it to NMEA0183 sentences, which are then transmitted on the WiFi network.

## Prerequisites

A Signal K Server:

- Installed on a suitable device (e.g. Victron GX, RaspberryPi, etc). See Installation for details.
- Connected to a NMEA2000, etc network and Data Connections configured.
- Connected to a WiFi network. (Beyond the scope of this document.)

## Server Setup and Configuration

All configuration is done from within the Signal K Server Admin UI. Open the Admin UI in your browser and complete the following steps.

#### Step 1. Enter Vessel Base Data:

- Select Server -> Setup from the menu.

- The Vessel Base Data section, enter values for Length, GPS Distance from Bow and GPS Distance from Center.

#### Step 2. Install and Configure Plugins:

The following plugins are required to process and transform the received data to NMEA0183:

- `signalk-to-nmea0183` (documentation on npmjs)
- `signalk-n2kais-to-nmea0183` (documentation on npmjs)

Note: Starting with Signal K Server version 2.2.0 these plugins are pre-installed. It is recommended that these plugins be updated to the current version.

To install the plugins:

- In the Admin UI, select Appstore -> Available-> All from the menu
- Locate the `signalk-to-nmea0183`plugin and click the install icon
- Locate the `signalk-n2kais-to-nmea0183` plugin and click the install icon
- Restart the Signal K Server.

Note: If the Restart button is not displayed in the upper right of screen, refer to Enabling Security for details.

To configure the plugins:

- In the Admin UI, select Server -> Plugin Config from the menu.

- Locate `signalk-to-nmea0183` plugin.

  1. Ensure it is enabled
  2. Check ALL the boxes to transmit all NMEA0183 sentence types
  3. Leave the transmission interval (throttle) at 0
  4. Click the Submit button to save your choices.

- Locate `signalk-n2kais-to-nmea0183` plugin. This plugin transmits all the AIS targets.

  1. Ensure it is enabled
  2. Enter nmea0183out in the NMEA 0183 Out Events field.
  3. Click the Submit button to save the configuration.

#### Step 3. Enable NMEA0183 on the WiFi network:

- In the Admin UI, select Server -> Settings

- Locate the Server Settings section

- Ensure that NMEA 0183 over TCP (10110) is set to On

- Click Save and Restart the Signal K Server.

Once restarted the Signal K Server will transmit NMEA0183 sentences containing all your navigation and available AIS target data on the WiFi network on TCP port 10110.

Note: It is recommended that Signal K over TCP (8375) is set to On if you are using an app (e.g. Aqua Map) which supports the “Signal K over TCP” protocol as it is more feature rich.

## Configuring Apps

Device apps can now be configured to connect to the NMEA0183 data stream from the Signal K Server.

Following is an example of how to connect the Navionics boating app.

- Open the menu

- Select Paired devices and add a new paired device

- Enter a name for the device e.g. MySignalK Server

- In Host enter the IP address of the Signal K Server you configured in the steps above

- In Port enter 10110

- Select TCP

- Click Save

# Data Logging

Signal K server can log all input data from the configure input connections to a hourly data log files.

You can activate data logging for each connection by switching on Data Logging under Server / Data Connections, saving the connection settings. The setting takes effect after restarting the server.

The log files are downloadable in the Admin UI under Server / Server Logs.

The logs contain the data that the server has processed in the raw, original format (prior to conversion to Signal K) and each message is timestamped.

Log files can be used for archiving, to later play back the data or for debugging purposes. The server can play them back by creating a Data Connection with Data Type `File Stream` and secondary Data Type as `Multiplexed Log`.

## Help & Support

Signal K has an friendly and helpful community where you can find support and assistance whether you are trouble shooting issues or just have a question.

Join the discussion:

- Discord (New to Signal K Discord? Click here for an invite.)

- GitHub Discussions

- FAQ: Frequently Asked Questions

## Frequently Asked Questions

Answers to common issues and queries can be found on the Frequently Asked Questions space on GitHub.

Following are links to common queries:

- How do I integrate with NMEA2000 (CAN bus).

- Installing & Updating NodeJS

# Sponsor Signal K

Signal K is all about creating open and interoperable marine data systems. We have created an open specification for representing marine related data, APIs and interfacing to use the data and free software that you can download and use.

If you would like to contribute and help fund continued development visit Signal K on Open Collective.

# Notes for Developers

Signal K Server has an extensible architecture that enables developers to add functionality to support new protocols, devices, information sources, etc.

The information in this section aims to provide guidance, not only on how to develop plugins and applications to extend capability, but also how to do so in alignment with the Signal K specification, protocol and server architecture. By understanding the underlying architecture, the plugins and apps you create will ensure that the additional functionality and data will be discoverable and work in harmony with other solutions.

## Looking Ahead

Signal K Server v2 marks the start of an evolution from the Signal K v1 approach of defining the paths, their hierarchy and the full data model schema, towards an approach centered around modular REST APIs (HTTP endpoints defined as OpenApi specifications).

These APIs enact operations (i.e. activate a route, advance to next point, etc) rather just expose a generic data model with some well known paths. They are available under the path `/signalk/v2/api` so they can coexist with v1 APIs. There is a connection with the Signal K full data model but, unlike the v1 APIs it is not 1:1, it is abstracted behind the interface.

The reason for adopting this approach is to address the fact that many paths within a Signal K hierarchy are related, a change in the value of one path will require that the value of other paths be updated to ensure that the data model is consistent. At present this relies on the plugin / application knowing which paths in the hierarchy are related. Additionally there may be other plugins / applications also updating some of the same paths which can cause the data model to become invalid, which then erodes trust in the data which impacts its use in navigation.

The v1 model for using PUT handlers is also very vague and causes confusion. The aim of defining APIs with clear contracts using industry standard OpenApi mechanism is to make APIs discoverable and their use and semantics explicit.

The use of APIs to perform operations addresses these issues providing the following benefits:

1. A standardised interface for all applications / plugins to perform an operation
2. Provides clear ownership of the paths in the Signal K data model
3. Ensures values are being maintained in all of the related paths.
4. Increases trust in the data for use in all scenarios.

### Stream Interface

Currently, when v2 REST APIs emit deltas that contain v2 paths and structure, but they do not end up in the full model. This means that these paths and values are only available via API GET requests.

## Offline Use

When operating on a vessel you should not assume that a connection to Internet services is available. Therefore, it is important that the WebApps and Plugins you create be "self contained" and provide all the resources they require to operate (i.e. fonts, stylesheets, images, etc). This also minimises data charges even if your module does use data over Internet.

For WebApps and Plugins that do connect to Internet based services to provide data, they should be resilient to changes in the connection status to those services and where necessary display their status.

## Deprecations and Breaking Changes

With the move towards REST APIs and the desire to improve the data model (and also fix some mistakes) it's inevitable that there will be deprecations and breaking changes.

For example, when addressing duplicate Great Circle and Rhumbline course paths, the resultant changes will likley break compatibility with v1.

For details about paths that are flagged for deprecation see Changes & Deprecations.

# What's new in Version 2.

Signal K Server version 2 introduces new REST APIs designed to perform specific operations (e.g. set destination, advance to next point, etc).

These APIs have been implemented to ensure the integrity of the underlying Signal K data model by maintaining values in all related paths associated with the operation. In this way a cohesive, reliable data set is presented to all connected applications and devices.

The new APIs are mounted under `/signalk/v2/api`, their definitions available as OpenApi documents accessible via Documentation -> OpenAPI in the server admin user interface. They coexist with `/signalk/v1/api` paths to ensure continued operation of applications.

Some REST APIs provide an `interface` for use by plugins via the Server Plugin API to enable them to enact operations in a managed way.

Important: The Signal K data paths maintained by the REST APIs should NOT be updated directly by any other plugin or process!

With the move towards operation based APIs some paths are flagged for deprecation. Please see Changes & Deprecations for details.

### Course API

Provides common course operations via `/signalk/v2/api/vessels/self/navigation/course`.

See the Course API for details.

### Resources API

Provides operations for creating, maintaining and accessing resources such as routes, waypoints, etc via `/signalk/v2/api/resources`.

See the Resources API for details.

## Notes for Developers:

### NMEA0183 / NMEA2000 message processing

Whilst the Course API and its associated operations provide a means of setting a course, NMEA data streams are the source of information when the course is set on a connected device.

In the past, plugins processing NMEA data streams have directly populated the mapped `v1` Signal K paths based on the received sentence / PGN values. Moving forward these plugins should utilise the relevant Server Plugin API methods to enact course operations.

### Stream updates

The new REST APIs emit `v2` deltas with values that are objects.

For example, when a course is activated, deltas will be emitted for `navigation.course.previousPoint`, `navigation.course.nextPoint` and `navigation.course.activeRoute` where the value is an object.

Example: v2 Delta

    {
        "path": "navigation.course.previousPoint",
        "value": {
            "position": {
               "latitude": 65.0,
               "longitude": 3.754
            },
            "type": "Location",
            "href": null
        }
    }

#### Connection with v1 Full Data Model

The current implementation of Signal K Server provides only a single `stream` endpoint (`/signalk/v1/stream`) and all values emitted as deltas (both `v1` & `v2`) will continue appear there.

It should be noted, that even though both `v1` & `v2` deltas appear in the one stream, only `v1` deltas will populate the full data model and be available under the `/signalk/v1/api` path!

# Changes & Deprecations

The introduction of new REST APIs in version 2 and the move to an operations based model has resulted in some version 1 paths being flagged for deprecation.

It is recommended that applications and plugins referencing these deprecated paths update their operation to reference the version 2 paths.

## Changes

The following changes have been implemented with the introduction of Resources API and apply to applications using the `./signalk/v2/resources` endpoint.

Note: These changes DO NOT impact applications using the `./signalk/v1/resources` endpoint.

### 1. Resource ID prefix assignment

The version 1 specification defined resource Ids with the following format `urn:mrn:signalk:uuid:<UUIDv4>`.

e.g. `urn:mrn:signalk:uuid:18592f80-3425-43c2-937b-0be64b6be68c`

The Resource API has dropped the use the prefix and ids are now just a uuidv4 value.

e.g. `18592f80-3425-43c2-937b-0be64b6be68c`

This format is used for both accessing a resource e.g. `/signalk/v1/api/resources/waypoints/18592f80-3425-43c2-937b-0be64b6be68c` as well as the value within an `href` attribute.

Example:

    {
       "name": "...",
       "descripton": "...",
       "href": "/resources/waypoints/18592f80-3425-43c2-937b-0be64b6be68c",
       ...
    }

### 2. Resource Attributes

The Resources API has updated the definition of the following resources and may break applications that simply shift to using the `v2` api without catering for the changes:

- routes: removed the `start`, `end` properties.
- waypoints: removed `position` attribute, added `name`, `description` and `type` attributes.
- regions: removed `geohash` attribute, added `name` and `description` properties.
- notes: removed `geohash` and `region` attributes, added `href` and `properties` attributes.
- charts: There has been a significant changes to include support for WMS, WMTS and TileJSON sources.

Please see the Resources OpenAPI definition for details.

## Deprecations:

### 1. courseGreatCircle, courseRhumbline paths

With the introduction of the Course API the following paths should now be considered deprecated:

- `/signalk/v1/api/vessels/self/navigation/courseGreatCircle`
- `/signalk/v1/api/vessels/self/navigation/courseRhumbline`

Note: The Course API does currently maintain values in these paths for the purposes of backward compatibility, but applications and plugins referencing these paths should plan to move to using the equivalent paths under `/signalk/v2/api/vessels/self/navigation/course`.

# WebApps and Components

## Introduction

Signal K Server provides the following ways to add web-based user interfaces to enhance functionality and usability:

1. Standalone WebApps are web applications that when launched, the server Admin UI disappears and the webapp controls the whole page (browser window / tab).

2. Embedded WebApps are web applications that when launched, are embedded in the server Admin UI, leaving the toolbar and menu available to the user.

3. Embedded Plugin Configuration Forms are forms provided by a plugin that the server embeds within the Plugin Config screen to replace the generic form rendered using the plugin configuration schema. This allows a richer set of controls to be provided for the user to configure the plugin compared to the more generice server generated form provides.

4. Embedded Components are individual UI components provided by a plugin or a webapp. They are listed in the Addons section at the bottom of the Webapps page of the Admin UI. More a concept than a fully implemented feature at this stage, the idea is to allow a plugin to add individual components to different parts of the server UI.

All Plugins, WebApps and Components can be installed via the Appstore.

## WebApp Structure

All WebApps (like plugins) are installed with `npm`, either from the npm registry or from your own Github repository. Only WebApps that are relevant for all users should be published to `npm` to be made available in the Appstore of all Signal K Servers.

Note: Private plugins need not be published to `npm` - see the documentation for npm install for details.

The basic structure of a webapp is:

- A folder named `public` that contains the html, JavaScript and resource files such as images, fonts and style sheets. This folder is automatically mounted by the server so that the webapp is available after installation and the server restarted.
- `package.json` containing special keywords that classifies the webapp:
  - `signalk-webapp` - standalone webapp
  - `signalk-embeddable-webapp` - embeddable webapp
  - `signalk-plugin-configurator` - plugin configuration form

This structure is all that is needed for a standalone webapp.

You can also include the following section in `package.json` to control how your webapp appears in the Webapps list:

      "signalk": {
        "appIcon": "./assets/icons/icon-72x72.png",
        "displayName": "Freeboard-SK"
      },

where:

- `appIcon` is the path (relative to the `public` directory) to an image within the package to display in the webapp list. The image should be at least 72x72 pixels in size.
- `displayName` is the text you want to appear as the name in the webapp list. (By default the name attribute in the `package.json` is used.). Displayname is also used in an automatic redirect from the root of the server: if you have a webapp with displayName `foo` and you access it using for example the url http://foo.bar.org:3000 the first part of the hostname matches the webapp's displayName and you will be redirected to it instead of the default landingPage, the Admin webapp. With this mechanism you can add easy to access DNS names to each webapp, including .local names.

See also Working Offline.

## Application Data: Storing Webapp Data on the Server

Application Data is only supported if security is turned on. It supports two namespaces, one for global data and one for user specific data. For example, a client might want to store boat specific gauge configuration globally so that other users have access to it. Otherwise, it could use the user area to store user specific preferences.

The data is structured and manipulated in JSON format.

Global storage: `/signalk/v1/applicationData/global/:appid/:version` User storage: `/signalk/v1/applicationData/user/:appid/:version`

There are two ways to update or add stored data:

- You can POST any json data to any path:

    POST /signalk/v1/applicationData/user/my-application/1.0/unitPreferences
    {
      "shortDistance": "m",
      "longDistance": "km"
    }

- You can also use json patch format (http://jsonpatch.com):

    POST /signalk/v1/applicationData/user/my-application/1.0
    [
      { "op": "add", "path": "/unitPreferences", "value": { "shortDistace": "m" } },
      { "op": "add", "path": "/unitPreferences/longDistance", "value": "km"}
    ]

Use an HTTP GET request to retrieve data from the server:

`GET /signalk/v1/applicationData/user/my-application/1.0/unitPreferences/shortDistance`

You can just GET the list of keys:

    GET /signalk/v1/applicationData/user/my-application/1.0/unitPreferences?keys=true
    [ "longDistance", "shortDistance"]

You get can a list of available versions:

    GET /signalk/v1/applicationData/user/my-application
    [ "1.0", "1.1"]

## Discovering Server Features

To assist in tailoring a WebApps UI, it can "discover" the features supported by the server by sending a request to `/signalk/v2/features`.

The response wil contain an object detailing the available APIs and Plugins.

You can use the `enabled` parameter to specify to only return enabled or disabled features.

To list only enabled features: `/signalk/v2/features?enable=1`

To list only disabled features: `/signalk/v2/features?enable=0`

Example response:

    {
      "apis": [
        "resources","course"
      ],
      "plugins": [
        {
          "id": "anchoralarm",
          "name": "Anchor Alarm",
          "version": "1.13.0",
          "enabled": true
        },
        {
          "id": "autopilot",
          "name": "Autopilot Control",
          "version": "1.4.0",
          "enabled": false
        },
        {
          "id": "sk-to-nmea2000",
          "name": "Signal K to NMEA 2000",
          "version": "2.17.0",
          "enabled": false
        },
        {
          "id": "udp-nmea-sender",
          "name": "UDP NMEA0183 Sender",
          "version": "2.0.0",
          "enabled": false
        }
      ]
    }

## Embedded Components and Admin UI / Server interfaces

Embedded components are implemented using Webpack Federated Modules and React Code Splitting.

Note: There is no keyword for a module that provides only embedded components, use `signalk-webapp` instead.

You need to configured Webpack to create the necessary code for federation using ModuleFederationPlugin and expose the component with fixed names:

- embeddable webapp: `./AppPanel`
- plugin configuration form: `./PluginConfigurationPanel`
- embedded component: `./AddonPanel`

The ModuleFederationPlugin library name must match the package name and be a "safe" name for a webpack module like in `library: { type: 'var', name: packageJson.name.replace(/[-@/]/g, '_') },`

The exposed modules need to `export default` a React component - both class based components and stateless functional components can be used. The server dependencies like `reactstrap` can and should be used. Add `@signalk/server-admin-ui-dependencies` as a dependency to the webapp, it defines the depedencies used by the server admin UI.

See the vesselpositions embedded webapp/component and Calibration plugin for examples of each. It is probably easier to start with either one and modify them to suit your needs. Don't forget to change the module id and name in package.json!

## WebApp / Component and Admin UI / Server interfaces

Standalone WebApps can use the server's APIs (Signal K http and WebSocket APIs as well as any server specific endpoints) but they need to implement everything else themselves.

Embedded WebApps, Components and Plugin Configuration Forms work inside the Admin UI, so they can interact with both the Admin UI and the server using APIs exposed by the Admin UI as component properties.

Embedded webapp properties:

- access to the login status of the browser user
- ability to render Login form instead of the webapp content
- getting and setting application data
- opening an automatically reconnecting WebSocket connection to the server
- getting Signal K data via `get`
- Embedded

PluginConfigurationForm properties:

- `configuration` : the configuration data of the plugin
- `save`: function to save the configuration data
- EmbeddedPluginConfigurationForm

Note: The documentation regarding embedded WebApps and Components provided at this time is rudimentary and should be considered under development as the concept is evolving.

## Authentication and Session Management

Per the specification the server provides the endpoint `/signalk/v1/auth/login` for logging in. A successful request will

- set an authentication cookie
- return an authentication token

For cookie based, shared sessions all a webapp needs to do is use `credentials: "include"` when making api calls with fetch. Cookies are included automatically in the initial WebSocket opening HTTP request, so the same works automatically for WebSocket connections.

The session cookie's value is the same as the token value: it is a JWT token that includes a validity period and is signed by the server. The server is stateless: JWT is verified for each request for a valid signature and time. Validity period is governed by server's security `expires` configuration value that can be changed in Admin UI's Security section.

The login endpoint has an optional `rememberMe` request parameter. By default, without `rememberMe` set to true, the cookie is erased on browser restarts per standard browser behavior. When true the response's set cookie header includes MaxAge value based on the server's `expires` value. This makes the cookie persist over browser restarts.

As the cookie is set to be `HttpOnly` webapp JavaScript has no access to it. Including it in server requests and persisting its value is managed by the browser, governed by the `Set-Cookie` headers sent by the server.

Additionally the server sets cookie `skLoginInfo` when the user logs in and removes it when the user logs out. A webapp can poll for changes of this cookie to be notified of the browser's cookie based login status.

For token based sessions a webapp may manage the authentication token itself. It must include it explicitly in fetch call headers. As JavaScript has no access to headers but cookies are included automatically by browsers when opening WebSocket connections the server will use the server-set, HttpOnly cookie. Normally browsers do not allow shadowing the server-set cookie with a new value. The only option for WebSocket connections is using a query parameter to override the cookie with a token.

The order that the server uses for finding the JWT token is

1. query parameter `token`
2. request header `authorization`
3. authorization cookie (name managed by the server)

Token-based session management is currently discouraged, because it may result in session confusion: all login calls set the shared session cookie for all webapps that are using cookie based, shared sessions.

Each webapp acting separately, managing its authentication token independently, means that

- each application needs to implement token management separately so that closing and reopening the webapp during a browser session does not require the user to reauthenticate
- when navigating between the different webapps the user needs to authenticate to each one separately

The server's Admin UI is a regular webapp using cookie based sessions, there is no separate authentication mechanism.

# Server plugins

## Overview

Signal K Node server plugins are components that extend functionality of the server. They are installed via the AppStore and configured via the Admin UI.

Signal K server exposes an interface for plugins to use in order to interact with the full data model, emit delta messages and process requests.

Plugins can also provide a webapp by placing the relavent files in a folder named `/public/` which the server will mount under `http://{skserver}:3000/{pluginId}`.

Note: With the move towards Signal K server providing APIs to perform operations, it is important that you consider how the proposed functionality provided by your plugin aligns with the Signal K architecture before starting development.

For example, if the plugin you are looking to develop is providing access to information such as `route,` `waypoint`, `POI`, or `charts` you should be creating a Resources Provider Plugin for the Resources API.

Or if you are looking to perform course calculations or integrate with an auotpilot, you will want to review the Course API documentation prior to commencing your project.

OpenApi description for your plugin's API

If your plugin provides an API you should consider providing an OpenApi description. This promotes cooperation with other plugin/webapp authors and also paves the way for incorporating new APIs piloted within a plugin into the Signal K specification. See Add OpenAPI definition below.

## Getting Started with Plugin Development

### Prerequisites

To get started developing your plugin you will need the following:

- Signal K server instance on your device (clone of GIT repository or docker instance)
- NodeJs version 18 or later and NPM installed
- SignalK server configuration folder. (Created when Signal K server is started. default location is `$HOME/.signalk`).

### Setting up your project

1. Create a folder for your plugin code and create the necessary file structure:

    mkdir my-pluin
    cd my-plugin
    npm init      # create package.json file

2. Create the folders to hold your plugin code and webapp UI.

    /my-plugin
      /plugin     # plugin (javascript code / built typesrcipt code)
        index.js
        ..
      /public     # web app UI
        index.html
        ..
      /src        # typescript source code (not required if using javascript)
        index.ts
        ...
      package.json

3. Update the `package.json` to reflect your project structure and add keywords to identify the package for the Signal K AppStore.

    {
      "name": "my-plugin",
      "version": "1.0.0",
      "description": "My signalk plugin",
      "keywords": [
        "signalk-node-server-plugin",
        "signalk-category-ais"
      ],
      "signalk-plugin-enabled-by-default": false,
      "signalk": {
        "appIcon": "./assets/icons/icon-72x72.png",
        "displayName": "My Great WebApp"
      },
      "main": "plugin/index.js",
      ...
    }

4. Optional: Install any dependencies or third party packages.

    npm i

### Link your project to Signal K server.

Once you have developed your plugin code and are ready to debug, the most convenient way is to use `npm link` to link your plugin code to your instance of Signal K server.

To do this, from within a terminal window:

    # Ensure you are in the folder containing your built plugin code
    cd my_plugin_src

    # Create a link (may require the use of sudo)
    npm link

    # Change to the Signal K server configuration directory
    cd ~/.signalk

    # Link your plugin using the name in the package.json file
    #(may require the use of sudo)
    npm link my-signalk-plugin-app

When you start Signal K server the plugin will now appear in the Plugin Config screen where it can be configured and enabled.

Updating and/or installing new plugins will remove the link and you need to re-link your plugin.

### Debugging

The simplest way to debug your plugin is to turn on Enable Debug log for your plugin in the Plugin Config screen.

Alternatively, you can debug your plugin by starting the Signal K server with the `DEBUG` environment variable:

    $ DEBUG=my-signalk-plugin signalk-server

    # sample output
    my-signalk-plugin Plugin stopped +0ms
    my-signalk-plugin Plugin started +2ms

You can also view debug information about the plugin loading process:

    $ DEBUG=signalk:interfaces:plugins signalk-server

    # sample output
    signalk:interfaces:plugins Registering plugin my-signalk-plugin +0ms
    signalk:interfaces:plugins Could not find options for plugin my-signalk-plugin, returning empty options:  +2ms

#### Sample Data

For development purposes, it's often nice to have some mocked data. SignalK comes with a synthesized NMEA2000 data set that can be used as sample data.

You can enable this by adding `--sample-n2k-data` to the command line:

    $ DEBUG=my-signalk-plugin signalk-server --sample-n2k-data

## Start Coding

Signal K server plugins are NodeJs `javascript` or `typescript` projects that return an object that implements the `Plugin` interface.

They are installed into the `node_modules` folder that resides inside the SignalK server's configuration directory (`$HOME/.signalk` by default).

A Signal K plugin is passed a reference to the Signal K server plugin interface which it can use to interact with the server.

Following are code snippets that can be used as a template for plugin development ensuring the returned Plugin object contains the required functions.

### Javascript

Create `index.js` with the following content:

    module.exports = (app) => {

      const plugin = {
        id: 'my-signalk-plugin',
        name: 'My Great Plugin',
        start: (settings, restartPlugin) => {
          // start up code goes here.
        },
        stop: () => {
          // shutdown code goes here.
        },
        schema: () => {
          properties: {
            // plugin configuration goes here
          }
        }
      };

      return plugin;
    };

### Typescript

Create `index.js` with the following content:

    import { Plugin, PluginServerApp } from '@signalk/server-api';

    module.exports = (app: PluginServerApp): Plugin => {

      const plugin: Plugin = {
        id: 'my-signalk-plugin',
        name: 'My Great Plugin',
        start: (settings, restartPlugin) => {
          // start up code goes here.
        },
        stop: () => {
          // shutdown code goes here.
        },
        schema: () => {
          properties: {
            // plugin configuration goes here
          }
        }
      };

      return plugin;
    }

A plugin must return an object containing the following functions:

- `start(settings, restartPlugin)`: This function is called when the plugin is enabled or when the server starts (and the plugin is enabled). The `settings` parameter contains the configuration data entered via the Plugin Config screen. `restartPlugin` is a function that can be called by the plugin to restart itself.

- `stop()`: This function is called when the plugin is disabled or after configuration changes. Use this function to "clean up" the resources consumed by the plugin i.e. unsubscribe from streams, stop timers / loops and close devices. If there are asynchronous operations in your plugin's stop implementation you should return a Promise that resolves when stopping is complete.

- `schema()`: A function that returns an object defining the schema of the plugin's configuration data. It is used by the server to generate the user interface in the Plugin Config screen.

Note: When a plugin's configuration is changed the server will first call `stop()` to stop the plugin and then `start()` with the new configuration data. Return a Promise from `stop` if needed so that `start` is not called before stopping is complete.

A plugin can also contain the following optional functions:

- `uiSchema()`: A function that returns an object defining the attributes of the UI components displayed in the Plugin Config screen.

- `registerWithRouter(router)`: This function (which is called during plugin startup) enables plugins to provide an API by registering paths with the Express router is passed as a parameter when invoked. It is strongly recommended that he plugin implement `getOpenAPI()` if this function is used.

Example:

    plugin.registerWithRouter = (router) => {
        router.get('/preferences', (req, res) => {
        res.status(200).json({
          preferences: {
            color: 'red',
            speed: 1.23
          }
        });
      });
    };

- `getOpenApi()`: Function to return the OpenAPI definition. This should be implemented when your plugin provides HTTP endpoints for clients to call. Doing so makes the OpenAPI definition available in the server Admin UI under `Documentation -> OpenAPI`.

Example:

    const openapi = require('./openApi.json');

    plugin.getOpenApi = () => openapi;

## Plugin configuration / Schema

A plugin's `schema` function must return a JSON Schema object decribing the structure of the configuration data. This is used by the server to render the plugin's configuration screen in the Admin UI.

The configuration data is stored by the server under the following path `$SIGNALK_NODE_CONFIG_DIR/plugin-config-data/<plugin-name>.json`. (Default value of SIGNALK_NODE_CONFIG_DIR is $HOME/.signalk.)

Example:

      plugin.schema = {
        type: 'object',
        required: ['some_string', 'some_other_number'],
        properties: {
          some_string: {
            type: 'string',
            title: 'Some string that the plugin needs'
          },
          some_number: {
            type: 'number',
            title: 'Some number that the plugin needs',
            default: 60
          },
          some_other_number: {
            type: 'number',
            title: 'Some other number that the plugin needs',
            default: 5
          }
        }
      };

JSON Schema approach works reasonably well for simple to medium complex configuration data.

It should ne noted that some JSON schema constructs are not supported. Refer (details) for details.

The server supports also custom plugin configuration components, bypassing the automatic configuration format generation.

The plugin is passed the configuration settings as the first parameter of the `start` function.

    plugin.start = (settings, restartPlugin) => {
      // settings contains the plugin configuration
      ...
    }

### UI Schema

The plugin can define `uiSchema` by returning a uiSchema object which is used to control how the user interface is rendered in the Admin UI.

_Example: Make all data in an object called 'myObject' collapsible:

    uiSchema['myObject'] = {
      'ui:field': 'collapsible',
      collapse: {
        field: 'ObjectField',
        wrapClassName: 'panel-group'
      }
    }

For more information, see react-jsonschema-form-extras

### Making a plugin enabled by default

If your plugin does not require any initial configuration, you can enable it to start when the Signal K server is restarted after the plugin is installed.

To do this add the following to the `package.json`:

      "signalk-plugin-enabled-by-default": true

## Add an OpenAPI Definition

If your plugin exposes an API to interact with it then you should include an OpenAPI definition.

You do this by creating an OpenAPI definition within the file `openApi.json` and then returning the content of the file with the `getOpenApi` method.

Example:

    const openapi = require('./openApi.json');
    ...

    plugin.getOpenApi = () => openapi;

This will include your plugin's OpenApi definition in the documentation in the server's Admin UI under Documentation -> OpenAPI.

Note: If the plugin's OpenApi description DOES NOT include a `servers` property, the API path presented in the documentation will be relative to the Signal K API path. You should include this property the plugin API is rooted elsewhere. Example:

      "servers": [
        {
          "url": "/myapi/endpoint"
        }
      ],

See testplugin for an example.

## Logging

To record deltas sent by the plugin in the server's data log, enable the Log plugin output in the plugin configuration screen.

## Removing a plugin

Plugins can be removed via the AppStore.

You can also remove a plugin manually by:

1. Deleting it's folder under `~/.signalk/node_modules`
2. Deleting it's entry from `~/.signalk/package.json`
3. Run `npm prune` from the `~/.signalk/` directory.

Alternatively you can:

1. Remove the folder `~/.signalk/node_modules`
2. Run `npm install` from the `~/.signalk/` directory.

Finally you can remove the plugin setting file in `~/.signalk/plugin-config-data/`.

## Examples

Following are links to some published SignalK plugins that serve as an example of working plugins:

- set-system-time
- Ais Reporter

# Processing data from the server

A plugin will generally want to:

1. Subscribe to data published by the server (i.e. received from a NMEA 2000 bus, etc)
2. Emit data.

In both cases the plugin will use deltas which the server uses to signal changes in the Signal K full data model. Delta messages contain the new value associated with a path (not the amount of change from the previous value.)_

See the Signal K Delta Specification for details.

Using the server API, plugins can either:

1. Get the current value of a path in the full model or
2. Subscribe to a path and access a stream of deltas that updates every time the value is updated.

By specifying a context e.g. 'vessels.self' you can limit the number of delta messages received to those of host vesseel. To receive all deltas you can specify `*` as the context.

You can also limit the deltas received by the path you supply. If you supply a specific path e.g. navigation.position, only updates in the value will be received. Since paths are hierarchical, paths can contain wildcards _e.g.navigation.* which will deliver deltas containing updates to all paths under `navigation`.

The data received is formatted as per the following example:

      {
        path: 'navigation.position',
        value: { longitude: 24.7366117, latitude: 59.72493 },
        context: 'vessel.self',
        source: {
            label: 'n2k-sample-data',
            type: 'NMEA2000',
            pgn: 129039,
            src: '43'
        },
        $source: 'n2k-sample-data.43',
        timestamp: '2014-08-15T19:00:02.392Z'
      }

## Reading the current path value

The server API provides the following methods for retrieving values from the full data model.

- `getSelfPath(path)` returns the value of the supplied `path` in the `vessels.self` context.

    const value = app.getSelfPath('uuid');
    app.debug(value); // Should output something like urn:mrn:signalk:uuid:a9d2c3b1-611b-4b00-8628-0b89d014ed60

- `getPath(path)` returns the value of the path (including the context) starting from the root of the full data model.

    const baseStations = app.getPath('shore.basestations');

## Subscribing to Deltas

A can subscribe to a stream of updates (deltas) by creating the subscription.

Subcriptions are generally manged in the plugin `start()` and `stop()` methods to ensure the subscribtions are unsubscribed prior to the plugin stopping to ensure all resources are freed.

The following example illustrates the pattern using the `subscriptionmanager` API method.

    let unsubscribes = [];

    plugin.start = (options, restartPlugin) => {
      app.debug('Plugin started');
      let localSubscription = {
        context: '*', // Get data for all contexts
        subscribe: [{
          path: '*', // Get all paths
          period: 5000 // Every 5000ms
        }]
      };

      app.subscriptionmanager.subscribe(
        localSubscription,
        unsubscribes,
        subscriptionError => {
          app.error('Error:' + subscriptionError);
        },
        delta => {
          delta.updates.forEach(u => {
            app.debug(u);
          });
        }
      );
    };

    plugin.stop = () => {
      unsubscribes.forEach(f => f());
      unsubscribes = [];
    };

In the `start()` method create a subscription definition `localSubscription` which is then passed to `app.subscriptionmanager.subscribe()` as the first argument, we also pass the `unsubscribes` array in the second argument.

The third argument is a function that will be called when there's an error.

The final argument is a function that will be called every time an update is received.

In the `stop()` method each subcription in the `unsubscribes` array is unsubscribed and the resources released.

## Sending Deltas

A SignalK plugin can not only read deltas, but can also send them. This is done using the `handleMessage()` API method and supplying:

1. The plugin id
2. A formatted delta update message
3. The Signal K version ['v1' or 'v2'] (if omitted the default is 'v1'). See REST APIs for details.

Example:

    app.handleMessage(
        plugin.id,
        {
            updates: [{
                values: [{
                    path: 'environment.outside.temperature',
                    value: -253
                }]
            }]
        },
        'v1'
      );

## Sending NMEA 2000 data from a plugin

A SignalK plugin can not only emit deltas, but can also send data such as NMEA 2000 data.

This is done using the `emit()` API and specifying the provider as well as the formatted data to send.

Example: Send NMEA using Actisense serial format:

      app.emit(
        'nmea2000out',
        '2017-04-15T14:57:58.468Z,0,262384,0,0,14,01,0e,00,88,b6,02,00,00,00,00,00,a2,08,00');

Example: Send NMEA using Canboat JSON format:

      app.emit('nmea2000JsonOut', {
        pgn: 130306,
        'Wind Speed': speed,
        'Wind Angle': angle < 0 ? angle + Math.PI*2 : angle,
        'Reference': "Apparent"
      });

### Sending a message on NMEA2000 startup

If you need to send an NMEA2000 message out at startup, e.g get current state from a device you will need to wait until the provider is ready before sending your message.

Example: Send NMEA after the provider is ready:

      app.on('nmea2000OutAvailable', () => {
         app.emit(
           'nmea2000out',
           '2017-04-15T14:57:58.468Z,2,6,126720,%s,%s,4,a3,99,01,00');
      });

# Server API for plugins

SignalK server provides an interface to allow plugins to:

- Discover Features.
- Access / update the full data model
- send / receive deltas (updates)
- Interact with APIs
- Expose HTTP endpoints

These functions are available via the `app` object passed to the plugin when it is invoked.

### Discover Features

#### `app.getFeatures(enabed)`

Returns an object detailing the available APIs and Plugins.

The `enabled` parameter is optional and has the following values:

- `undefined` (not provided): list all features
- `true`: list only enabled features
- `false`: list only disabled features

Example:

    let features = app.getFeatures();

    {
      "apis": [
        "resources","course"
      ],
      "plugins": [
        {
          "id": "anchoralarm",
          "name": "Anchor Alarm",
          "version": "1.13.0",
          "enabled": true
        },
        {
          "id": "autopilot",
          "name": "Autopilot Control",
          "version": "1.4.0",
          "enabled": false
        },
        {
          "id": "sk-to-nmea2000",
          "name": "Signal K to NMEA 2000",
          "version": "2.17.0",
          "enabled": false
        },
        {
          "id": "udp-nmea-sender",
          "name": "UDP NMEA0183 Sender",
          "version": "2.0.0",
          "enabled": false
        }
      ]
    }

### Accessing the Data Model

#### `app.getPath(path)`

Returns the entry for the provided path starting from the `root` of the full data model.

Example:

    let baseStations = app.getPath('shore.basestations');

    // baseStations:
    {
      'urn:mrn:imo:mmsi:2766140': {
        url: 'basestations',
        navigation: { position: {latitude: 45.2, longitude: 76.4} },
        mmsi: '2766140'
      },
      'urn:mrn:imo:mmsi:2766160': {
        url: 'basestations',
        navigation: { position: {latitude: 46.9, longitude: 72.22} },
        mmsi: '2766160'
      }
    }

#### `app.getSelfPath(path)`

Returns the entry for the provided path starting from `vessels.self` in the full data model.

Example:

    let uuid = app.getSelfPath('uuid');
    // Note: This is synonymous with app.getPath('vessels.self.uuid')

    app.debug(uuid);
    // urn:mrn:signalk:uuid:a9d2c3b1-611b-4b00-8628-0b89d014ed60

#### `app.registerPutHandler(context, path, callback, source)`

Register a handler to action `PUT` requests for a specific path.

The action handler can handle the request synchronously or asynchronously.

The `callback` parameter should be a function which accepts the following arguments:

- `context`
- `path`
- `value`
- `callback`

For synchronous actions, the handler must return a value describing the response of the request:

    {
      state: 'COMPLETED',
      statusCode: 200
    }

or

    {
     state:'COMPLETED',
     statusCode: 400,
     message:'Some Error Message'
    }

The `statusCode` value can be any valid HTTP response code.

For asynchronous actions, that may take considerable time to complete and the requester should not be kept waiting for the result, the handler must return:

    { state: 'PENDING' }

When the action has completed the handler should call the `callback` function with the result:

    callback({ state: 'COMPLETED', statusCode: 200 })

or

    callback({
      state:'COMPLETED',
      statusCode: 400,
      message:'Some Error Message'
    })

Example: Synchronous response:

    function myActionHandler(context, path, value, callback) {
      if(doSomething(context, path, value)){
        return { state: 'COMPLETED', statusCode: 200 };
      } else {
        return { state: 'COMPLETED', statusCode: 400 };
      }
    }

    plugin.start = (options) => {
      app.registerPutHandler('vessels.self', 'some.path', myActionHandler, 'somesource.1');
    }

Example: Asynchronous response:

    function myActionHandler(context, path, value, callback) {

      doSomethingAsync(context, path, value, (result) =>{
        if(result) {
          callback({ state: 'COMPLETED', result: 200 })
        } else {
          callback({ state: 'COMPLETED', result: 400 })
        }
      });

      return { state: 'PENDING' };
    }

    plugin.start = (options) => {
      app.registerPutHandler('vessels.self', 'some.path', myActionHandler);
    }

### Working with Deltas

#### `app.handleMessage(pluginId, delta, skVersion = 'v1')`

Emit a delta message.

Note: These deltas are handled by the server in the same way as any other incoming deltas.

Example:

    app.handleMessage('my-signalk-plugin', {
      updates: [
        {
          values: [
            {
              path: 'navigation.courseOverGroundTrue',
              value: 1.0476934
            }
          ]
        }
      ]
    });

Plugins emitting deltas that use Signal K v2 paths (like the Course API paths) should call `handleMessage` with the optional `skVersion` parameter set to `v2`. This prevents v2 API data getting mixed in v1 paths' data in full data model & the v1 http API.

Omitting the `skVersion` parameter will cause the delta to be sent as `v1`.

#### `app.streambundle.getBus(path)`

Get a Bacon JS stream for a Signal K path that will stream values from any context.

The `path` parameter is optional. If it is not provided the returned stream produces values for all paths.

Stream values are objects with the following structure:

      {
        path: ...,
        value: ...,
        context: ...,
        source: ...,
        $source: ...,
        timestamp: ...
      }

Example:

    app.streambundle
      .getBus('navigation.position')
      .forEach(pos => app.debug(pos));

    // output
    {
      path: 'navigation.position',
      value: { longitude: 24.7366117, latitude: 59.72493 },
      context: 'vessels.urn:mrn:imo:mmsi:2766160',
      source: {
        label: 'n2k-sample-data',
        type: 'NMEA2000',
        pgn: 129039,
        src: '43'
      },
      '$source': 'n2k-sample-data.43',
      timestamp: '2014-08-15T19:00:02.392Z'
    }
    {
      path: 'navigation.position',
      value: { longitude: 24.82365, latitude: 58.159598 },
      context: 'vessels.urn:mrn:imo:mmsi:2766140',
      source: {
        label: 'n2k-sample-data',
        type: 'NMEA2000',
        pgn: 129025,
        src: '160'
      },
      '$source': 'n2k-sample-data.160',
      timestamp: '2014-08-15T19:00:02.544Z'
    }

#### `app.streambundle.getSelfBus(path)`

Get a Bacon JS stream for path from the `vessels.self` context.

The `path` parameter is optional. If it is not provided the returned stream contains values for all paths.

Example:

    app.streambundle
      .getSelfBus('navigation.position')
      .forEach(pos => app.debug(pos));

    // output
    {
      path: 'navigation.position',
      value: { longitude: 24.7366117, latitude: 59.72493 },
      context: 'vessels.urn:mrn:signalk:uuid:a9d2c3b1-611b-4b00-8628-0b89d014ed60',
      source: {
        label: 'n2k-sample-data',
        type: 'NMEA2000',
        pgn: 129039,
        src: '43'
      },
      '$source': 'n2k-sample-data.43',
      timestamp: '2014-08-15T19:00:02.392Z'
    }
    {
      path: 'navigation.position',
      value: { longitude: 24.7366208, latitude: 59.7249198 },
      context: 'vessels.urn:mrn:signalk:uuid:a9d2c3b1-611b-4b00-8628-0b89d014ed60',
      source: {
        label: 'n2k-sample-data',
        type: 'NMEA2000',
        pgn: 129025,
        src: '160'
      },
      '$source': 'n2k-sample-data.160',
      timestamp: '2014-08-15T19:00:02.544Z'
    }

#### `app.streambundle.getSelfStream(path)`

Get a Bacon JS stream for a path in the `vessels.self` context.

The `path` argument is optional. If it is not provided the returned stream produces values for all paths.

Note: This is similar to `app.streambundle.getSelfBus(path)`, except that the stream values contain only the `value` property from the incoming deltas.

Example:

    app.streambundle
      .getSelfStream('navigation.position')
      .forEach(pos => app.debug(pos));

    // output

      my-signalk-plugin { longitude: 24.736677, latitude: 59.7250108 } +600ms
      my-signalk-plugin { longitude: 24.736645, latitude: 59.7249883 } +321ms
      my-signalk-plugin { longitude: 24.7366563, latitude: 59.7249807 } +174ms
      my-signalk-plugin { longitude: 24.7366563, latitude: 59.724980699999996 } +503ms

#### `app.streambundle.getAvailablePaths()`

Get a list of available full data model paths maintained by the server.

Example:

    app.streambundle.getAvailablePaths();

    // returns
    [
      "navigation.speedOverGround",
      "navigation.courseOverGroundTrue",
      "navigation.courseGreatCircle.nextPoint.position",
      "navigation.position",
      "navigation.gnss.antennaAltitude",
      "navigation.gnss.satellites",
      "navigation.gnss.horizontalDilution",
      "navigation.gnss.positionDilution",
      "navigation.gnss.geoidalSeparation",
      "navigation.gnss.type","navigation.gnss.methodQuality",
      "navigation.gnss.integrity",
      "navigation.magneticVariation",
    ]

#### `app.registerDeltaInputHandler ((delta, next) => {} )`

Register a function to intercept all delta messages before they are processed by the server.

The callback function should call `next(delta)` with either:

- A modified delta (if it wants to alter the incoming delta)
- With the original delta to process it normally.

Note: Not calling `next(delta)` will cause the incoming delta to be dropped and will only show in delta statistics.

Other, non-delta messages produced by provider pipe elements are emitted normally.

    app.registerDeltaInputHandler((delta, next) => {
      delta.updates.forEach(update => {
        update.values.forEach(pathValue => {
          if(pathValue.startsWith("foo")) {
            pathValue.path = "bar"
          }
        })
      })
      next(delta)
    });

### Configuration

#### `app.savePluginOptions(options, callback)`

Save changes to the plugin's configuration options.

Example:

    let options = {
      myConfigValue = 'Something the plugin calculated'
    };

    app.savePluginOptions(options, () => {app.debug('Plugin options saved')});

#### `app.readPluginOptions()`

Read the stored plugin configuration options.

Example:

    let options = app.readPluginOptions();

#### `app.getDataDirPath()`

Returns the full path of the directory where the plugin can persist its internal data, e.g. data files, etc.

Example:

    let myDataFile = require('path').join( app.getDataDirPath(), 'somedatafile.ext')

### Messages and Debugging

#### `app.setPluginStatus(msg)`

Set the current status of the plugin that is displayed in the plugin configuration UI and the Dashboard.

The `msg` parameter should be a short text message describing the current status of the plugin.

Example:

    app.setPluginStatus('Initializing');
    // Do something
    app.setPluginStatus('Done initializing');

Note: Replaces deprecated `setProviderStatus()`

#### `app.setPluginError(msg)`

Set the current error status of the plugin that is displayed in the plugin configuration UI and the Dashboard.

The `msg` parameter should be a short text message describing the current status of the plugin.

Example:

    app.setPluginError('Error connecting to database');

Note: Replaces deprecated `setProviderError()`

#### `app.debug(...)`

Log debug messages.

This function exposes the `debug` method from the debug module. The npm module name is used as the debug name.

`app.debug()` can take any type and will serialize it before outputting.

_Note: Do not use `debug` from the debug module directly! Using `app.debug()`provided by the server ensures that the plugin taps into the server's debug logging system, including the helper switches in Admin UI's Server Log page.

#### `app.error(message)`

Report errors in a human-oriented message. Currently just logs the message, but in the future error messages hopefully will show up in the admin UI.

#### `reportOutputMessages(count)`

Report to the server that the plugin has sent data to other hosts so it can be displayed on the Dashboard.

Note: This function is for use when the plugin is sending data to hosts other than the Signal K server (e.g. network packets, http requests or messages sent to a broker).

This function should NOT be used for deltas that the plugin sends with `handleMessage()`!

The `count` parameter is optional and represents the number of messages sent between this call the previous call. If omitted the call will count as one output message.

Example:

    app.reportOutputMessages(54);

### Serial Port

#### `app.getSerialPorts() => Promise<Ports>`

This returns a Promise which will resolve to a Ports object which contains information about the serial ports available on the machine.

### Resources API Interface

#### `app.registerResourceProvider(ResourceProvider)`

Used by Resource Provider plugins to register each resource type it handles.

See `Resource Provider Plugins` for details.

#### `app.resourcesApi.getResource(resource_type, resource_id, provider_id?)`

Retrieve the resource with the supplied SignalK resource_type and resource_id.

Note: Requires a registered Resource Provider for the supplied `resource_type`.

- `resource_type`: Any Signal K (i.e. `routes`,`waypoints`, `notes`, `regions` & `charts`) or user defined resource types.

- `resource_id`: The resource identifier. (e.g. `ac3a3b2d-07e8-4f25-92bc-98e7c92f7f1a`)

- `provider_id` (optional): The id of the Resource Provider plugin to use to complete the request. Most commonly used for creating a new resource entry when more than one provider is registered for the specified resource type.

- returns: `Promise<any>` Promise for the resource.

Example:

    app.resourcesApi.getResource(
      'waypoints',
      'ac3a3b2d-07e8-4f25-92bc-98e7c92f7f1a'
      }
    ).then ( () => {
      // success
      ...
    }).catch (error) {
      // handle error
      console.log(error.message);
      ...
    }

#### `app.resourcesApi.setResource(resource_type, resource_id, resource_data, provider_id?)`

Create / update value of the resource with the supplied SignalK resource_type and resource_id.

Note: Requires a registered Resource Provider for the supplied `resource_type`.

- `resource_type`: Any Signal K (i.e. `routes`,`waypoints`, `notes`, `regions` & `charts`) or user defined resource types.

- `resource_id`: The resource identifier. (e.g. `ac3a3b2d-07e8-4f25-92bc-98e7c92f7f1a`)

- `resource_data`: A complete and valid resource record.

- `provider_id` (optional): The id of the Resource Provider plugin to use to complete the request. Most commonly used for creating a new resource entry when more than one provider is registered for the specified resource type.

- returns: `Promise<void>`

Example:

    app.resourcesApi.setResource(
      'waypoints',
      'ac3a3b2d-07e8-4f25-92bc-98e7c92f7f1a',
      {
        "name": "My Waypoint",
        "feature": {
          "type":"Feature",
          "geometry": {
            "type": "Point",
            "coordinates": [138.5, -38.6]
          },
          "properties":{}
        }
      }
    ).then ( () => {
      // success
      ...
    }).catch (error) {
      // handle error
      console.log(error.message);
      ...
    }

#### `app.resourcesApi.deleteResource(resource_type, resource_id, provider_id?)`

Delete the resource with the supplied SignalK resource_type and resource_id.

Note: Requires a registered Resource Provider for the supplied `resource_type`.

- `resource_type`: Any Signal K (i.e. `routes`,`waypoints`, `notes`, `regions` & `charts`) or user defined resource types.

- `resource_id`: The resource identifier. (e.g. `ac3a3b2d-07e8-4f25-92bc-98e7c92f7f1a`)

- `provider_id` (optional): The id of the Resource Provider plugin to use to complete the request.

- returns: `Promise<void>`

Example:

    app.resourcesApi.deleteResource(
      'notes',
      'ac3a3b2d-07e8-4f25-92bc-98e7c92f7f1a'
    ).then ( () => {
      // success
      ...
    }).catch (error) {
      // handle error
      console.log(error.message);
      ...
    }

#### `app.resourcesApi.listResources(resource_type, params, provider_id?)`

Retrieve collection of resource entries of the supplied resource_type matching the provided criteria.

Note: Requires a registered Resource Provider for the supplied `resource_type`.

- `resource_type`: Any Signal K (i.e. `routes`,`waypoints`, `notes`, `regions` & `charts`) or user defined resource types.

- `params`: Object contining `key | value` pairs repesenting the crteria by which to filter the returned entries.

- `provider_id` (optional): The id of the Resource Provider plugin to use to complete the request.

Note: The registered Resource Provider must support the supplied parameters for results to be filtered.

- returns: `Promise<{[key: string]: any}>`

Example:

    app.resourcesApi.listResources(
      'waypoints',
      {region: 'fishing_zone'}
    ).then (data => {
      // success
      console.log(data);
      ...
    }).catch (error) {
      // handle error
      console.log(error.message);
      ...
    }

### Course API Interface

The `Course API` provides the following functions for use by plugins.

#### `app.getCourse()`

Retrieves the current course information.

- returns: Resolved Promise on success containing the same course information returned by the `/course` API endpoint.

#### `app.clearDestination()`

Cancels navigation to the current point or route being followed.

- returns: Resolved Promise on success.

#### `app.setDestination(dest)`

Set course to a specified position / waypoint.

- `dest`: Object containing destination position information as per `/course/destination`.

- returns: Resolved Promise on success.

#### `app.activateRoute(rte)`

Follow a route. in the specified direction and starting at the specified point.

- `rte`: Object containing route information as per `/course/activeRoute`.

- returns: Resolved Promise on success.

### PropertyValues

The PropertyValues mechanism provides a means for passing configuration type values between different components running in the server process such as plugins and input connections.

A plugin can both emit values and listen for values emitted by others.

The difference between the PropertyValues mechanism and Event Emitters in NodeJs is that when `onPropertyValues` is called, the `callback()` function will be invoked and passed an array containing all of the previous values for that property name, starting with the initial value of `undefined`. If no values have been emitted for that property name the callback will be invoked with a value of `undefined`.

    app.emitPropertyValue: (name: string, value: any) => void

    onPropertyValues: (
      name: string,
      callback: (propValuesHistory: PropertyValue[]) => void
    ) => Unsubscribe

PropertyValue has the following structure:

    interface PropertyValue {
      timestamp: number // millis
      setter: string // plugin id, server, provider id
      name: string
      value: any
    }

Note that the value can be also a function.

This mechanism allows plugins to offer extensions via "Well Known Properties", for example

- additional NMEA0183 sentence parsers for custom sentences via `nmea0183sentenceParser`
- additional PGN definitions for propietary or custom PGNs

Code handling incoming PropertyValues should be fully reactive due to:

- Plugins being able to emit PropertyValues when they activated and / or started
- There being no defined load / startup order for plugins / connections.

So even if all plugins / connections emit during their startup, you cannot depend on a specific PropertyValue being available. It may be present when your code starts or it may arrive after your code has started.

Note: The PropertyValues mechanism is not intended to be used for data passing on a regular basis, as the total history makes it a potential memory leak.

To safeguard against a component accidentally emitting regularly, via a fixed upper bound is enforced for the value array per property name. New values will be ignored if the upper bound is reached and are logged as errors.

### Exposing custom HTTP paths & OpenApi

Plugins are able to provide an API via a function called `registerWithRouter(router)`, which like the plugin's `start` and `stop` functions, will be called during plugin startup with an Express router as the parameter.

The router will be mounted at `/plugins/<pluginId>` and you can use standard Express (`.get()` `.post()` `.use()`, etc) methods to add HTTP path handlers.

Note: `GET /plugins/<pluginid>` and `POST /plugins/<pluginid>/configure` are reserved by server (see below).

It should be noted that Express does not have a public API for deregistering subrouters, so `stop` does not do anything to the router.

If a plugin does provide an API, it is strongly recommended that it provide an OpenApi description to document its operation.

Doing so promotes interoperability with other plugins / webapps by making it easy to find and use the functionality built into plugins. It is also a means to avoid duplication, promote reuse and the possibility of including them in the Signal K specification.

See Server Plugins for details.

### Plugin configuration HTTP API

#### `GET /plugins/`

Get a list of installed plugins and their configuration data.

#### `GET /plugins/<pluginid>`

Get information from an installed plugin.

Example result:

    {
      "enabled": false,
      "id": "marinetrafficreporter",
      "name": "Marine Traffic Reporter"
    }

#### `POST /plugins/<pluginid>/configure`

Save configuration data for a plugin. Stops and starts the plugin as a side effect.

# Resource Provider plugins

## Overview

The Signal K server Resource API provides a common set operations for clients to interact with routes, waypoints, charts, etc but it does NOT provide the ability to persist or retrieve resources to / from storage.

This functionality needs to be provided by one or more server plugins that interface with the Resource API to facilitate the storage and retrieval of resource data.

These plugins are called Provider Plugins.

Resource API architecture:

This de-coupling of request handling and data storage provides the flexibility to persist resource data in a variety of different storage types as well as Internet based services.

Note: Signal K server comes with the resources-provider-plugin pre-installed which persists resource data to the local file system.

### Resources API:

The Resources API handles all client requests received via the `/signalk/v2/api/resources` path, before passing on the request to registered provider plugin(s).

The Resources API performs the following operations when a request is received:

1. Checks for registered provider(s) for the resource type (i.e. route, waypoint, etc.)
2. Checks that the required ResourceProvider methods are defined for the requested operation (i.e. POST, PUT, GET, DELETE)
3. Performs an access control check
4. `POST` and `PUT` requests for Standard (Signal K defined) resource types are checked for validity of the submitted:

- `resource id`
- `resource data` against the OpenAPI definition.

Only after successful completion of all these operations is the request passed on to the registered provider plugin(s).

## Provider plugins:

A resource provider plugin is a Signal K server plugin that implements the Resource Provider Interface which:

- Tells server the resource type(s) provided for by the plugin (i.e. route, waypoint, etc.)
- Registers the methods used to action requests passed from the server and perform the writing, retrieval and deletion of resources from storage.

Note: multiple providers can be registered for a resource type (e.g. 2 x chart providers)

The `ResourceProvider` interface is defined as follows in `@signalk/server-api`:

    interface ResourceProvider {
      type: ResourceType
      methods: ResourceProviderMethods
    }

where:

- `type`: The resource type provided for by the plugin. These can be either Standard (Signal K defined) or Custom (user defined) resource types (e.g. `'routes'`, `'fishingZones'`)

- `methods`: An object implementing the `ResourceProviderMethods` interface defining the functions to which resource requests are passed by the SignalK server. Note: The plugin MUST implement each method, even if that operation is NOT supported by the plugin!

The `ResourceProviderMethods` interface is defined as follows in `@signalk/server-api`:

    interface ResourceProviderMethods {
      listResources: (query: { [key: string]: any }) => Promise<{[id: string]: any}>
      getResource: (id: string, property?: string) => Promise<object>
      setResource: (
        id: string,
        value: { [key: string]: any }
      ) => Promise<void>
      deleteResource: (id: string) => Promise<void>
    }

Note: The Resource Provider is responsible for implementing the methods and returning data in the required format!

### Provider Methods:

`listResources(query)`: This method is called when a request is made for resource entries that match a specific criteria.

Note: It is the responsibility of the resource provider plugin to filter the resources returned as per the supplied query parameters.

- `query:` Object contining `key | value` pairs repesenting the parameters by which to filter the returned entries. e.g. {region: 'fishing_zone'}

returns: `Promise<{[id: string]: any}>`

Example: Return waypoints within the bounded area with lower left corner at E5.4 N25.7 & upper right corner E6.9 & N31.2:

    GET /signalk/v2/api/resources/waypoints?bbox=[5.4,25.7,6.9,31.2]

ResourceProvider method invocation:

    listResources(
      {
        bbox: '5.4,25.7,6.9,31.2'
      }
    );

Returns:

    {
      "07894aba-f151-4099-aa4f-5e5773734b69": {
        "name":"my Point",
        "description":"A Signal K waypoint",
        "distance":124226.65183615577,
        "feature":{
          "type":"Feature",
          "geometry":{
            "type":"Point",
            "coordinates":[5.7,26.4]
          },
          "properties":{}
        },
        "timestamp":"2023-01-01T05:02:54.561Z",
        "$source":"resources-provider"
      },
      "0c894aba-d151-4099-aa4f-be5773734e99": {
        "name":"another point",
        "description":"Another Signal K waypoint",
        "distance":107226.84,
        "feature":{
          "type":"Feature",
          "geometry":{
            "type":"Point",
            "coordinates":[6.1,29.43]
          },
          "properties":{}
        },
        "timestamp":"2023-01-01T05:02:54.561Z",
        "$source":"resources-provider"
      }
    }

`getResource(id, property?)`: This method is called when a request is made for a specific resource entry with the supplied `id`. If `property` is supplied then the value of the resource property is returned. If there is no resource associated with the id the call should return Promise.reject.

- `id`: String containing the target resource entry id. (e.g. '07894aba-f151-4099-aa4f-5e5773734b99')
- `property` (optional): Name of resource property for which to return the value (in dot notation). e.g. feature.geometry.coordinates

returns: `Promise<object>`

Example resource request:

    GET /signalk/v2/api/resources/routes/07894aba-f151-4099-aa4f-5e5773734b99

ResourceProvider method invocation:

    getResource(
      '07894aba-f151-4099-aa4f-5e5773734b99'
    );

Returns:

    {
      "name":"myRoute",
      "description":"A Signal K route",
      "distance":124226.65183615577,
      "feature":{
        "type":"Feature",
        "geometry":{
          "type":"LineString",
          "coordinates":[[-8,-8],[-8.5,-8],[-8.5,-8.4],[-8.7,-8.3]]
        },
        "properties":{}
      },
      "timestamp":"2023-01-01T05:02:54.561Z",
      "$source":"resources-provider"
    }

Example resource property value request:

    GET /signalk/v2/api/resources/routes/07894aba-f151-4099-aa4f-5e5773734b99/feature/geometry/type

ResourceProvider method invocation:

    getResource(
      '07894aba-f151-4099-aa4f-5e5773734b99',
      'feature.geometry.type'
    );

Returns:

    {
      "value": "LineString",
      "timestamp":"2023-01-01T05:02:54.561Z",
      "$source":"resources-provider"
    }

`setResource(id, value)`: This method is called when a request is made to save / update a resource entry with the supplied id. The supplied data is a complete resource record.

- `id:` String containing the id of the resource entry created / updated. e.g. '07894aba-f151-4099-aa4f-5e5773734b99'

- `value:` Resource data to be stored.

returns: `Promise<void>`

Example PUT resource request:

    PUT /signalk/v2/api/resources/routes/07894aba-f151-4099-aa4f-5e5773734b99 {resource_data}

ResourceProvider method invocation:

    setResource(
      '07894aba-f151-4099-aa4f-5e5773734b99',
      {
        name: 'test route',
        distance': 8000,
        feature: {
          type: 'Feature',
          geometry: {
            type: 'LineString',
            coordinates: [[138.5, -38.6], [138.7, -38.2], [138.9, -38.0]]
          },
          properties:{}
        }
      }
    );

Example POST resource request:

    POST /signalk/v2/api/resources/routes {resource_data}

ResourceProvider method invocation:

    setResource(
      '<server_generated_id>',
      {
        name: 'test route',
        distance': 8000,
        feature: {
          type: 'Feature',
          geometry: {
            type: 'LineString',
            coordinates: [[138.5, -38.6], [138.7, -38.2], [138.9, -38.0]]
          },
          properties:{}
        }
      }
    );

`deleteResource(id)`: This method is called when a request is made to remove the specific resource entry with the supplied resource id.

- `id:` String containing the target resource entry id. e.g. '07894aba-f151-4099-aa4f-5e5773734b99'

returns: `Promise<void>`

Example resource request:

    DELETE /signalk/v2/api/resources/routes/07894aba-f151-4099-aa4f-5e5773734b99

ResourceProvider method invocation:

    deleteResource(
      '07894aba-f151-4099-aa4f-5e5773734b99'
    );

### Registering as a Resource Provider:

To register a plugin as a provider for one or more resource types with the SignalK server, it must call the server's `registerResourceProvider` function for each resource type being serviced during plugin startup.

The function has the following signature:

    app.registerResourceProvider(resourceProvider: ResourceProvider)

where:

- `resourceProvider`: is a reference to a `ResourceProvider` object containing the resource type and methods to receive the requests.

Note: More than one plugin can be registered as a provider for a resource type.

Example: Plugin registering as a routes & waypoints provider.

    import { ResourceProvider } from '@signalk/server-api'

    module.exports = function (app) {

      const plugin = {
        id: 'mypluginid',
        name: 'My Resource Providerplugin'
      }

      const routesProvider: ResourceProvider = {
          type: 'routes',
          methods: {
            listResources: (params) => {
              fetchRoutes(params)
              ...
            },
            getResource: (id, property?) => {
              getRoute(id, property)
              ...
            },
            setResource: (id, value )=> {
              saveRoute(id, value)
              ...
            },
            deleteResource: (id) => {
              deleteRoute(id, value)
              ...
            }
          }
        }

      const waypointsProvider: ResourceProvider = {
          type: 'waypoints',
          methods: {
            listResources: (params) => {
              fetchWaypoints(params)
              ...
            },
            getResource: (id, property?) => {
              getWaypoint(id, property)
              ...
            },
            setResource: (id, value )=> {
              saveWaypoint(id, value)
              ...
            },
            deleteResource: (id) => {
              deleteWaypoint(id, value)
              ...
            }
          }
        }

      plugin.start = function(options) {
        ...
        try {
          app.registerResourceProvider(routesProvider)
          app.registerResourceProvider(waypointsProvider)
        }
        catch (error) {
          // handle error
        }
      }

      return plugin
    }

### Methods

A Resource Provider plugin must implement ALL methods to service the requests passed from the server.

Each method should return a Promise on success and `throw` on error, if a request is not serviced or is not implemented.

Example:

    // SignalK server plugin
    module.exports = function (app) {

      const plugin = {
        id: 'mypluginid',
        name: 'My Resource Providerplugin',
        start: options => {
          ...
          app.registerResourceProvider({
            type: 'waypoints',
            methods: {
              listResources: (params) => {
                return new Promise( (resolve, reject) => {
                  ...
                  if (ok) {
                    resolve(resource_list)
                  } else {
                    reject( new Error('Error fetching resources!'))
                  }
                })
              },
              getResource: (id, property?) => {
                return new Promise( (resolve, reject) => {
                  ...
                  if (ok) {
                    resolve(resource_list)
                  } else {
                    reject( new Error('Error fetching resource with supplied id!'))
                  }
                })
              },
              setResource: (id, value )=> {
                throw( new Error('Not implemented!'))
              },
              deleteResource: (id) => {
                throw( new Error('Not implemented!'))
              }
            }
          })
        }

      }
    }

# Course Calculations and Providers

The Course API defines the path `/vessels/self/navigation/course/calcValues` to accommodate the calculated values related to course navigation.

These paths are available to be populated by a "course provider" plugin that uses the course information set using the Course API. This approach promotes the extensibility of Signal K server providing flexibility and interoperability. See Course Provider Plugins below.

## Calculated value paths: `calcValues`

The following paths are defined to hold values calculated using the information maintained by Course API operations:

- calcMethod: ("Rhumbline" or "GreatCircle")
- crossTrackError
- bearingTrackTrue
- bearingTrackMagnetic
- estimatedTimeOfArrival (e.g. "2022-04-22T05:02:56.484Z")
- distance
- bearingTrue
- bearingMagnetic
- velocityMadeGood
- timeToGo
- targetSpeed
- previousPoint.distance

Example:

    {
      "calcMethod": "Rhumbline",
      "crossTrackError": 458.784,
      "bearingTrackTrue": 4.58491,
      "bearingTrackMagnetic": 4.51234,
      "estimatedTimeOfArrival": "2022-04-22T05:02:56.484Z",
      "distance": 10157,
      "bearingTrue": 4.58491,
      "bearingMagnetic": 4.51234,
      "velocityMadeGood": 7.2653,
      "timeToGo": 8491,
      "targetSpeed": 2.2653,
      "previousPoint": {
        "distance": 10157
      }
    }

## Course Notifications

Calculated course values that cross a threshold should trigger a notification so that the necessary action can be taken.

The Course API defines the following notifications which should be implemented by a course provider:

- `navigation.course.arrivalCircleEntered`
- `navigation.course.perpendicularPassed`

## Course Provider Plugins

Signal K server includes the `Course Data Provider` plugin as part of the installation to provide out-of-the-box support for course calculations nd notifications.

This plugin can be replaced with others from the AppStore, or your own, to extend the number and types of calculations performed.

If you are looking to develop a course provider plugin, following are the recommended guidlines:

1. Ensure values are generated for ALL the defined paths (above)
2. Values MUST be calculated using `/vessels/self/navigation/course` path values mainntained by the Course API
3. Ensure values are set to null when no destination is set or the value cannot be calculated
4. Perform the calculations using a "worker thread" to minimise impact on the server "main thread"
5. Ensure the worker is set up and shut down as part of plugin "start" and "stop" functions
6. Raise the notifications outlined above.

# 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 <AutopilotInfo> 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!)
        }
    }

# Publishing to The AppStore

Plugins and WebApps are available in the AppStore when they have been published to npm repository with the one or more of the following keywords in the `package.json` file:

- `signalk-node-server-plugin`
- `signalk-webapp`

Additionally you can have your plugin appear within one or more AppStore categories by also adding the following keyword(s):

- `signalk-category-chart-plotters`
- `signalk-category-nmea-2000`
- `signalk-category-nmea-0183`
- `signalk-category-instruments`
- `signalk-category-hardware`
- `signalk-category-ais`
- `signalk-category-notifications`
- `signalk-category-digital-switching`
- `signalk-category-utility`
- `signalk-category-cloud`
- `signalk-category-weather`
- `signalk-category-deprecated`
- `signalk-category-hidden` (won't show on the App Store)

To have your plugin start automatically after being installed, without requiring any configuration via the Plugin Config screen add the following key to the `package.json` file:

    "signalk-plugin-enabled-by-default": true

To control the way your WebApp is displayed in the Admin UI add a `signalk` key with the following attributes:

      "signalk": {
        "appIcon": "./img/icon-72x72.png", // path to an image file to use as an icon.
        "displayName": "My SK App" // name to display in place of the package name.
      }

Example: package.json

    {
      "name": "my-signalk-plugin-app",
      "version": "1.0.0",
      "description": "My great signalk plugin-app",
      "keywords": [
        "signalk-node-server-plugin",
        "signalk-webapp",
        "signalk-category-ais"
      ],
      "signalk-plugin-enabled-by-default": true,
      "signalk": {
        "appIcon": "./assets/icons/icon-72x72.png",
        "displayName": "My Great WebApp"
      },
      "main": "plugin/index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "author": "",
      "license": "ISC"
    }

#### Publishing your Plugin

Once you have developed and tested your Plugin / WebApp you can publish it to make it visible in the AppStore. To do this, in a terminal session from within the folder containing `package.json`:

    npm publish

# REST APIs

REST APIs were introduced in Signal K server version 2 to provide a way for applications and plugins perform operations and ensure that the Signal K data model is consistent.

The OpenAPI definitions can be found under Documentation -> OpenAPI in the server Admin UI.

### APIs available in Signal K server v2.0.0 and later:

APIs are available via `/signalk/v2/api/<endpoint>`

API | Description | Endpoint
--- | --- | ---
Course | Set a course, follow a route, advance to next point, etc. | `vessels/self/navigation/course`
Resources | Create, view, update and delete waypoints, routes, etc. | `resources`
`Autopilot` | Provide the ability to send common commands to an autopilot via a provider plugin. | `vessels/self/autopilot`

#### Following is a list of proposed APIs for implementation:

Proposed API | Description | Endpoint
--- | --- | ---
`Notifications` | Provide the ability to raise, update and clear notifications from multiple sources. View PR | `notifications`
`Anchor` | Provide endpoints to perform operations and facilitate an anchor alarm. | `vessels/self/navigation/anchor`

# Working with the Course API

## Overview

The Course API provides common course operations under the path `/signalk/v2/api/vessels/self/navigation/course` ensuring that all related Signal K data model values are maintained and consistent. This provides a set of data that can be confidently used for course calculations and autopilot operation.

Additionally, the Course API persists course information on the server to ensure data is not lost in the event of a server restart.

Client applications use `HTTP` requests (`PUT`, `GET`,`DELETE`) to perform operations and retrieve course data.

The Course API also listens for destination information in the NMEA stream and will set / clear the destination accordingly (e.g. NMEA0183 RMB sentence, NMEA2000 PGN 129284). See Configuration for more details.

Note: You can view the Course API OpenAPI definition in the Admin UI (Documentation => OpenApi).

## Setting a Course

The Course API provides endpoints for:

1. Navigate to a location (lat, lon)
2. Navigate to a waypoint (href to waypoint resource)
3. Follow a Route (href to a route resource).

### 1. Navigate to a Location

To navigate to a point submit a HTTP `PUT` request to `/signalk/v2/api/vessels/self/navigation/course/destination` and supply the latitude & longitude of the destination point.

    HTTP PUT 'http://hostname:3000/signalk/v2/api/vessels/self/navigation/course/destination' {"position": {"latitude": -60.5, "longitude": -166.7}}

### 2. Navigate to a Waypoint

To navigate to a point submit a HTTP `PUT` request to `/signalk/v2/api/vessels/self/navigation/course/destination` and supply a reference to a waypoint resource entry under `/resources/waypoints`

    HTTP PUT 'http://hostname:3000/signalk/v2/api/vessels/self/navigation/course/destination' {"href": "/resources/waypoints/5242d307-fbe8-4c65-9059-1f9df1ee126f"}

### 3. Follow a Route

To follow a route submit a HTTP `PUT` request to `/signalk/v2/api/vessels/self/navigation/course/activeRoute` and supply a reference to a route resource entry under `/resources/routes`.

    HTTP PUT 'http://hostname:3000/signalk/v2/api/vessels/self/navigation/course/activeRoute' {"href": "/resources/routes/5242d307-fbe8-4c65-9059-1f9df1ee126f"}

Additional parameters can be set when following a route including:

- Defining the point along the route to start at
- The direction to follow the route (forward / reverse)

Example: Following a route in reverse direction:

    HTTP PUT 'http://hostname:3000/signalk/v2/api/vessels/self/navigation/course/activeRoute'
    {
      "href": "/resources/routes/5242d307-fbe8-4c65-9059-1f9df1ee126f",
      "reverse": true
    }

#### Advancing along a Route

As progress along a route is made, you can use the following endpoints to update the destination.

To set the destination to the next point along the route:

    HTTP PUT 'http://hostname:3000/signalk/v2/api/vessels/self/navigation/course/activeRoute/nextPoint'

To advance the destination to a point `n` places beyond the current destination point, supply a positive number representing the number of points to advance:

    HTTP PUT 'http://hostname:3000/signalk/v2/api/vessels/self/navigation/course/activeRoute/nextPoint' {"value": 2}

Sets destination to the point after the next in sequence.

To set the destination to the previous point along the route:

    HTTP PUT 'http://hostname:3000/signalk/v2/api/vessels/self/navigation/course/activeRoute/nextPoint' {"value": -1}

To set the destination to a point `n` places prior the current destination point, supply a negative number representing the number of points prior:

    HTTP PUT 'http://hostname:3000/signalk/v2/api/vessels/self/navigation/course/activeRoute/nextPoint' {"value": -2}

Sets destination to the point two prior to the current destination.

To set the destination to a specific point along the route, supply the zero-based index of the point:

Example: 4th point along the route.

    HTTP PUT 'http://hostname:3000/signalk/v2/api/vessels/self/navigation/course/activeRoute/pointIndex' {"value": 3}

Value contains the 'zero-based' index of the point along the route (i.e. 0 = 1st point, 1 = 2nd point, etc.)

To reverse the direction along the route:

    HTTP PUT 'http://hostname:3000/signalk/v2/api/vessels/self/navigation/course/activeRoute/reverse'

#### Delta Messages

The Course API emits delta messages with the following paths when course information has been changed.

Note: Delta values reflect the relevant property of the Course Information data object as detailed in the Retrieving Course Information section.

- `navigation.course.startTime`
- `navigation.course.targetArrivalTime`
- `navigation.course.arrivalCircle`
- `navigation.course.activeRoute`
- `navigation.course.nextPoint`
- `navigation.course.previousPoint`

## Retrieving Course Information

Course information is retrieved by submitting a HTTP `GET` request to `/signalk/v2/api/vessels/self/navigation/course`.

    HTTP GET 'http://hostname:3000/signalk/v2/api/vessels/self/navigation/course'

The contents of the response will reflect the operation used to set the current course. The `nextPoint` & `previousPoint` sections will always contain values but `activeRoute` will only contain values when a route is being followed.

#### 1. Operation: Navigate to a location (lat, lon)

Example response:

    {
      "startTime": "2023-01-27T01:47:39.785Z",
      "targetArrivalTime": "2022-06-10T01:29:27.592Z",
      "arrivalCircle": 4000,
      "activeRoute": null,
      "nextPoint": {
        "type": "Location",
        "position": {
          "latitude": -34.92084502261776,
          "longitude": 131.54823303222656
        }
      },
      "previousPoint": {
        "type":"VesselPosition",
        "position": {
          "latitude": -34.82084502261776,
          "longitude": 131.04823303222656
        }
      }
    }

#### 2. Operation: Navigate to a waypoint (href to waypoint resource)

Example response:

    {
      "startTime": "2023-01-27T01:47:39.785Z",
      "targetArrivalTime": "2022-06-10T01:29:27.592Z",
      "arrivalCircle": 4000,
      "activeRoute": null,
      "nextPoint": {
        "href": "/resources/waypoints/f24d72e4-e04b-47b1-920f-66b78e7b033e",
        "type": "Waypoint",
        "position": {
          "latitude": -34.92084502261776,
          "longitude": 131.54823303222656
        }
      },
      "previousPoint": {
        "type":"VesselPosition",
        "position": {
          "latitude": -34.82084502261776,
          "longitude": 131.04823303222656
        }
      }
    }

#### 3. Operation: Follow a Route (href to a route resource).

Example response:

    {
      "startTime": "2023-01-27T01:47:39.785Z",
      "targetArrivalTime": "2022-06-10T01:29:27.592Z",
      "arrivalCircle": 1000,
      "activeRoute": {
        "href": "/resources/routes/e24d72e4-e04b-47b1-920f-66b78e7b0331",
        "pointIndex": 0,
        "pointTotal": 5,
        "reverse": false,
        "name": "my route",
        "waypoints": [
          {
            "latitude": -34.92084502261776,
            "longitude": 131.54823303222656
          },
          {
            "latitude": -34.86621482446046,
            "longitude": 132.10166931152344,
          },
          {
            "latitude": -34.6309479733581,
            "longitude": 132.23350524902344
          },
          {
            "latitude": -34.63546778783319,
            "longitude": 131.8867492675781
          },
          {
            "latitude": -34.71000915922492,
            "longitude": 131.82289123535156
          }
        ]
      },
      "nextPoint": {
        "type": "RoutePoint",
        "position": {
          "latitude": -34.92084502261776,
          "longitude": 131.54823303222656
        }
      },
      "previousPoint": {
        "type":"VesselPosition",
        "position": {
          "latitude": -34.82084502261776,
          "longitude": 131.04823303222656
        }
      }
    }

## Cancelling navigation

To cancel the current course navigation and clear the course data.

    HTTP DELETE 'http://hostname:3000/signalk/v2/api/vessels/self/navigation/course'

Note: This operation will NOT change the destination information coming from the NMEA input stream! If the NMEA source device is still emitting destination data this will reappear as the current destination.

To ignore destination data from NMEA sources see Configuration below.

## Configuration

The default configuration of the Course API will accept destination information from both API requests and NMEA stream data sources.

For NMEA sources, Course API monitors the the following Signal K paths populated by both the `nmea0183-to-signalk` and `n2k-to-signalk` plugins:

- navigation.courseRhumbline.nextPoint.position
- navigation.courseGreatCircle.nextPoint.position

HTTP requests are prioritised over NMEA data sources, so making an API request will overwrite the destination information received from and NMEA source.

Note: when the destination cleared using an API request, if the NMEA stream is emitting an active destination position, this will then be used by the Course API to populate course data.

#### Ignoring NMEA Destination Information

The Course API can be configured to ignore destination data in the NMEA stream by enabling `apiOnly` mode.

In `apiOnly` mode destination information can only be set / cleared using HTTP API requests.

- `apiOnly` Mode = Off (default)

  - Destination data is accepted from both HTTP API and NMEA sources
  - Setting a destination using the HTTP API will override the destination data received via NMEA
  - When clearing the destination using the HTTP API, if destination data is received via NMEA this will then be used as the active destination.
  - To clear destination sourced via NMEA, clear the destination on the source device.

- `apiOnly` Mode = On

  - Course operations are only accepted via the HTTP API
  - NMEA stream data is ignored
  - Switching to `apiOnly` mode when an NMEA sourced destination is active will clear the destination.

#### Retrieving Course API Configuration

To retrieve the Course API configuration settings, submit a HTTP `GET` request to `/signalk/v2/api/vessels/self/navigation/course/_config`.

    HTTP GET 'http://hostname:3000/signalk/v2/api/vessels/self/navigation/course/_config'

Example response:

    {
      "apiOnly": false
    }

#### Enable / Disable `apiOnly` mode

To enable `apiOnly` mode, submit a HTTP `POST` request to `/signalk/v2/api/vessels/self/navigation/course/_config/apiOnly`.

Enable apiOnly mode:

    HTTP POST 'http://hostname:3000/signalk/v2/api/vessels/self/navigation/course/_config/apiOnly'

To disable `apiOnly` mode, submit a HTTP `DELETE` request to `/signalk/v2/api/vessels/self/navigation/course/_config/apiOnly`.

Disable apiOnly mode:

    HTTP DELETE 'http://hostname:3000/signalk/v2/api/vessels/self/navigation/course/_config/apiOnly'

## Course Calculations

Whilst not performing course calculations, the Course API defines the paths to accommodate the values calculated during course navigation.

Click here for details.

# Course Calculations and Providers

The Course API defines the path `/vessels/self/navigation/course/calcValues` to accommodate the calculated values related to course navigation.

These paths are available to be populated by a "course provider" plugin that uses the course information set using the Course API. This approach promotes the extensibility of Signal K server providing flexibility and interoperability. See Course Provider Plugins below.

## Calculated value paths: `calcValues`

The following paths are defined to hold values calculated using the information maintained by Course API operations:

- calcMethod: ("Rhumbline" or "GreatCircle")
- crossTrackError
- bearingTrackTrue
- bearingTrackMagnetic
- estimatedTimeOfArrival (e.g. "2022-04-22T05:02:56.484Z")
- distance
- bearingTrue
- bearingMagnetic
- velocityMadeGood
- timeToGo
- targetSpeed
- previousPoint.distance

Example:

    {
      "calcMethod": "Rhumbline",
      "crossTrackError": 458.784,
      "bearingTrackTrue": 4.58491,
      "bearingTrackMagnetic": 4.51234,
      "estimatedTimeOfArrival": "2022-04-22T05:02:56.484Z",
      "distance": 10157,
      "bearingTrue": 4.58491,
      "bearingMagnetic": 4.51234,
      "velocityMadeGood": 7.2653,
      "timeToGo": 8491,
      "targetSpeed": 2.2653,
      "previousPoint": {
        "distance": 10157
      }
    }

## Course Notifications

Calculated course values that cross a threshold should trigger a notification so that the necessary action can be taken.

The Course API defines the following notifications which should be implemented by a course provider:

- `navigation.course.arrivalCircleEntered`
- `navigation.course.perpendicularPassed`

## Course Provider Plugins

Signal K server includes the `Course Data Provider` plugin as part of the installation to provide out-of-the-box support for course calculations nd notifications.

This plugin can be replaced with others from the AppStore, or your own, to extend the number and types of calculations performed.

If you are looking to develop a course provider plugin, following are the recommended guidlines:

1. Ensure values are generated for ALL the defined paths (above)
2. Values MUST be calculated using `/vessels/self/navigation/course` path values mainntained by the Course API
3. Ensure values are set to null when no destination is set or the value cannot be calculated
4. Perform the calculations using a "worker thread" to minimise impact on the server "main thread"
5. Ensure the worker is set up and shut down as part of plugin "start" and "stop" functions
6. Raise the notifications outlined above.

# Working with the Resources API

## Overview

The SignalK specification defines a number of resources (routes, waypoints, notes, regions & charts) each with its own path under the root `resources` path (e.g. `/signalk/v2/api/resources/routes`).

Additionally, the `/resources` path can be used to host other user defined resource types, each grouped within its own folder (e.g. `/signalk/v2/api/resources/fishingZones`).

The Resources API validates requests to these resource paths and passes them to a Resource Provider plugin for storage and retrieval.

Client applications can then use `HTTP` requests to these paths to store (`POST`, `PUT`), retrieve (`GET`) and remove (`DELETE`) resource entries.

Note: the ability to store resource entries is controlled by the server security settings so client applications may need to authenticate for write / delete operations to complete successfully.

### Retrieving Resources

Resource entries are retrived by submitting an HTTP `GET` request to the relevant path.

For example to return a list of all available routes

    HTTP GET 'http://hostname:3000/signalk/v2/api/resources/routes'

or alternatively fetch a specific route.

    HTTP GET 'http://hostname:3000/signalk/v2/api/resources/routes/94052456-65fa-48ce-a85d-41b78a9d2111'

A filtered list of entries can be retrieved based on criteria such as:

- being within a bounded area
- distance from vessel
- total entries returned
- map zoom level

by supplying a query string containing `key | value` pairs in the request.

Example 1: Retrieve waypoints within 50km of the vessel. Note: distance in meters value should be provided.

    HTTP GET 'http://hostname:3000/signalk/v2/api/resources/waypoints?distance=50000'

Example 2: Retrieve up to 20 waypoints within 90km of the vessel.

    HTTP GET 'http://hostname:3000/signalk/v2/api/resources/waypoints?distance=90000&limit=20'

Example 3: Retrieve waypoints within a bounded area. Note: the bounded area is supplied as bottom left & top right corner coordinates in the form swLongitude,swLatitude,neLongitude,neLatitude.

    HTTP GET 'http://hostname:3000/signalk/v2/api/resources/waypoints?bbox=[-135.5,38,-134,38.5]'

_Example 4: Return notes for display on a map view at zoom level 5.

    HTTP GET 'http://hostname:3000/signalk/v2/api/resources/notes?zoom=5'

It is up to the provider to determine which resource entries are returned for any given zoom level. As a guide we recommend alignment with the criteria in the following document: https://wiki.openstreetmap.org/wiki/Zoom_levels_.

### Deleting Resources

Resource entries are deleted by submitting an HTTP `DELETE` request to a path containing the `id` of the resource to delete.

Example: Delete from storage the route with id `94052456-65fa-48ce-a85d-41b78a9d2111`.

    HTTP DELETE 'http://hostname:3000/signalk/v2/api/resources/routes/94052456-65fa-48ce-a85d-41b78a9d2111'

### Creating / updating Resources

Creating a new resource entry:

Resource entries are created by submitting an HTTP `POST` request to a path for the relevant resource type.

    HTTP POST 'http://hostname:3000/signalk/v2/api/resources/routes' {resource_data}

The new resource is created and its `id` (generated by the server) is returned in the response message.

    {
      "state": "COMPLETED",
      "statusCode": 200,
      "id": "94052456-65fa-48ce-a85d-41b78a9d2111"
    }

Note: Each `POST` will generate a new `id` so if the resource data remains the same duplicate resources will be created.

Updating a resource entry:

Resource entries are updated by submitting an HTTP `PUT` request to a path for the relevant resource type that includes the resource `id`.

    HTTP PUT 'http://hostname:3000/signalk/v2/api/resources/waypoints/94052456-65fa-48ce-a85d-41b78a9d2111'

As the `PUT` request replaces the record with the supplied `id`, the submitted resource data should contain a complete record for the resource type being written.

Each resource type has a specific set of attributes that are required to be supplied before the resource entry can be created or updated.

If either the submitted resource data or the resource id are invalid then the operation is aborted._

Note: the submitted resource data is validated against the OpenApi schema definition for the relevant resource type.

## Multiple Providers for a Resource Type

The Resources API will allow for multiple plugins to register as a provider for the same resource type.

When this scenario occurs the server services request in the following ways:

Listing entries:

When a list of resources is requested

for example:

    HTTP GET 'http://hostname:3000/signalk/v2/api/resources/waypoints'

each registered provider will be asked to return matching entries and the server aggregates the results and returns them to the client.

Requests for specific resources:

When a request is received for a specific resource

for example:

    HTTP GET 'http://hostname:3000/signalk/v2/api/resources/waypoints/94052456-65fa-48ce-a85d-41b78a9d2111'

    HTTP PUT 'http://hostname:3000/signalk/v2/api/resources/waypoints/94052456-65fa-48ce-a85d-41b78a9d2111'

    HTTP DELETE 'http://hostname:3000/signalk/v2/api/resources/waypoints/94052456-65fa-48ce-a85d-41b78a9d2111'

each registered provider will polled to determine which one owns the entry with the supplied id. The provider with the resource entry is then the target of the requested operation (`getResource()`, `setResource()`, `deleteResource()`).

Creating new resource entries:

When a request is received to create a new resource

for example:

    HTTP POST 'http://hostname:3000/signalk/v2/api/resources/waypoints'

By default the first provider that was registered for that resource type will be the target of the requested operation (`setResource()`).

You can view the registered providers for a resource type by making the following request:

    HTTP GET 'http://hostname:3000/signalk/v2/api/resources/{resourceType}/_providers'

_Example: `HTTP GET 'http://hostname:3000/signalk/v2/api/resources/charts/_providers'

    [
      "charts",
      "resources-provider"
    ]

You can retrieve the default provider for a resource type by making the following request:

    HTTP GET 'http://hostname:3000/signalk/v2/api/resources/{resourceType}/_providers/_default'

Example: `HTTP GET 'http://hostname:3000/signalk/v2/api/resources/charts/_providers/_default'

    "resources-provider"

You can change the provider used for writing a resource record in the following ways:

1. Per-request by using the `?provider=` query parameter.
2. Setting a "default" provider for a specific resource type

1. Per-request by using the `?provider=` query parameter:

When multiple providers are registered for a resource type the client can specify which provider should be the target of the request by using the query parameter `provider`.

Example:

    HTTP GET 'http://hostname:3000/signalk/v2/api/resources/waypoints?provider=my-plugin-id'

    HTTP GET 'http://hostname:3000/signalk/v2/api/resources/waypoints/94052456-65fa-48ce-a85d-41b78a9d2111?provider=my-plugin-id'

    HTTP PUT 'http://hostname:3000/signalk/v2/api/resources/waypoints/94052456-65fa-48ce-a85d-41b78a9d2111?provider=my-plugin-id'

    HTTP DELETE 'http://hostname:3000/signalk/v2/api/resources/waypoints/94052456-65fa-48ce-a85d-41b78a9d2111?provider=my-plugin-id'

    HTTP POST 'http://hostname:3000/signalk/v2/api/resources/waypoints?provider=my-plugin-id'

the value assigned to `provider` is the `plugin id` of the resource provider plugin.

The plugin id can be obtained from the Signal K server url http://hostname:3000/skServer/plugins.

Example:

    HTTP GET 'http://hostname:3000/plugins'

    [
      {
        "id": "mysk-resource-plugin",  // <-- plugin id
        "name": "Resources Provider",
        "packageName": "mysk-resource-plugin",
        "version": "1.3.0",
        ...
      },
      ...
    ]

2. Setting a default provider for a resource type:

To change the default provider for a resource type make a POST request to http://hostname:3000/signalk/v2/api/resources/{resourceType}/_providers/_default/{pluginId} where `pluginId` is the id of resource provider plugin.

Example: Direct create new chart source entries to `my-chart-plugin`.

    HTTP POST 'http://hostname:3000/signalk/v2/api/resources/charts/_providers/_default/my-chart-plugin'

# Notifications API

#### (Under Development)

Note: This API is currently under development and the information provided here is likely to change.

The Signal K server Notifications API will provide a set of operations for raising, actioning and clearing notifications.

It will implement:

- Both HTTP endpoints for interactive use (`/signalk/v2/api/notifications`) and an interface for use by plugins and connection handlers to ensure effective management of notifications.

- The ability to action notifications (e.g. acknowledge, silence, etc) and preserve the resulting status so it is available to all connected devices.

- A unique `id` for each notification which can then be used to action it, regardless of the notification source.

View the PR for more details.

# Working with the Autopilot API

## Overview

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 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 `/signalk/v2/api/vessels/self/autopilots/_default`.

- When only one autopilot is present, it will be automatically assigned as the default.

- When multiple autopilots are present, and a default is yet to be assigned, one will be assigned when:

  - An update is received from a provider plugin, the autopilot which is the source of the update will be assigned as the default.
  - An API request is received, the first autopilot device registered, is assigned as the default.
  - A request is sent to the `/_providers/_default` API endpoint (see Setting the Default Autopilot).

### Getting the Default Autopilot Identifier

To get the id of the default autopilot, submit an HTTP `GET` request to `/signalk/v2/api/vessels/self/autopilots/_providers/_default`.

Example:

    HTTP GET "/signalk/v2/api/vessels/self/autopilots/_providers/_default"

Response:

    {
      "id":"raymarine-id"
    }

### Setting an Autopilot 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:

    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 `/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/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.

    HTTP GET "/signalk/v2/api/vessels/self/autopilots"

Example: List of registered autopilots showing that `pypilot-id` is assigned as the default.

    {
      "pypilot-id": {
        "provider":"pypilot-provider",
        "isDefault": true
      },
      "raymarine-id": {
        "provider":"raymarine-provider",
        "isDefault": false
      }
    }

## Autopilot Deltas

Deltas emitted by the Autopilot API will have the base path `steering.autopilot` with the `$source` containing the autopilot device identifier.

Example: Deltas for `autopilot.engaged` from two autopilots (`raymarine-id`).

    {
      "context":"vessels.self",
      "updates":[
        {
          "$source":"pypilot-id",
          "timestamp":"2023-11-19T06:12:47.820Z",
          "values":[
            {"path":"steering.autopilot.engaged","value":false}
          ]
        },
        {
          "$source":"raymarine-id",
          "timestamp":"2023-11-19T06:12:47.820Z",
          "values":[
            {"path":"steering.autopilot.engaged","value":true}
          ]
        }
      ]
    }

## Autopilot Notifications

The Autopilot API will provide notifications under the path `notifications.steering.autopilot` with the `$source` containing the autopilot device identifier.

A set of normalised notification paths are defined to provide a consistant way for client apps to receive and process alarm messages.

- `waypointAdvance`
- `waypointArrival`
- `routeComplete`
- `xte`
- `heading`
- `wind`

Example:

    {
      "context":"vessels.self",
      "updates":[
        {
          "$source":"pypilot-id",
          "timestamp":"2023-11-19T06:12:47.820Z",
          "values":[
            {
              "path": "notifications.steering.autopilot.waypointAdvance",
              "value": {
                "state": "alert",
                "method": ["sound"],
                "message": "Waypoint Advance"
              }
            }
          ]
        }
      ]
    }

## Autopilot offline / unreachable

If an autopilot device is not connected or unreachable, the provider for that autopilot device will set the `state` of the device to `off-line`.

## Autopilot Operations

All API operations are invoked by issuing requests to:

1. `/signalk/v2/api/vessels/self/autopilots/_default/*`

Targets the default autopilot device.

OR

2. `/signalk/v2/api/vessels/self/autopilots/{id}/*`

Target the autopilot with the supplied `{id}`

Example:

    HTTP GET "/signalk/v2/api/vessels/self/autopilots/_default/state"

    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/autopilots/{id}`.

    HTTP GET "/signalk/v2/api/vessels/self/autopilots/{id}"

Response:

    {
      "options":{
        "state":["enabled","disabled"],
        "mode":["gps","compass","wind"]
      },
      "state":"disabled",
      "mode":"gps",
      "target": 0,
      "engaged": false
    }

Where:

- `options` contains arrays of valid `state` and `mode` selection options
- `state` represents the current state of the device
- `mode` represents the current mode of the device
- `target` represents the current target value with respect to the selected `mode`
- `engaged` will be true when the autopilot is actively steering the vessel.

### Setting the Autopilot State

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.

    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 `/signalk/v2/api/vessels/self/autopilots/{id}/state` endpoint.

    HTTP GET "/signalk/v2/api/vessels/self/autopilots/{id}/state"

Response:

    {
      "value":"enabled",
    }

### Setting the Autopilot Mode

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.

    HTTP PUT "/signalk/v2/api/vessels/self/autopilots/{id}/mode" {"value": "gps"}

### Getting the Autopilot Mode

The current autopilot mode can be retrieved by submitting an HTTP `GET` request to the `mode` endpoint.

    HTTP GET "/signalk/v2/api/vessels/self/autopilots/{id}/mode"

Response:

    {
      "value":"gps",
    }

### Setting the Target value

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.

Note: The value supplied should be a number within the valid range for the selected `mode`.

    // Set target to 129 degrees
    HTTP PUT "signalk/v2/api/vessels/self/autopilots/{id}/target" {"value": 129, "units": "deg"}

    // Set target to 0.349066 radians (20 degrees)
    HTTP PUT "signalk/v2/api/vessels/self/autopilots/{id}/target" {"value": 0.349066}

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.

    // Adjust target 2 degrees port
    HTTP PUT "signalk/v2/api/vessels/self/autopilots/{id}/target/adjust" {"value": -2, , "units": "deg"}

    // Adjust target 0.0349066 radians (2 degrees) starboard
    HTTP PUT "signalk/v2/api/vessels/self/autopilots/{id}/target/adjust" {"value": 0.0349066}

### 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.

    HTTP GET "/signalk/v2/api/vessels/self/autopilots/{id}/target"

Response:

    {
      "value": 2.2345,
    }

### Engaging / Disengaging the Autopilot

#### Engaging the autopilot

An autopilot can be engaged by setting it to a speciifc `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.

    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` 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.

    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 `./autopilots/{id}/tack/{direction}` where direction is either `port` or `starboard`.

Example: Tack to Port

    HTTP POST "/signalk/v2/api/vessels/self/autopilots/{id}/tack/port"

Example: Tack to 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 `/signalk/v2/api/vessels/self/autopilots/{id}/gybe/{direction}` where direction is either `port` or `starboard`.

Example: Gybe to Port

    HTTP POST "/signalk/v2/api/vessels/self/autopilots/{id}/gybe/port"

Example: Gybe to Starboard

    HTTP POST "/signalk/v2/api/vessels/self/autopilots/{id}/gybe/starboard"

### Dodging Obstacles

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:

To enter dodge mode at the current course

    POST /signalk/v2/api/vessels/self/autopilots/{id}/dodge

To enter dodge mode and change course by 5 degrees starboard

    PUT /signalk/v2/api/vessels/self/autopilots/{id}/dodge {"value": 5, "units": "deg"}

To enter dodge mode and change course by 5 degrees port

    PUT /signalk/v2/api/vessels/self/autopilots/{id}/dodge {"value": -5, "units": "deg"}

To cancel dodge mode

    DELETE /signalk/v2/api/vessels/self/autopilots/{id}/dodge

# Anchor API

#### (Proposed)

Note: The definition of this API is currently under development and the information provided here is likely to change.

The Signal K server Anchor API will define endpoints that can be implemented by plugins for the purposes of implementing and and operating an anchor alarm.

A plugin that implements this API must ensure that all endpoints and operations comply with the definition to ensure applications making requests receive reliable and consistent results.

The following HTTP requests are proposed:

POST `/navigation/anchor/drop` (Commence lowering of anchor)

POST `/navigation/anchor/radius` { value: number } (Set the radius of the alarm area)

POST `/navigation/anchor/reposition` { rodeLength: number, anchorDepth: number } (Calculate anchor position)

POST `/navigation/anchor/raise` (Commence raising the anchor)

# Contributing

Signal K server is an Open Source project and contributions are welcome.

Contributions are made by creating Pull Requests in the GitHub repository.

Working on your first Pull Request?

You can learn how from this free series How to Contribute to an Open Source Project on GitHub

### Submitting a Pull Request (PR)

Before you submit your Pull Request (PR) consider the following guidelines:

1. Fork the repository.

2. Make your changes in a new git branch:

       git checkout -b my-fix-branch master

3. Create your patch.

4. Commit your changes using a descriptive commit message that follows the conventions outlined here. Whilst we are not 100% strict about this, it really helps when reviewing the PR and in making the commit history readable. The TL;DR of it is below.

   - The subject line should be in the format `<type>: <subject>`, where `<type>` should be one of:
     - feat (feature)
     - fix (bug fix)
     - docs (documentation)
     - style (formatting, missing semi colons, ...)
     - refactor
     - test (when adding missing tests)
     - chore (maintain)
   - `<subject>` should use imperative, present tense: "change" not "changed" or "changes"
   - Examples of good Subject Lines:
     - `doc: clarify meta.units behaviour`
     - `chore: update keyswithmetadat.json`
     - `style: whitespace`
     - `fix: allow nextPoint to be an intermediate leaf`
     - `feature: push design object fields under value/values`
   - Message body should also be in imperative, present tense and include motivation for the change and differences to previous behaviour.
   - Footer should reference any issues. If the PR should close issue(s) (assuming it is committed), use closes/fixes or resolves and the issue number. eg. "closes #18", "fixes #21 and resolves #23".
   - Subject, Body and Footer are separated by a blank line.

5. Push your branch to GitHub:

       git push origin my-fix-branch

6. In GitHub, create a pull request.

- Use the same guidelines as commit messages to write the PR title and description. The server's release notes are automatically generated from PR titles, so think about how you can make them informative and easy to understand. The description should tell how the change affects the server's behavior and motivation for doing the change.
- If we suggest changes to your PR we expect you to:

  - Implement the agreed changes.

  - Rebase your branch and force push to your GitHub repository (this will update your Pull Request):

        git rebase master -i
        git push -f

#### After your pull request is merged

After your pull request is merged, you can safely delete your branch and pull the changes from the main (upstream) repository:

- Delete the remote branch on GitHub either through the GitHub web UI or your local shell as follows:

      git push origin --delete my-fix-branch

- Check out the master branch:

      git checkout master -f

- Delete the local branch:

      git branch -D my-fix-branch

- Update your master with the latest upstream version:

      git pull --ff upstream master