signalk-server
Version:
An implementation of a [Signal K](http://signalk.org) server for boats.
62 lines (57 loc) • 21.4 kB
HTML
<html class="default" lang="en" data-base="../../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>Autopilot Providers | Signal K</title><meta name="description" content="Documentation for Signal K"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../../assets/style.css?cache=1750891486567"/><link rel="stylesheet" href="../../assets/highlight.css?cache=1750891486567"/><script defer src="../../assets/main.js?cache=1750891486567"></script><script async src="../../assets/icons.js?cache=1750891486567" id="tsd-icons-script"></script><script async src="../../assets/search.js?cache=1750891486567" id="tsd-search-script"></script><script async src="../../assets/navigation.js?cache=1750891486567" id="tsd-nav-script"></script><script async src="../../assets/hierarchy.js?cache=1750891486567" id="tsd-hierarchy-script"></script><link rel="stylesheet" href="../../assets/theme.css"/></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="../../index.html" class="title"><img src="../../assets/logo.svg" alt="Signal K"/></a><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../../assets/icons.svg#icon-search"></use></svg><span class="visible@s">Search</span></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><div id="tsd-toolbar-links"><a href="https://discord.gg/uuZrwz4dCS" target="_blank" rel="noopener" class="toolbar-icon visible@s" aria-label="Discord"><svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path d="M524.5 69.8a1.5 1.5 0 0 0 -.8-.7A485.1 485.1 0 0 0 404.1 32a1.8 1.8 0 0 0 -1.9 .9 337.5 337.5 0 0 0 -14.9 30.6 447.8 447.8 0 0 0 -134.4 0 309.5 309.5 0 0 0 -15.1-30.6 1.9 1.9 0 0 0 -1.9-.9A483.7 483.7 0 0 0 116.1 69.1a1.7 1.7 0 0 0 -.8 .7C39.1 183.7 18.2 294.7 28.4 404.4a2 2 0 0 0 .8 1.4A487.7 487.7 0 0 0 176 479.9a1.9 1.9 0 0 0 2.1-.7A348.2 348.2 0 0 0 208.1 430.4a1.9 1.9 0 0 0 -1-2.6 321.2 321.2 0 0 1 -45.9-21.9 1.9 1.9 0 0 1 -.2-3.1c3.1-2.3 6.2-4.7 9.1-7.1a1.8 1.8 0 0 1 1.9-.3c96.2 43.9 200.4 43.9 295.5 0a1.8 1.8 0 0 1 1.9 .2c2.9 2.4 6 4.9 9.1 7.2a1.9 1.9 0 0 1 -.2 3.1 301.4 301.4 0 0 1 -45.9 21.8 1.9 1.9 0 0 0 -1 2.6 391.1 391.1 0 0 0 30 48.8 1.9 1.9 0 0 0 2.1 .7A486 486 0 0 0 610.7 405.7a1.9 1.9 0 0 0 .8-1.4C623.7 277.6 590.9 167.5 524.5 69.8zM222.5 337.6c-29 0-52.8-26.6-52.8-59.2S193.1 219.1 222.5 219.1c29.7 0 53.3 26.8 52.8 59.2C275.3 311 251.9 337.6 222.5 337.6zm195.4 0c-29 0-52.8-26.6-52.8-59.2S388.4 219.1 417.9 219.1c29.7 0 53.3 26.8 52.8 59.2C470.7 311 447.5 337.6 417.9 337.6z"></path></svg></a><a href="https://github.com/SignalK/signalk-server" target="_blank" rel="noopener" class="toolbar-icon visible@s" aria-label="Discord"><svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3 .3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5 .3-6.2 2.3zm44.2-1.7c-2.9 .7-4.9 2.6-4.6 4.9 .3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3 .7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3 .3 2.9 2.3 3.9 1.6 1 3.6 .7 4.3-.7 .7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3 .7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3 .7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"></path></svg></a><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../../assets/icons.svg#icon-menu"></use></svg></a></div></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb" aria-label="Breadcrumb"><li><a href="../../Developing.html">Developing</a></li><li><a href="../Plugins.html">Plugins</a></li><li><a href="" aria-current="page">Autopilot Providers</a></li></ul></div><div class="tsd-panel tsd-typography"><h1 id="autopilot-provider-plugins" class="tsd-anchor-link">Autopilot Provider plugins<a href="#autopilot-provider-plugins" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../../assets/icons.svg#icon-anchor"></use></svg></a></h1><p>The Signal K <a href="../REST_APIs/Autopilot_API.html">Autopilot API</a> provides 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 <a href="/doc/openapi/?urls.primaryName=autopilot">OpenAPI</a> document.</p>
<p>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 <strong>provider plugin</strong> to action the request on the autopilot device.</p>
<p>This de-coupling of request handling and autopilot communication provides the flexibility to support a variety of autopilot devices and ensures interoperability and reliabilty.</p>
<p>Autopilot API requests are passed to a <strong>provider plugin</strong> which will process and action the request facilitating communication with the autopilot device.</p>
<p>The following diagram provides an overview of the Autopilot API architectue.</p>
<img src="../../media/autopilot_provider.svg" width="600px">
<p><em>Autopilot API architecture</em></p>
<h2 id="provider-plugins" class="tsd-anchor-link">Provider Plugins<a href="#provider-plugins" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>An autopilot provider plugin is a Signal K server plugin that implements the <a href="../../_signalk/server-api/AutopilotProvider.html" class="tsd-kind-interface"><code>AutoPilotProvider</code></a> interface, which:</p>
<ul>
<li>Tells server the autopilot devices provided for by the plugin</li>
<li>Registers the methods used to action requests passed from the server to perform autopilot operations.</li>
</ul>
<p>Multiple providers can be registered and each provider can manage one or more autopilot devices.</p>
<p><strong>Note: An Autopilot Provider plugin MUST:</strong></p>
<ul>
<li>Implement all Autopilot API interface methods.</li>
<li>Facilitate communication on the target autopilot device to send commands and retrieve both status and configuration information</li>
<li>Ensure the <code>engaged</code> path attribute value is maintained to reflect the operational status of the autopilot.</li>
<li>Map the <code>engage</code> and <code>disengage</code> operations to an appropriate autopilot device <code>state</code>.</li>
<li>Set the state as <code>off-line</code> if the autopilot device is not connected or unreachable.</li>
<li>Set the mode as <code>dodge</code> when the autopilot device is is in dodge mode.</li>
</ul>
<h2 id="registering-as-an-autopilot-provider" class="tsd-anchor-link">Registering as an Autopilot Provider<a href="#registering-as-an-autopilot-provider" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>A provider plugin must register itself with the Autopilot API during start up by calling the <a href="../../_signalk/server-api/ServerAPI.html#registerautopilotprovider" class="tsd-kind-method"><code>registerAutopilotProvider</code></a>.</p>
<p><em>Example: Plugin registering as an autopilot provider.</em></p>
<pre><code class="javascript"><span class="hl-5">import</span><span class="hl-1"> { AutopilotProvider } </span><span class="hl-5">from</span><span class="hl-1"> </span><span class="hl-2">'@signalk/server-api'</span><br/><br/><span class="hl-3">module</span><span class="hl-1">.</span><span class="hl-3">exports</span><span class="hl-1"> </span><span class="hl-5">=</span><span class="hl-1"> </span><span class="hl-5">function</span><span class="hl-1"> (</span><span class="hl-0">app</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-3">plugin</span><span class="hl-1"> </span><span class="hl-5">=</span><span class="hl-1"> {</span><br/><span class="hl-1"> id: </span><span class="hl-2">'mypluginid'</span><span class="hl-1">,</span><br/><span class="hl-1"> name: </span><span class="hl-2">'My autopilot Provider plugin'</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-3">autopilotProvider</span><span class="hl-5">:</span><span class="hl-1"> </span><span class="hl-0">AutopilotProvider</span><span class="hl-1"> </span><span class="hl-5">=</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-8">getData</span><span class="hl-1">: (</span><span class="hl-0">deviceId</span><span class="hl-1">) </span><span class="hl-5">=></span><span class="hl-1"> { </span><span class="hl-5">return</span><span class="hl-1"> </span><span class="hl-5">...</span><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-8">getState</span><span class="hl-1">: (</span><span class="hl-0">deviceId</span><span class="hl-1">) </span><span class="hl-5">=></span><span class="hl-1"> { </span><span class="hl-5">return</span><span class="hl-1"> </span><span class="hl-5">...</span><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-8">setState</span><span class="hl-1">: (</span><span class="hl-0">state</span><span class="hl-1">, </span><span class="hl-0">deviceId</span><span class="hl-1">) </span><span class="hl-5">=></span><span class="hl-1"> { </span><span class="hl-5">...</span><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-8">getMode</span><span class="hl-1">: (</span><span class="hl-0">deviceId</span><span class="hl-1">) </span><span class="hl-5">=></span><span class="hl-1"> { </span><span class="hl-5">return</span><span class="hl-1"> </span><span class="hl-5">...</span><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-8">setMode</span><span class="hl-1">: (</span><span class="hl-0">mode</span><span class="hl-1">, </span><span class="hl-0">deviceId</span><span class="hl-1">) </span><span class="hl-5">=></span><span class="hl-1"> { </span><span class="hl-5">...</span><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-8">getTarget</span><span class="hl-1">: (</span><span class="hl-0">deviceId</span><span class="hl-1">) </span><span class="hl-5">=></span><span class="hl-1"> { </span><span class="hl-5">return</span><span class="hl-1"> </span><span class="hl-5">...</span><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-8">setTarget</span><span class="hl-1">(</span><span class="hl-0">value</span><span class="hl-1">, </span><span class="hl-0">deviceId</span><span class="hl-1">) </span><span class="hl-5">=></span><span class="hl-1"> { </span><span class="hl-5">...</span><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-8">adjustTarget</span><span class="hl-1">(</span><span class="hl-0">value</span><span class="hl-1">, </span><span class="hl-0">deviceId</span><span class="hl-1">) </span><span class="hl-5">=></span><span class="hl-1"> { </span><span class="hl-5">...</span><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-8">engage</span><span class="hl-1">: (</span><span class="hl-0">deviceId</span><span class="hl-1">) </span><span class="hl-5">=></span><span class="hl-1"> { </span><span class="hl-5">...</span><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-8">disengage</span><span class="hl-1">: (</span><span class="hl-0">deviceId</span><span class="hl-1">) </span><span class="hl-5">=></span><span class="hl-1"> { </span><span class="hl-5">...</span><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-8">tack</span><span class="hl-1">:(</span><span class="hl-0">direction</span><span class="hl-1">, </span><span class="hl-0">deviceId</span><span class="hl-1">) </span><span class="hl-5">=></span><span class="hl-1"> { </span><span class="hl-5">...</span><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-8">gybe</span><span class="hl-1">:(</span><span class="hl-0">direction</span><span class="hl-1">, </span><span class="hl-0">deviceId</span><span class="hl-1">) </span><span class="hl-5">=></span><span class="hl-1"> { </span><span class="hl-5">...</span><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-8">dodge</span><span class="hl-1">:(</span><span class="hl-0">value</span><span class="hl-1">, </span><span class="hl-0">deviceId</span><span class="hl-1">) </span><span class="hl-5">=></span><span class="hl-1"> { </span><span class="hl-5">...</span><span class="hl-1"> }</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-3">pilots</span><span class="hl-1"> </span><span class="hl-5">=</span><span class="hl-1"> [</span><span class="hl-2">'pilot1'</span><span class="hl-1">, </span><span class="hl-2">'pilot2'</span><span class="hl-1">]</span><br/><br/><span class="hl-1"> plugin.</span><span class="hl-8">start</span><span class="hl-1"> </span><span class="hl-5">=</span><span class="hl-1"> </span><span class="hl-5">function</span><span class="hl-1">(</span><span class="hl-0">options</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-5">...</span><br/><span class="hl-1"> </span><span class="hl-5">try</span><span class="hl-1"> {</span><br/><span class="hl-1"> app.</span><span class="hl-8">registerAutopilotProvider</span><span class="hl-1">(autopilotProvider, pilots)</span><br/><span class="hl-1"> }</span><br/><span class="hl-1"> </span><span class="hl-5">catch</span><span class="hl-1"> (error) {</span><br/><span class="hl-1"> </span><span class="hl-4">// handle error</span><br/><span class="hl-1"> }</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-5">return</span><span class="hl-1"> plugin</span><br/><span class="hl-1">}</span>
</code><button type="button">Copy</button></pre>
<h2 id="sending-updates-and-notifications" class="tsd-anchor-link">Sending Updates and Notifications<a href="#sending-updates-and-notifications" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>The Autopilot API is responsible for sending both update and notification <code>deltas</code> to Signal K clients.</p>
<p>Data received from an autopilot device, regardless of the communications protocol (NMEA2000, etc), should be sent to the Autopilot API by calling the <a href="../../_signalk/server-api/ServerAPI.html#autopilotupdate" class="tsd-kind-method"><code>autopilotUpdate</code></a> method.</p>
<p>This will ensure:</p>
<ul>
<li>Default pilot status is correctly maintained</li>
<li><code>steering.autopilot.*</code> both V1 and V2 deltas are sent</li>
</ul>
<div class="tsd-alert tsd-alert-important"><div class="tsd-alert-title"><svg width="16" height="16" viewBox="0 0 16 16" aria-hidden="true"><use href="../../assets/icons.svg#icon-alertImportant"></use></svg><span>Important</span></div><p>
The values provided via <code>autopilotUpdate</code> will be sent in the relevant delta message, so ensure they are in the correct units (e.g. angles in radians, etc).</p>
</div>
<p><em>Example Update:</em></p>
<pre><code class="javascript"><span class="hl-1">app.</span><span class="hl-8">autopilotUpdate</span><span class="hl-1">(</span><span class="hl-2">'my-pilot'</span><span class="hl-1">, {</span><br/><span class="hl-1"> target: </span><span class="hl-3">1.52789</span><span class="hl-1">,</span><br/><span class="hl-1"> mode: </span><span class="hl-2">'compass'</span><br/><span class="hl-1">})</span>
</code><button type="button">Copy</button></pre>
<p>Notifications / Alarms are sent using one of the normalised alarm names below as the path and a <code>Notification</code> as the value.</p>
<ul>
<li>waypointAdvance</li>
<li>waypointArrival</li>
<li>routeComplete</li>
<li>xte</li>
<li>heading</li>
<li>wind</li>
</ul>
<p><em>Example Notification:</em></p>
<pre><code class="javascript"><span class="hl-1">app.</span><span class="hl-8">autopilotUpdate</span><span class="hl-1">(</span><span class="hl-2">'my-pilot'</span><span class="hl-1">, {</span><br/><span class="hl-1"> alarm: {</span><br/><span class="hl-1"> path: </span><span class="hl-2">'waypointAdvance'</span><span class="hl-1">,</span><br/><span class="hl-1"> value: {</span><br/><span class="hl-1"> state: </span><span class="hl-2">'alert'</span><br/><span class="hl-1"> method: [</span><span class="hl-2">'sound'</span><span class="hl-1">]</span><br/><span class="hl-1"> message: </span><span class="hl-2">'Waypoint Advance'</span><br/><span class="hl-1"> }</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">})</span>
</code><button type="button">Copy</button></pre>
<h2 id="unhandled-operations" class="tsd-anchor-link">Unhandled Operations<a href="#unhandled-operations" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>A provider plugin <strong>MUST</strong> implement <strong>ALL</strong> Autopilot API interface methods, regardless of whether the operation is supported or not.</p>
<p>For an operation that is not supported by the autopilot device, then the plugin should <code>throw</code> an exception.</p>
<p><em>Example:</em></p>
<pre><code class="typescript"><span class="hl-1">{</span><br/><span class="hl-1"> </span><span class="hl-4">// unsupported operation method definition</span><br/><span class="hl-1"> async </span><span class="hl-8">gybe</span><span class="hl-1">(d, id) {</span><br/><span class="hl-1"> </span><span class="hl-5">throw</span><span class="hl-1"> </span><span class="hl-5">new</span><span class="hl-1"> </span><span class="hl-8">Error</span><span class="hl-1">(</span><span class="hl-2">'Unsupprted operation!</span><span class="hl-7">)</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span>
</code><button type="button">Copy</button></pre>
</div></div><div class="col-sidebar"><div class="page-menu"><details open class="tsd-accordion tsd-page-navigation"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../../assets/icons.svg#icon-chevronDown"></use></svg><h3>On This Page</h3></summary><div class="tsd-accordion-details"><a href="#provider-plugins"><span>Provider <wbr/>Plugins</span></a><a href="#registering-as-an-autopilot-provider"><span>Registering as an <wbr/>Autopilot <wbr/>Provider</span></a><a href="#sending-updates-and-notifications"><span>Sending <wbr/>Updates and <wbr/>Notifications</span></a><a href="#unhandled-operations"><span>Unhandled <wbr/>Operations</span></a></div></details></div><div class="site-menu"><nav class="tsd-navigation"><a href="../../modules.html">Signal K</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>