UNPKG

signalk-server

Version:

An implementation of a [Signal K](http://signalk.org) server for boats.

164 lines (143 loc) 55.4 kB
<!DOCTYPE html><html class="default" lang="en" data-base="../../../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>Integration Guide for WASM 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=1783009712609"/><link rel="stylesheet" href="../../../assets/highlight.css?cache=1783009712609"/><script defer src="../../../assets/main.js?cache=1783009712609"></script><script async src="../../../assets/icons.js?cache=1783009712609" id="tsd-icons-script"></script><script async src="../../../assets/search.js?cache=1783009712609" id="tsd-search-script"></script><script async src="../../../assets/navigation.js?cache=1783009712609" id="tsd-nav-script"></script><script async src="../../../assets/hierarchy.js?cache=1783009712609" id="tsd-hierarchy-script"></script><link rel="stylesheet" href="../../../assets/theme.css"/><script>if(window.self!==window.top){document.documentElement.classList.add('embedded')}</script></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 class="title-logo" src="../../../assets/logo.svg" alt="Signal K"/><svg class="title-home-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-label="Documentation home"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path><polyline points="9 22 9 12 15 12 15 22"></polyline></svg></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="../WASM_Plugins.html">WASM Plugins</a></li><li><a href="" aria-current="page">Integration Guide for WASM Plugins</a></li></ul></div><div class="tsd-panel tsd-typography"><h1 id="integration-guide-for-wasm-plugins" class="tsd-anchor-link">Integration Guide for WASM Plugins<a href="#integration-guide-for-wasm-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> <h2 id="static-file-serving" class="tsd-anchor-link">Static File Serving<a href="#static-file-serving" 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 serve HTML, CSS, JavaScript and other static files:</p> <p><strong>Structure:</strong></p> <pre><code><span class="hl-0">@signalk</span><span class="hl-1">/</span><span class="hl-0">my</span><span class="hl-1">-</span><span class="hl-0">plugin</span><span class="hl-1">/</span><br/><span class="hl-0">├── public</span><span class="hl-1">/</span><span class="hl-0"> # Automatically served at </span><span class="hl-1">/</span><span class="hl-0">plugins</span><span class="hl-1">/</span><span class="hl-0">my</span><span class="hl-1">-</span><span class="hl-0">plugin</span><span class="hl-1">/</span><br/><span class="hl-0">│ ├── index.html</span><br/><span class="hl-0">│ ├── style.css</span><br/><span class="hl-0">│ └── app.js</span><br/><span class="hl-0">├── plugin.wasm</span><br/><span class="hl-0">└── package.json</span> </code><button>Copy</button></pre> <p><strong>Access:</strong> <code>http://localhost:3000/plugins/my-plugin/</code> serves <code>public/index.html</code></p> <h2 id="resource-providers" class="tsd-anchor-link">Resource Providers<a href="#resource-providers" 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>WASM plugins can act as <strong>resource providers</strong> for Signal K resources like weather data, routes, waypoints, or custom resource types.</p> <h3 id="enabling-resource-provider-capability" class="tsd-anchor-link">Enabling Resource Provider Capability<a href="#enabling-resource-provider-capability" 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>Add <code>resourceProvider: true</code> to your package.json:</p> <pre><code class="json"><span class="hl-0">{</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;wasmCapabilities&quot;</span><span class="hl-0">: {</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;network&quot;</span><span class="hl-0">: </span><span class="hl-2">true</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;dataRead&quot;</span><span class="hl-0">: </span><span class="hl-2">true</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;dataWrite&quot;</span><span class="hl-0">: </span><span class="hl-2">true</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;resourceProvider&quot;</span><span class="hl-0">: </span><span class="hl-2">true</span><br/><span class="hl-0"> }</span><br/><span class="hl-0">}</span> </code><button type="button">Copy</button></pre> <h3 id="registering-as-a-resource-provider" class="tsd-anchor-link">Registering as a Resource Provider<a href="#registering-as-a-resource-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></h3> <h4 id="assemblyscript" class="tsd-anchor-link">AssemblyScript<a href="#assemblyscript" 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> <pre><code class="typescript"><span class="hl-1">import</span><span class="hl-0"> { registerResourceProvider } </span><span class="hl-1">from</span><span class="hl-0"> </span><span class="hl-4">&#39;@signalk/assemblyscript-plugin-sdk/assembly/resources&#39;</span><br/><br/><span class="hl-6">// In plugin start():</span><br/><span class="hl-1">if</span><span class="hl-0"> (</span><span class="hl-1">!</span><span class="hl-7">registerResourceProvider</span><span class="hl-0">(</span><span class="hl-4">&#39;weather-forecasts&#39;</span><span class="hl-0">)) {</span><br/><span class="hl-0"> </span><span class="hl-7">setError</span><span class="hl-0">(</span><span class="hl-4">&#39;Failed to register as resource provider&#39;</span><span class="hl-0">)</span><br/><span class="hl-0"> </span><span class="hl-1">return</span><span class="hl-0"> </span><span class="hl-2">1</span><br/><span class="hl-0">}</span> </code><button type="button">Copy</button></pre> <h4 id="rust" class="tsd-anchor-link">Rust<a href="#rust" 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> <pre><code class="rust"><span class="hl-0">#[link(wasm_import_module </span><span class="hl-1">=</span><span class="hl-0"> </span><span class="hl-4">&quot;env&quot;</span><span class="hl-0">)]</span><br/><span class="hl-1">extern</span><span class="hl-0"> </span><span class="hl-4">&quot;C&quot;</span><span class="hl-0"> {</span><br/><span class="hl-0"> </span><span class="hl-1">fn</span><span class="hl-0"> </span><span class="hl-7">sk_register_resource_provider</span><span class="hl-0">(type_ptr</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-1">*const</span><span class="hl-0"> </span><span class="hl-5">u8</span><span class="hl-0">, type_len</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-5">usize</span><span class="hl-0">) </span><span class="hl-1">-&gt;</span><span class="hl-0"> </span><span class="hl-5">i32</span><span class="hl-0">;</span><br/><span class="hl-0">}</span><br/><br/><span class="hl-1">pub</span><span class="hl-0"> </span><span class="hl-1">fn</span><span class="hl-0"> </span><span class="hl-7">register_resource_provider</span><span class="hl-0">(resource_type</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-1">&amp;</span><span class="hl-5">str</span><span class="hl-0">) </span><span class="hl-1">-&gt;</span><span class="hl-0"> </span><span class="hl-5">bool</span><span class="hl-0"> {</span><br/><span class="hl-0"> </span><span class="hl-1">let</span><span class="hl-0"> bytes </span><span class="hl-1">=</span><span class="hl-0"> resource_type</span><span class="hl-1">.</span><span class="hl-7">as_bytes</span><span class="hl-0">();</span><br/><span class="hl-0"> </span><span class="hl-1">unsafe</span><span class="hl-0"> { </span><span class="hl-7">sk_register_resource_provider</span><span class="hl-0">(bytes</span><span class="hl-1">.</span><span class="hl-7">as_ptr</span><span class="hl-0">(), bytes</span><span class="hl-1">.</span><span class="hl-7">len</span><span class="hl-0">()) </span><span class="hl-1">==</span><span class="hl-0"> </span><span class="hl-2">1</span><span class="hl-0"> }</span><br/><span class="hl-0">}</span><br/><br/><span class="hl-6">// In plugin_start():</span><br/><span class="hl-1">if</span><span class="hl-0"> </span><span class="hl-1">!</span><span class="hl-7">register_resource_provider</span><span class="hl-0">(</span><span class="hl-4">&quot;weather-forecasts&quot;</span><span class="hl-0">) {</span><br/><span class="hl-0"> </span><span class="hl-6">// Registration failed</span><br/><span class="hl-0"> </span><span class="hl-1">return</span><span class="hl-0"> </span><span class="hl-2">1</span><span class="hl-0">;</span><br/><span class="hl-0">}</span> </code><button type="button">Copy</button></pre> <h3 id="implementing-resource-handlers" class="tsd-anchor-link">Implementing Resource Handlers<a href="#implementing-resource-handlers" 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>After registering, your plugin must export these handler functions:</p> <h4 id="-list-resources-matching-a-query" class="tsd-anchor-link"><code>resources_list_resources</code> - List resources matching a query<a href="#-list-resources-matching-a-query" 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><strong>AssemblyScript:</strong></p> <pre><code class="typescript"><span class="hl-1">export</span><span class="hl-0"> </span><span class="hl-1">function</span><span class="hl-0"> </span><span class="hl-7">resources_list_resources</span><span class="hl-0">(</span><span class="hl-5">queryJson</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-2">string</span><span class="hl-0">)</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-2">string</span><span class="hl-0"> {</span><br/><span class="hl-0"> </span><span class="hl-6">// queryJson: {&quot;bbox&quot;: [...], &quot;distance&quot;: 1000, ...}</span><br/><span class="hl-0"> </span><span class="hl-6">// Return JSON object: {&quot;resource-id-1&quot;: {...}, &quot;resource-id-2&quot;: {...}}</span><br/><span class="hl-0"> </span><span class="hl-1">return</span><span class="hl-0"> </span><span class="hl-4">&#39;{&quot;forecast-1&quot;: {&quot;name&quot;: &quot;Current Weather&quot;, &quot;type&quot;: &quot;weather&quot;}}&#39;</span><br/><span class="hl-0">}</span> </code><button type="button">Copy</button></pre> <p><strong>Rust:</strong></p> <pre><code class="rust"><span class="hl-0">#[no_mangle]</span><br/><span class="hl-1">pub</span><span class="hl-0"> </span><span class="hl-1">extern</span><span class="hl-0"> </span><span class="hl-4">&quot;C&quot;</span><span class="hl-0"> </span><span class="hl-1">fn</span><span class="hl-0"> </span><span class="hl-7">resources_list_resources</span><span class="hl-0">(</span><br/><span class="hl-0"> request_ptr</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-1">*const</span><span class="hl-0"> </span><span class="hl-5">u8</span><span class="hl-0">, request_len</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-5">usize</span><span class="hl-0">,</span><br/><span class="hl-0"> response_ptr</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-1">*mut</span><span class="hl-0"> </span><span class="hl-5">u8</span><span class="hl-0">, response_max_len</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-5">usize</span><span class="hl-0">,</span><br/><span class="hl-0">) </span><span class="hl-1">-&gt;</span><span class="hl-0"> </span><span class="hl-5">i32</span><span class="hl-0"> {</span><br/><span class="hl-0"> </span><span class="hl-6">// Parse query, build response</span><br/><span class="hl-0"> </span><span class="hl-1">let</span><span class="hl-0"> response </span><span class="hl-1">=</span><span class="hl-0"> </span><span class="hl-4">r#&quot;{&quot;forecast-1&quot;: {&quot;name&quot;: &quot;Current Weather&quot;}}&quot;#</span><span class="hl-0">;</span><br/><span class="hl-0"> </span><span class="hl-7">write_string</span><span class="hl-0">(response, response_ptr, response_max_len)</span><br/><span class="hl-0">}</span> </code><button type="button">Copy</button></pre> <h4 id="-get-a-single-resource" class="tsd-anchor-link"><code>resources_get_resource</code> - Get a single resource<a href="#-get-a-single-resource" 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><strong>AssemblyScript:</strong></p> <pre><code class="typescript"><span class="hl-1">export</span><span class="hl-0"> </span><span class="hl-1">function</span><span class="hl-0"> </span><span class="hl-7">resources_get_resource</span><span class="hl-0">(</span><span class="hl-5">requestJson</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-2">string</span><span class="hl-0">)</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-2">string</span><span class="hl-0"> {</span><br/><span class="hl-0"> </span><span class="hl-6">// requestJson: {&quot;id&quot;: &quot;forecast-1&quot;, &quot;property&quot;: null}</span><br/><span class="hl-0"> </span><span class="hl-1">return</span><span class="hl-0"> </span><span class="hl-4">&#39;{&quot;name&quot;: &quot;Current Weather&quot;, &quot;temperature&quot;: 20.5, &quot;humidity&quot;: 0.65}&#39;</span><br/><span class="hl-0">}</span> </code><button type="button">Copy</button></pre> <h4 id="-create-or-update-a-resource" class="tsd-anchor-link"><code>resources_set_resource</code> - Create or update a resource<a href="#-create-or-update-a-resource" 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><strong>AssemblyScript:</strong></p> <pre><code class="typescript"><span class="hl-1">export</span><span class="hl-0"> </span><span class="hl-1">function</span><span class="hl-0"> </span><span class="hl-7">resources_set_resource</span><span class="hl-0">(</span><span class="hl-5">requestJson</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-2">string</span><span class="hl-0">)</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-2">string</span><span class="hl-0"> {</span><br/><span class="hl-0"> </span><span class="hl-6">// requestJson: {&quot;id&quot;: &quot;forecast-1&quot;, &quot;value&quot;: {...}}</span><br/><span class="hl-0"> </span><span class="hl-6">// Return empty string on success, or error message</span><br/><span class="hl-0"> </span><span class="hl-1">return</span><span class="hl-0"> </span><span class="hl-4">&#39;&#39;</span><br/><span class="hl-0">}</span> </code><button type="button">Copy</button></pre> <h4 id="-delete-a-resource" class="tsd-anchor-link"><code>resources_delete_resource</code> - Delete a resource<a href="#-delete-a-resource" 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><strong>AssemblyScript:</strong></p> <pre><code class="typescript"><span class="hl-1">export</span><span class="hl-0"> </span><span class="hl-1">function</span><span class="hl-0"> </span><span class="hl-7">resources_delete_resource</span><span class="hl-0">(</span><span class="hl-5">requestJson</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-2">string</span><span class="hl-0">)</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-2">string</span><span class="hl-0"> {</span><br/><span class="hl-0"> </span><span class="hl-6">// requestJson: {&quot;id&quot;: &quot;forecast-1&quot;}</span><br/><span class="hl-0"> </span><span class="hl-1">return</span><span class="hl-0"> </span><span class="hl-4">&#39;&#39;</span><br/><span class="hl-0">}</span> </code><button type="button">Copy</button></pre> <h3 id="accessing-resources-via-http" class="tsd-anchor-link">Accessing Resources via HTTP<a href="#accessing-resources-via-http" 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 registered, resources are available at:</p> <pre><code><span class="hl-2">GET</span><span class="hl-0"> </span><span class="hl-1">/</span><span class="hl-0">signalk</span><span class="hl-1">/</span><span class="hl-0">v2</span><span class="hl-1">/</span><span class="hl-0">api</span><span class="hl-1">/</span><span class="hl-0">resources</span><span class="hl-1">/</span><span class="hl-0">{type} # List all</span><br/><span class="hl-2">GET</span><span class="hl-0"> </span><span class="hl-1">/</span><span class="hl-0">signalk</span><span class="hl-1">/</span><span class="hl-0">v2</span><span class="hl-1">/</span><span class="hl-0">api</span><span class="hl-1">/</span><span class="hl-0">resources</span><span class="hl-1">/</span><span class="hl-0">{type}</span><span class="hl-1">/</span><span class="hl-0">{id} # Get one</span><br/><span class="hl-2">POST</span><span class="hl-0"> </span><span class="hl-1">/</span><span class="hl-0">signalk</span><span class="hl-1">/</span><span class="hl-0">v2</span><span class="hl-1">/</span><span class="hl-0">api</span><span class="hl-1">/</span><span class="hl-0">resources</span><span class="hl-1">/</span><span class="hl-0">{type}</span><span class="hl-1">/</span><span class="hl-0">{id} # Create</span><span class="hl-1">/</span><span class="hl-0">update</span><br/><span class="hl-2">DELETE</span><span class="hl-0"> </span><span class="hl-1">/</span><span class="hl-0">signalk</span><span class="hl-1">/</span><span class="hl-0">v2</span><span class="hl-1">/</span><span class="hl-0">api</span><span class="hl-1">/</span><span class="hl-0">resources</span><span class="hl-1">/</span><span class="hl-0">{type}</span><span class="hl-1">/</span><span class="hl-0">{id} # Delete</span> </code><button>Copy</button></pre> <h3 id="standard-vs-custom-resource-types" class="tsd-anchor-link">Standard vs Custom Resource Types<a href="#standard-vs-custom-resource-types" 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>Signal K defines standard resource types with validation:</p> <ul> <li><code>routes</code> - Navigation routes</li> <li><code>waypoints</code> - Navigation waypoints</li> <li><code>notes</code> - Freeform notes</li> <li><code>regions</code> - Geographic regions</li> <li><code>charts</code> - Chart metadata</li> </ul> <p>Custom types (like <code>weather-forecasts</code>) have no schema validation and can contain any JSON structure.</p> <h2 id="weather-providers" class="tsd-anchor-link">Weather Providers<a href="#weather-providers" 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>WASM plugins can act as <strong>weather providers</strong> for Signal K's specialized Weather API.</p> <h3 id="weather-provider-vs-resource-provider" class="tsd-anchor-link">Weather Provider vs Resource Provider<a href="#weather-provider-vs-resource-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></h3> <table> <thead> <tr> <th>Feature</th> <th>Weather Provider</th> <th>Resource Provider</th> </tr> </thead> <tbody> <tr> <td>API Path</td> <td><code>/signalk/v2/api/weather/*</code></td> <td><code>/signalk/v2/api/resources/{type}</code></td> </tr> <tr> <td>Methods</td> <td>getObservations, getForecasts, getWarnings</td> <td>list, get, set, delete</td> </tr> <tr> <td>Use Case</td> <td>Standardized weather data</td> <td>Generic data storage</td> </tr> <tr> <td>Capability</td> <td><code>weatherProvider: true</code></td> <td><code>resourceProvider: true</code></td> </tr> <tr> <td>FFI</td> <td><code>sk_register_weather_provider</code></td> <td><code>sk_register_resource_provider</code></td> </tr> </tbody> </table> <h3 id="enabling-weather-provider-capability" class="tsd-anchor-link">Enabling Weather Provider Capability<a href="#enabling-weather-provider-capability" 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> <pre><code class="json"><span class="hl-0">{</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;wasmCapabilities&quot;</span><span class="hl-0">: {</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;network&quot;</span><span class="hl-0">: </span><span class="hl-2">true</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;dataWrite&quot;</span><span class="hl-0">: </span><span class="hl-2">true</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;weatherProvider&quot;</span><span class="hl-0">: </span><span class="hl-2">true</span><br/><span class="hl-0"> }</span><br/><span class="hl-0">}</span> </code><button type="button">Copy</button></pre> <h3 id="implementing-weather-handler-exports" class="tsd-anchor-link">Implementing Weather Handler Exports<a href="#implementing-weather-handler-exports" 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>Your plugin must export these handler functions:</p> <h4 id="-get-current-weather-observations" class="tsd-anchor-link"><code>weather_get_observations</code> - Get current weather observations<a href="#-get-current-weather-observations" 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> <pre><code class="typescript"><span class="hl-1">export</span><span class="hl-0"> </span><span class="hl-1">function</span><span class="hl-0"> </span><span class="hl-7">weather_get_observations</span><span class="hl-0">(</span><span class="hl-5">requestJson</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-2">string</span><span class="hl-0">)</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-2">string</span><span class="hl-0"> {</span><br/><span class="hl-0"> </span><span class="hl-6">// requestJson: {&quot;position&quot;: {&quot;latitude&quot;: 60.17, &quot;longitude&quot;: 24.94}, &quot;options&quot;: {...}}</span><br/><span class="hl-0"> </span><span class="hl-1">return</span><span class="hl-0"> (</span><br/><span class="hl-0"> </span><span class="hl-4">&#39;[{&quot;date&quot;:&quot;2025-01-01T00:00:00Z&quot;,&quot;type&quot;:&quot;observation&quot;,&quot;description&quot;:&quot;Clear sky&quot;,&#39;</span><span class="hl-0"> </span><span class="hl-1">+</span><br/><span class="hl-0"> </span><span class="hl-4">&#39;&quot;outside&quot;:{&quot;temperature&quot;:280.15,&quot;relativeHumidity&quot;:0.65,&quot;pressure&quot;:101300,&quot;cloudCover&quot;:0.1},&#39;</span><span class="hl-0"> </span><span class="hl-1">+</span><br/><span class="hl-0"> </span><span class="hl-4">&#39;&quot;wind&quot;:{&quot;speedTrue&quot;:5.0,&quot;directionTrue&quot;:1.57}}]&#39;</span><br/><span class="hl-0"> )</span><br/><span class="hl-0">}</span> </code><button type="button">Copy</button></pre> <h4 id="-get-weather-forecasts" class="tsd-anchor-link"><code>weather_get_forecasts</code> - Get weather forecasts<a href="#-get-weather-forecasts" 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> <pre><code class="typescript"><span class="hl-1">export</span><span class="hl-0"> </span><span class="hl-1">function</span><span class="hl-0"> </span><span class="hl-7">weather_get_forecasts</span><span class="hl-0">(</span><span class="hl-5">requestJson</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-2">string</span><span class="hl-0">)</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-2">string</span><span class="hl-0"> {</span><br/><span class="hl-0"> </span><span class="hl-6">// requestJson: {&quot;position&quot;: {...}, &quot;type&quot;: &quot;daily&quot;|&quot;point&quot;, &quot;options&quot;: {&quot;maxCount&quot;: 7}}</span><br/><span class="hl-0"> </span><span class="hl-1">return</span><span class="hl-0"> </span><span class="hl-4">&#39;[{&quot;date&quot;:&quot;...&quot;,&quot;type&quot;:&quot;daily&quot;,&quot;outside&quot;:{...},&quot;wind&quot;:{...}}]&#39;</span><br/><span class="hl-0">}</span> </code><button type="button">Copy</button></pre> <h4 id="-get-weather-warningsalerts" class="tsd-anchor-link"><code>weather_get_warnings</code> - Get weather warnings/alerts<a href="#-get-weather-warningsalerts" 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> <pre><code class="typescript"><span class="hl-1">export</span><span class="hl-0"> </span><span class="hl-1">function</span><span class="hl-0"> </span><span class="hl-7">weather_get_warnings</span><span class="hl-0">(</span><span class="hl-5">requestJson</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-2">string</span><span class="hl-0">)</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-2">string</span><span class="hl-0"> {</span><br/><span class="hl-0"> </span><span class="hl-6">// requestJson: {&quot;position&quot;: {...}}</span><br/><span class="hl-0"> </span><span class="hl-1">return</span><span class="hl-0"> </span><span class="hl-4">&#39;[]&#39;</span><br/><span class="hl-0">}</span> </code><button type="button">Copy</button></pre> <h3 id="weather-data-format" class="tsd-anchor-link">Weather Data Format<a href="#weather-data-format" 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> <h4 id="observationforecast-object" class="tsd-anchor-link">Observation/Forecast Object<a href="#observationforecast-object" 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> <pre><code class="json"><span class="hl-0">{</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;date&quot;</span><span class="hl-0">: </span><span class="hl-4">&quot;2025-12-05T10:00:00.000Z&quot;</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;type&quot;</span><span class="hl-0">: </span><span class="hl-4">&quot;observation&quot;</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;description&quot;</span><span class="hl-0">: </span><span class="hl-4">&quot;light rain&quot;</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;outside&quot;</span><span class="hl-0">: {</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;temperature&quot;</span><span class="hl-0">: </span><span class="hl-2">275.15</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;minTemperature&quot;</span><span class="hl-0">: </span><span class="hl-2">273.0</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;maxTemperature&quot;</span><span class="hl-0">: </span><span class="hl-2">278.0</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;feelsLikeTemperature&quot;</span><span class="hl-0">: </span><span class="hl-2">272.0</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;relativeHumidity&quot;</span><span class="hl-0">: </span><span class="hl-2">0.85</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;pressure&quot;</span><span class="hl-0">: </span><span class="hl-2">101300</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;cloudCover&quot;</span><span class="hl-0">: </span><span class="hl-2">0.75</span><br/><span class="hl-0"> },</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;wind&quot;</span><span class="hl-0">: {</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;speedTrue&quot;</span><span class="hl-0">: </span><span class="hl-2">5.2</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;directionTrue&quot;</span><span class="hl-0">: </span><span class="hl-2">3.14</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;gust&quot;</span><span class="hl-0">: </span><span class="hl-2">8.0</span><br/><span class="hl-0"> }</span><br/><span class="hl-0">}</span> </code><button type="button">Copy</button></pre> <p>Units:</p> <ul> <li>Temperature: Kelvin</li> <li>Humidity: Ratio (0-1)</li> <li>Pressure: Pascals</li> <li>Wind speed: m/s</li> <li>Wind direction: Radians</li> </ul> <h4 id="warning-object" class="tsd-anchor-link">Warning Object<a href="#warning-object" 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> <pre><code class="json"><span class="hl-0">{</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;startTime&quot;</span><span class="hl-0">: </span><span class="hl-4">&quot;2025-12-05T10:00:00.000Z&quot;</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;endTime&quot;</span><span class="hl-0">: </span><span class="hl-4">&quot;2025-12-05T18:00:00.000Z&quot;</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;details&quot;</span><span class="hl-0">: </span><span class="hl-4">&quot;Strong wind warning&quot;</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;source&quot;</span><span class="hl-0">: </span><span class="hl-4">&quot;Weather Service&quot;</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;type&quot;</span><span class="hl-0">: </span><span class="hl-4">&quot;Warning&quot;</span><br/><span class="hl-0">}</span> </code><button type="button">Copy</button></pre> <h3 id="accessing-weather-data-via-http" class="tsd-anchor-link">Accessing Weather Data via HTTP<a href="#accessing-weather-data-via-http" 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> <pre><code class="bash"><span class="hl-6"># List providers</span><br/><span class="hl-5">curl</span><span class="hl-0"> </span><span class="hl-4">http://localhost:3000/signalk/v2/api/weather/_providers</span><br/><br/><span class="hl-6"># Get observations for a location</span><br/><span class="hl-5">curl</span><span class="hl-0"> </span><span class="hl-4">&quot;http://localhost:3000/signalk/v2/api/weather/observations?lat=60.17&amp;lon=24.94&quot;</span><br/><br/><span class="hl-6"># Get daily forecasts</span><br/><span class="hl-5">curl</span><span class="hl-0"> </span><span class="hl-4">&quot;http://localhost:3000/signalk/v2/api/weather/forecasts/daily?lat=60.17&amp;lon=24.94&quot;</span><br/><br/><span class="hl-6"># Get point-in-time forecasts</span><br/><span class="hl-5">curl</span><span class="hl-0"> </span><span class="hl-4">&quot;http://localhost:3000/signalk/v2/api/weather/forecasts/point?lat=60.17&amp;lon=24.94&quot;</span><br/><br/><span class="hl-6"># Get weather warnings</span><br/><span class="hl-5">curl</span><span class="hl-0"> </span><span class="hl-4">&quot;http://localhost:3000/signalk/v2/api/weather/warnings?lat=60.17&amp;lon=24.94&quot;</span> </code><button type="button">Copy</button></pre> <h2 id="radar-providers" class="tsd-anchor-link">Radar Providers<a href="#radar-providers" 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>WASM plugins can act as <strong>radar providers</strong> for Signal K's Radar API at <code>/signalk/v2/api/vessels/self/radars</code>.</p> <h3 id="enabling-radar-provider-capability" class="tsd-anchor-link">Enabling Radar Provider Capability<a href="#enabling-radar-provider-capability" 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> <pre><code class="json"><span class="hl-0">{</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;signalk&quot;</span><span class="hl-0">: {</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;wasmCapabilities&quot;</span><span class="hl-0">: {</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;radarProvider&quot;</span><span class="hl-0">: </span><span class="hl-2">true</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">&quot;network&quot;</span><span class="hl-0">: </span><span class="hl-2">true</span><br/><span class="hl-0"> }</span><br/><span class="hl-0"> }</span><br/><span class="hl-0">}</span> </code><button type="button">Copy</button></pre> <h3 id="registering-as-a-radar-provider" class="tsd-anchor-link">Registering as a Radar Provider<a href="#registering-as-a-radar-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></h3> <pre><code class="typescript"><span class="hl-6">// Declare the host function</span><br/><span class="hl-0">@</span><span class="hl-7">external</span><span class="hl-0">(</span><span class="hl-4">&quot;env&quot;</span><span class="hl-0">, </span><span class="hl-4">&quot;sk_register_radar_provider&quot;</span><span class="hl-0">)</span><br/><span class="hl-1">declare</span><span class="hl-0"> </span><span class="hl-1">function</span><span class="hl-0"> </span><span class="hl-7">sk_register_radar_provider</span><span class="hl-0">(</span><span class="hl-5">namePtr</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-5">usize</span><span class="hl-0">, </span><span class="hl-5">nameLen</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-5">i32</span><span class="hl-0">)</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-5">i32</span><span class="hl-0">;</span><br/><br/><span class="hl-1">export</span><span class="hl-0"> </span><span class="hl-1">function</span><span class="hl-0"> </span><span class="hl-7">start</span><span class="hl-0">(</span><span class="hl-5">configJson</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-2">string</span><span class="hl-0">)</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-5">i32</span><span class="hl-0"> {</span><br/><span class="hl-0"> </span><span class="hl-1">const</span><span class="hl-0"> </span><span class="hl-2">name</span><span class="hl-0"> </span><span class="hl-1">=</span><span class="hl-0"> </span><span class="hl-4">&quot;My Radar Plugin&quot;</span><span class="hl-0">;</span><br/><span class="hl-0"> </span><span class="hl-1">const</span><span class="hl-0"> </span><span class="hl-2">nameBytes</span><span class="hl-0"> </span><span class="hl-1">=</span><span class="hl-0"> String.</span><span class="hl-2">UTF8</span><span class="hl-0">.</span><span class="hl-7">encode</span><span class="hl-0">(name);</span><br/><span class="hl-0"> </span><span class="hl-1">const</span><span class="hl-0"> </span><span class="hl-2">result</span><span class="hl-0"> </span><span class="hl-1">=</span><span class="hl-0"> </span><span class="hl-7">sk_register_radar_provider</span><span class="hl-0">(</span><br/><span class="hl-0"> </span><span class="hl-7">changetype</span><span class="hl-0">&lt;</span><span class="hl-5">usize</span><span class="hl-0">&gt;(nameBytes),</span><br/><span class="hl-0"> nameBytes.byteLength</span><br/><span class="hl-0"> );</span><br/><br/><span class="hl-0"> </span><span class="hl-1">if</span><span class="hl-0"> (result </span><span class="hl-1">===</span><span class="hl-0"> </span><span class="hl-2">0</span><span class="hl-0">) {</span><br/><span class="hl-0"> </span><span class="hl-7">sk_set_plugin_error</span><span class="hl-0">(</span><span class="hl-4">&quot;Failed to register as radar provider&quot;</span><span class="hl-0">, </span><span class="hl-2">38</span><span class="hl-0">);</span><br/><span class="hl-0"> </span><span class="hl-1">return</span><span class="hl-0"> </span><span class="hl-2">1</span><span class="hl-0">;</span><br/><span class="hl-0"> }</span><br/><br/><span class="hl-0"> </span><span class="hl-1">return</span><span class="hl-0"> </span><span class="hl-2">0</span><span class="hl-0">;</span><br/><span class="hl-0">}</span> </code><button type="button">Copy</button></pre> <h3 id="required-handler-exports" class="tsd-anchor-link">Required Handler Exports<a href="#required-handler-exports" 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> <pre><code class="typescript"><span class="hl-6">// Return JSON array of radar IDs this provider manages</span><br/><span class="hl-1">export</span><span class="hl-0"> </span><span class="hl-1">function</span><span class="hl-0"> </span><span class="hl-7">radar_get_radars</span><span class="hl-0">()</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-2">string</span><span class="hl-0"> {</span><br/><span class="hl-0"> </span><span class="hl-1">return</span><span class="hl-0"> </span><span class="hl-2">JSON</span><span class="hl-0">.</span><span class="hl-7">stringify</span><span class="hl-0">([</span><span class="hl-4">&#39;radar-0&#39;</span><span class="hl-0">, </span><span class="hl-4">&#39;radar-1&#39;</span><span class="hl-0">])</span><br/><span class="hl-0">}</span><br/><br/><span class="hl-6">// Return RadarInfo JSON for a specific radar</span><br/><span class="hl-1">export</span><span class="hl-0"> </span><span class="hl-1">function</span><span class="hl-0"> </span><span class="hl-7">radar_get_radar_info</span><span class="hl-0">(</span><span class="hl-5">requestJson</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-2">string</span><span class="hl-0">)</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-2">string</span><span class="hl-0"> {</span><br/><span class="hl-0"> </span><span class="hl-1">const</span><span class="hl-0"> </span><span class="hl-2">info</span><span class="hl-0"> </span><span class="hl-1">=</span><span class="hl-0"> {</span><br/><span class="hl-0"> id: </span><span class="hl-4">&#39;radar-0&#39;</span><span class="hl-0">,</span><br/><span class="hl-0"> name: </span><span class="hl-4">&#39;Furuno DRS4D-NXT&#39;</span><span class="hl-0">,</span><br/><span class="hl-0"> brand: </span><span class="hl-4">&#39;Furuno&#39;</span><span class="hl-0">,</span><br/><span class="hl-0"> status: </span><span class="hl-4">&#39;transmit&#39;</span><span class="hl-0">,</span><br/><span class="hl-0"> spokesPerRevolution: </span><span class="hl-2">2048</span><span class="hl-0">,</span><br/><span class="hl-0"> maxSpokeLen: </span><span class="hl-2">1024</span><span class="hl-0">,</span><br/><span class="hl-0"> range: </span><span class="hl-2">2000</span><span class="hl-0">,</span><br/><span class="hl-0"> controls: {</span><br/><span class="hl-0"> gain: { auto: </span><span class="hl-2">false</span><span class="hl-0">, value: </span><span class="hl-2">50</span><span class="hl-0"> },</span><br/><span class="hl-0"> sea: { auto: </span><span class="hl-2">true</span><span class="hl-0">, value: </span><span class="hl-2">30</span><span class="hl-0"> }</span><br/><span class="hl-0"> }</span><br/><span class="hl-0"> }</span><br/><span class="hl-0"> </span><span class="hl-1">return</span><span class="hl-0"> </span><span class="hl-2">JSON</span><span class="hl-0">.</span><span class="hl-7">stringify</span><span class="hl-0">(info)</span><br/><span class="hl-0">}</span> </code><button type="button">Copy</button></pre> <h3 id="radarinfo-interface" class="tsd-anchor-link">RadarInfo Interface<a href="#radarinfo-interface" 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> <pre><code class="typescript"><span class="hl-1">interface</span><span class="hl-0"> </span><span class="hl-5">RadarInfo</span><span class="hl-0"> {</span><br/><span class="hl-0"> </span><span class="hl-5">id</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-2">string</span><span class="hl-0"> </span><span class="hl-6">// Unique radar ID</span><br/><span class="hl-0"> </span><span class="hl-5">name</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-2">string</span><span class="hl-0"> </span><span class="hl-6">// Display name</span><br/><span class="hl-0"> </span><span class="hl-5">brand</span><span class="hl-1">?:</span><span class="hl-0"> </span><span class="hl-2">string</span><span class="hl-0"> </span><span class="hl-6">// Manufacturer</span><br/><span class="hl-0"> </span><span class="hl-5">status</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-4">&#39;off&#39;</span><span class="hl-0"> </span><span class="hl-1">|</span><span class="hl-0"> </span><span class="hl-4">&#39;standby&#39;</span><span class="hl-0"> </span><span class="hl-1">|</span><span class="hl-0"> </span><span class="hl-4">&#39;transmit&#39;</span><span class="hl-0"> </span><span class="hl-1">|</span><span class="hl-0"> </span><span class="hl-4">&#39;warming&#39;</span><br/><span class="hl-0"> </span><span class="hl-5">spokesPerRevolution</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-2">number</span><span class="hl-0"> </span><span class="hl-6">// Spokes per rotation</span><br/><span class="hl-0"> </span><span class="hl-5">maxSpokeLen</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-2">number</span><span class="hl-0"> </span><span class="hl-6">// Max spoke samples</span><br/><span class="hl-0"> </span><span class="hl-5">range</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-2">number</span><span class="hl-0"> </span><span class="hl-6">// Current range (meters)</span><br/><span class="hl-0"> </span><span class="hl-5">controls</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-5">RadarControls</span><span class="hl-0"> </span><span class="hl-6">// Current control values</span><br/><span class="hl-0"> </span><span class="hl-5">legend</span><span class="hl-1">?:</span><span class="hl-0"> </span><span class="hl-5">LegendEntry</span><span class="hl-0">[] </span><span class="hl-6">// Color legend for display</span><br/><span class="hl-0"> </span><span class="hl-5">streamUrl</span><span class="hl-1">?:</span><span class="hl-0"> </span><span class="hl-2">string</span><span class="hl-0"> </span><span class="hl-6">// Optional external WebSocket URL</span><br/><span class="hl-0">}</span> </code><button type="button">Copy</button></pre> <h3 id="streaming-radar-spokes" class="tsd-anchor-link">Streaming Radar Spokes<a href="#streaming-radar-spokes" 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>Radar spoke data arrives at ~60Hz (2048 spokes/rotation × 30-60 RPM). Plugins stream binary protobuf data directly to clients:</p> <pre><code class="typescript"><span class="hl-1">import</span><span class="hl-0"> { sk_radar_emit_spokes } </span><span class="hl-1">from</span><span class="hl-0"> </span><span class="hl-4">&#39;./signalk-