signalk-server
Version:
An implementation of a [Signal K](http://signalk.org) server for boats.
148 lines (133 loc) • 34.1 kB
HTML
<html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>Plugins | 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="" aria-current="page">Plugins</a></li></ul></div><div class="tsd-panel tsd-typography"><h1 id="server-plugins" class="tsd-anchor-link">Server plugins<a href="#server-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>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.</p>
<p>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.</p>
<p>Plugins can also provide a webapp by placing the relavent files in a folder named <code>/public/</code> which the server will mount under <code>http://{skserver}:3000/{pluginId}</code>.</p>
<p><strong>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.</strong></p>
<p>For example, if the plugin you are looking to develop is providing access to information such as <code>route,</code> <code>waypoint</code>, <code>POI</code>, or <code>charts</code> you should be creating a <em><a href="Plugins/Resource_Providers.html">Resources Provider Plugin</a></em> for the <em><a href="REST_APIs/Resources_API.html">Resources API</a></em>.</p>
<p>Or if you are looking to perform course calculations or integrate with an auotpilot, you will want to review the <em><a href="REST_APIs/Course_API.html">Course API</a></em> documentation prior to commencing your project.</p>
<p><strong>OpenApi description for your plugin's API</strong></p>
<p>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. <em>See <a href="#add-an-openapi-definition">Add OpenAPI definition</a></em> below.</p>
<hr>
<h2 id="getting-started-with-plugin-development" class="tsd-anchor-link">Getting Started with Plugin Development<a href="#getting-started-with-plugin-development" 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><h3 id="prerequisites" class="tsd-anchor-link">Prerequisites<a href="#prerequisites" 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></h3><p>To get started developing your plugin you will need the following:</p>
<ul>
<li>Signal K server instance on your device <em>(clone of GIT repository or docker instance)</em></li>
<li>NodeJs version 20 or later and NPM installed</li>
<li>SignalK server configuration folder. <em>(Created when Signal K server is started. default location is <code>$HOME/.signalk</code>)</em>.</li>
</ul>
<hr>
<h3 id="setting-up-your-project" class="tsd-anchor-link">Setting up your project<a href="#setting-up-your-project" 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></h3><ol>
<li>Create a folder for your plugin code and create the necessary file structure:</li>
</ol>
<pre><code class="shell"><span class="hl-0">mkdir</span><span class="hl-1"> </span><span class="hl-2">my-pluin</span><br/><span class="hl-3">cd</span><span class="hl-1"> </span><span class="hl-2">my-plugin</span><br/><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">init</span><span class="hl-1"> </span><span class="hl-4"># create package.json file</span>
</code><button type="button">Copy</button></pre>
<ol start="2">
<li>Create the folders to hold your plugin code and webapp UI.</li>
</ol>
<pre><code class="shell"><span class="hl-0">/my-plugin</span><br/><span class="hl-1"> </span><span class="hl-0">/plugin</span><span class="hl-1"> </span><span class="hl-4"># plugin (javascript code / built typesrcipt code)</span><br/><span class="hl-1"> </span><span class="hl-0">index.js</span><br/><span class="hl-1"> </span><span class="hl-3">..</span><br/><span class="hl-1"> </span><span class="hl-0">/public</span><span class="hl-1"> </span><span class="hl-4"># web app UI</span><br/><span class="hl-1"> </span><span class="hl-0">index.html</span><br/><span class="hl-1"> </span><span class="hl-3">..</span><br/><span class="hl-1"> </span><span class="hl-0">/src</span><span class="hl-1"> </span><span class="hl-4"># typescript source code (not required if using javascript)</span><br/><span class="hl-1"> </span><span class="hl-0">index.ts</span><br/><span class="hl-1"> </span><span class="hl-3">...</span><br/><span class="hl-1"> </span><span class="hl-0">package.json</span>
</code><button type="button">Copy</button></pre>
<ol start="3">
<li>Update the <code>package.json</code> to reflect your project structure and add keywords to identify the package for the Signal K AppStore.</li>
</ol>
<pre><code class="JSON"><span class="hl-1">{</span><br/><span class="hl-1"> </span><span class="hl-6">"name"</span><span class="hl-1">: </span><span class="hl-2">"my-plugin"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-6">"version"</span><span class="hl-1">: </span><span class="hl-2">"1.0.0"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-6">"description"</span><span class="hl-1">: </span><span class="hl-2">"My signalk plugin"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-6">"keywords"</span><span class="hl-1">: [</span><br/><span class="hl-1"> </span><span class="hl-2">"signalk-node-server-plugin"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">"signalk-category-ais"</span><br/><span class="hl-1"> ],</span><br/><span class="hl-1"> </span><span class="hl-6">"signalk-plugin-enabled-by-default"</span><span class="hl-1">: </span><span class="hl-3">false</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-6">"signalk"</span><span class="hl-1">: {</span><br/><span class="hl-1"> </span><span class="hl-6">"appIcon"</span><span class="hl-1">: </span><span class="hl-2">"./assets/icons/icon-72x72.png"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-6">"displayName"</span><span class="hl-1">: </span><span class="hl-2">"My Great WebApp"</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-6">"main"</span><span class="hl-1">: </span><span class="hl-2">"plugin/index.js"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-7">...</span><br/><span class="hl-1">}</span>
</code><button type="button">Copy</button></pre>
<ol start="4">
<li><em>Optional:</em> Install any dependencies or third party packages.</li>
</ol>
<pre><code class="shell"><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">i</span>
</code><button type="button">Copy</button></pre>
<h3 id="link-your-project-to-signal-k-server" class="tsd-anchor-link">Link your project to Signal K server.<a href="#link-your-project-to-signal-k-server" 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></h3><p>Once you have developed your plugin code and are ready to debug, the most convenient way is to use <code>npm link</code> to link your plugin code to your instance of Signal K server.</p>
<p>To do this, from within a terminal window:</p>
<pre><code class="shell"><span class="hl-4"># Ensure you are in the folder containing your built plugin code</span><br/><span class="hl-3">cd</span><span class="hl-1"> </span><span class="hl-2">my_plugin_src</span><br/><br/><span class="hl-4"># Create a link (may require the use of sudo)</span><br/><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">link</span><br/><br/><span class="hl-4"># Change to the Signal K server configuration directory</span><br/><span class="hl-3">cd</span><span class="hl-1"> </span><span class="hl-2">~/.signalk</span><br/><br/><span class="hl-4"># Link your plugin using the name in the package.json file</span><br/><span class="hl-4">#(may require the use of sudo)</span><br/><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">link</span><span class="hl-1"> </span><span class="hl-2">my-signalk-plugin-app</span>
</code><button type="button">Copy</button></pre>
<p>When you start Signal K server the plugin will now appear in the <strong>Plugin Config</strong> screen where it can be configured and enabled.</p>
<p>Updating and/or installing new plugins will remove the link and you need to re-link your plugin.</p>
<h3 id="debugging" class="tsd-anchor-link">Debugging<a href="#debugging" 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></h3><p>The simplest way to debug your plugin is to turn on <strong>Enable Debug log</strong> for your plugin in the <strong>Plugin Config</strong> screen.</p>
<p>Alternatively, you can debug your plugin by starting the Signal K server with the <code>DEBUG</code> environment variable:</p>
<pre><code class="shell"><span class="hl-0">$</span><span class="hl-1"> </span><span class="hl-2">DEBUG=my-signalk-plugin</span><span class="hl-1"> </span><span class="hl-2">signalk-server</span><br/><br/><span class="hl-4"># sample output</span><br/><span class="hl-0">my-signalk-plugin</span><span class="hl-1"> </span><span class="hl-2">Plugin</span><span class="hl-1"> </span><span class="hl-2">stopped</span><span class="hl-1"> </span><span class="hl-2">+0ms</span><br/><span class="hl-0">my-signalk-plugin</span><span class="hl-1"> </span><span class="hl-2">Plugin</span><span class="hl-1"> </span><span class="hl-2">started</span><span class="hl-1"> </span><span class="hl-2">+2ms</span>
</code><button type="button">Copy</button></pre>
<p>You can also view debug information about the plugin loading process:</p>
<pre><code class="shell"><span class="hl-0">$</span><span class="hl-1"> </span><span class="hl-2">DEBUG=signalk:interfaces:plugins</span><span class="hl-1"> </span><span class="hl-2">signalk-server</span><br/><br/><span class="hl-4"># sample output</span><br/><span class="hl-0">signalk:interfaces:plugins</span><span class="hl-1"> </span><span class="hl-2">Registering</span><span class="hl-1"> </span><span class="hl-2">plugin</span><span class="hl-1"> </span><span class="hl-2">my-signalk-plugin</span><span class="hl-1"> </span><span class="hl-2">+0ms</span><br/><span class="hl-0">signalk:interfaces:plugins</span><span class="hl-1"> </span><span class="hl-2">Could</span><span class="hl-1"> </span><span class="hl-2">not</span><span class="hl-1"> </span><span class="hl-2">find</span><span class="hl-1"> </span><span class="hl-2">options</span><span class="hl-1"> </span><span class="hl-2">for</span><span class="hl-1"> </span><span class="hl-2">plugin</span><span class="hl-1"> </span><span class="hl-2">my-signalk-plugin,</span><span class="hl-1"> </span><span class="hl-2">returning</span><span class="hl-1"> </span><span class="hl-2">empty</span><span class="hl-1"> </span><span class="hl-2">options:</span><span class="hl-1"> </span><span class="hl-2">+2ms</span>
</code><button type="button">Copy</button></pre>
<h4 id="sample-data" class="tsd-anchor-link">Sample Data<a href="#sample-data" 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></h4><p>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.</p>
<p>You can enable this by adding <code>--sample-n2k-data</code> to the command line:</p>
<pre><code class="shell"><span class="hl-0">$</span><span class="hl-1"> </span><span class="hl-2">DEBUG=my-signalk-plugin</span><span class="hl-1"> </span><span class="hl-2">signalk-server</span><span class="hl-1"> </span><span class="hl-3">--sample-n2k-data</span>
</code><button type="button">Copy</button></pre>
<hr>
<h2 id="start-coding" class="tsd-anchor-link">Start Coding<a href="#start-coding" 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>Signal K server plugins are NodeJs <code>javascript</code> or <code>typescript</code> projects that return an object that implements the <a href="../_signalk/server-api/Plugin.html" class="tsd-kind-interface">Plugin</a> interface.</p>
<p>They are installed into the <code>node_modules</code> folder that resides inside the SignalK server's configuration directory <em>(<code>$HOME/.signalk</code> by default)</em>.</p>
<p>A Signal K plugin is passed a reference to the Signal K server plugin interface which it can use to interact with the server.</p>
<p>Following are code snippets that can be used as a template for plugin development ensuring the returned Plugin object contains the required functions.</p>
<h3 id="javascript" class="tsd-anchor-link">Javascript<a href="#javascript" 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></h3><p>Create <code>index.js</code> with the following content:</p>
<pre><code class="javascript"><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-0">app</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-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">'my-signalk-plugin'</span><span class="hl-1">,</span><br/><span class="hl-1"> name: </span><span class="hl-2">'My Great Plugin'</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-8">start</span><span class="hl-1">: (</span><span class="hl-0">settings</span><span class="hl-1">, </span><span class="hl-0">restartPlugin</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-4">// start up code goes here.</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-8">stop</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-4">// shutdown code goes here.</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-8">schema</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-0">properties</span><span class="hl-1">: {</span><br/><span class="hl-1"> </span><span class="hl-4">// plugin configuration goes here</span><br/><span class="hl-1"> }</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>
<h3 id="typescript" class="tsd-anchor-link">Typescript<a href="#typescript" 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></h3><p>Create <code>index.js</code> with the following content:</p>
<pre><code class="typescript"><span class="hl-5">import</span><span class="hl-1"> { Plugin, ServerAPI } </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-5">export</span><span class="hl-0"> </span><span class="hl-5">default</span><span class="hl-0"> (app</span><span class="hl-5">:</span><span class="hl-0"> ServerAPI)</span><span class="hl-5">:</span><span class="hl-0"> Plugin </span><span class="hl-5">=></span><span class="hl-0"> </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-5">:</span><span class="hl-1"> </span><span class="hl-0">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">'my-signalk-plugin'</span><span class="hl-1">,</span><br/><span class="hl-1"> name: </span><span class="hl-2">'My Great Plugin'</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-8">start</span><span class="hl-1">: (</span><span class="hl-0">settings</span><span class="hl-1">, </span><span class="hl-0">restartPlugin</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-4">// start up code goes here.</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-8">stop</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-4">// shutdown code goes here.</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-8">schema</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-0">properties</span><span class="hl-1">: {</span><br/><span class="hl-1"> </span><span class="hl-4">// plugin configuration goes here</span><br/><span class="hl-1"> }</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>
<p>A plugin must return an object containing the following functions:</p>
<ul>
<li>
<p><code>start(settings, restartPlugin)</code>: This function is called when the plugin is enabled or when the server starts (and the plugin is enabled). The <code>settings</code> parameter contains the configuration data entered via the <strong>Plugin Config</strong> screen. <code>restartPlugin</code> is a function that can be called by the plugin to restart itself.</p>
</li>
<li>
<p><code>stop()</code>: 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.</p>
</li>
<li>
<p><code>schema()</code>: 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 <strong>Plugin Config</strong> screen.</p>
</li>
</ul>
<p><em>Note: When a plugin's configuration is changed the server will first call <code>stop()</code> to stop the plugin and then <code>start()</code> with the new configuration data. Return a Promise from <code>stop</code> if needed so that <code>start</code> is not called before stopping is complete.</em></p>
<p>A plugin can also contain the following optional functions:</p>
<ul>
<li>
<p><code>uiSchema()</code>: A function that returns an object defining the attributes of the UI components displayed in the <strong>Plugin Config</strong> screen.</p>
</li>
<li>
<p><code>registerWithRouter(router)</code>: 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 <code>getOpenAPI()</code> if this function is used.</p>
</li>
</ul>
<p><em>Example:</em></p>
<pre><code class="javascript"><span class="hl-1">plugin.</span><span class="hl-8">registerWithRouter</span><span class="hl-1"> </span><span class="hl-5">=</span><span class="hl-1"> (</span><span class="hl-0">router</span><span class="hl-1">) </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> router.</span><span class="hl-8">get</span><span class="hl-1">(</span><span class="hl-2">'/preferences'</span><span class="hl-1">, (</span><span class="hl-0">req</span><span class="hl-1">, </span><span class="hl-0">res</span><span class="hl-1">) </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> res.</span><span class="hl-8">status</span><span class="hl-1">(</span><span class="hl-3">200</span><span class="hl-1">).</span><span class="hl-8">json</span><span class="hl-1">({</span><br/><span class="hl-1"> preferences: {</span><br/><span class="hl-1"> color: </span><span class="hl-2">'red'</span><span class="hl-1">,</span><br/><span class="hl-1"> speed: </span><span class="hl-3">1.23</span><br/><span class="hl-1"> }</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>
<ul>
<li><code>getOpenApi()</code>: 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 <code>Documentation -> OpenAPI</code>.</li>
</ul>
<p><em>Example:</em></p>
<pre><code class="javascript"><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-3">openapi</span><span class="hl-1"> </span><span class="hl-5">=</span><span class="hl-1"> </span><span class="hl-8">require</span><span class="hl-1">(</span><span class="hl-2">'./openApi.json'</span><span class="hl-1">)</span><br/><br/><span class="hl-1">plugin.</span><span class="hl-8">getOpenApi</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"> openapi</span>
</code><button type="button">Copy</button></pre>
<hr>
<h2 id="add-an-openapi-definition" class="tsd-anchor-link">Add an OpenAPI Definition<a href="#add-an-openapi-definition" 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>If your plugin exposes an API to interact with it then you should include an OpenAPI definition.</p>
<p>You do this by creating an OpenAPI definition within the file <code>openApi.json</code> and then returning the content of the file with the <code>getOpenApi</code> method.</p>
<p><em>Example:</em></p>
<pre><code class="javascript"><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-3">openapi</span><span class="hl-1"> </span><span class="hl-5">=</span><span class="hl-1"> </span><span class="hl-8">require</span><span class="hl-1">(</span><span class="hl-2">'./openApi.json'</span><span class="hl-1">);</span><br/><span class="hl-5">...</span><br/><br/><span class="hl-1">plugin.</span><span class="hl-8">getOpenApi</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"> openapi;</span>
</code><button type="button">Copy</button></pre>
<p>This will include your plugin's OpenApi definition in the documentation in the server's Admin UI under <em>Documentation -> OpenAPI</em>.</p>
<p>Note: If the plugin's OpenApi description DOES NOT include a <code>servers</code> 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.
<em>Example:</em></p>
<pre><code class="JSON"><span class="hl-1"> </span><span class="hl-2">"servers"</span><span class="hl-1">: [</span><br/><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-6">"url"</span><span class="hl-1">: </span><span class="hl-2">"/myapi/endpoint"</span><br/><span class="hl-1"> }</span><br/><span class="hl-1"> ],</span>
</code><button type="button">Copy</button></pre>
<p>See <a href="https://github.com/SignalK/signalk-server/tree/b82477e63ebdc14878164ce1ed3aedd80c5a8b0c/test/plugin-test-config/node_modules/testplugin">testplugin</a> for an example.</p>
<hr>
<h2 id="logging" class="tsd-anchor-link">Logging<a href="#logging" 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>To record deltas sent by the plugin in the server's data log, enable the <strong>Log plugin output</strong> in the plugin configuration screen.</p>
<hr>
<h2 id="removing-a-plugin" class="tsd-anchor-link">Removing a plugin<a href="#removing-a-plugin" 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>Plugins can be removed via the AppStore.</p>
<p>You can also remove a plugin manually by:</p>
<ol>
<li>Deleting it's folder under <code>~/.signalk/node_modules</code></li>
<li>Deleting it's entry from <code>~/.signalk/package.json</code></li>
<li>Run <code>npm prune</code> from the <code>~/.signalk/</code> directory.</li>
</ol>
<p>Alternatively you can:</p>
<ol>
<li>Remove the folder <code>~/.signalk/node_modules</code></li>
<li>Run <code>npm install</code> from the <code>~/.signalk/</code> directory.</li>
</ol>
<p>Finally you can remove the plugin setting file in <code>~/.signalk/plugin-config-data/</code>.</p>
<hr>
<h2 id="examples" class="tsd-anchor-link">Examples<a href="#examples" 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>Following are links to some published SignalK plugins that serve as an example of working plugins:</p>
<ul>
<li><a href="https://github.com/SignalK/set-system-time/blob/master/index.js">set-system-time</a></li>
<li><a href="https://github.com/SignalK/aisreporter/issues">Ais Reporter</a></li>
</ul>
</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="#getting-started-with-plugin-development"><span>Getting <wbr/>Started with <wbr/>Plugin <wbr/>Development</span></a><ul><li><a href="#prerequisites"><span>Prerequisites</span></a></li><li><a href="#setting-up-your-project"><span>Setting up your project</span></a></li><li><a href="#link-your-project-to-signal-k-server"><span>Link your project to <wbr/>Signal <wbr/>K server.</span></a></li><li><a href="#debugging"><span>Debugging</span></a></li></ul><a href="#start-coding"><span>Start <wbr/>Coding</span></a><ul><li><a href="#javascript"><span>Javascript</span></a></li><li><a href="#typescript"><span>Typescript</span></a></li></ul><a href="#add-an-openapi-definition"><span>Add an <wbr/>Open<wbr/>API <wbr/>Definition</span></a><a href="#logging"><span>Logging</span></a><a href="#removing-a-plugin"><span>Removing a plugin</span></a><a href="#examples"><span>Examples</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>