signalk-server
Version:
An implementation of a [Signal K](http://signalk.org) server for boats.
193 lines (189 loc) • 29.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>Unit Preferences | 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="../Guides.html">Guides</a></li><li><a href="" aria-current="page">Unit Preferences</a></li></ul></div><div class="tsd-panel tsd-typography"><h1 id="unit-preferences" class="tsd-anchor-link">Unit Preferences<a href="#unit-preferences" 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>This guide describes the unit preferences mechanism in Signal K Server.</p>
<h2 id="for-end-users" class="tsd-anchor-link">For End Users<a href="#for-end-users" 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 allows you to define your preferred units for different categories of data (e.g., Speed, Depth, Temperature) centrally. These settings are applied across all compatible apps and dashboards.</p>
<h3 id="changing-unit-settings" class="tsd-anchor-link">Changing Unit Settings<a href="#changing-unit-settings" 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>You can configure your unit preferences in the Signal K Server Admin UI.</p>
<ol>
<li>Open the <strong>Server Admin</strong> interface.</li>
<li>Navigate to <strong>Server > Configuration > Settings</strong>.</li>
<li>Scroll down to the <strong>Unit Preferences</strong> section.</li>
</ol>
<h3 id="available-settings" class="tsd-anchor-link">Available Settings<a href="#available-settings" 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="active-preset" class="tsd-anchor-link">Active Preset<a href="#active-preset" 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>The simplest way to configure units is to select a <strong>Preset</strong>. A preset is a collection of unit preferences for all standard categories.</p>
<p>Available presets:</p>
<ul>
<li><strong>Metric</strong>: km/h, kilometers, meters, Celsius, liters.</li>
<li><strong>Imperial (US)</strong>: mph, miles, feet, Fahrenheit, US gallons.</li>
<li><strong>Imperial (UK)</strong>: mph, miles, feet, Celsius, UK gallons.</li>
<li><strong>Nautical (Metric)</strong>: knots, nautical miles, meters, Celsius, liters.</li>
<li><strong>Nautical Imperial (US)</strong>: knots, nautical miles, feet, Fahrenheit, US gallons.</li>
<li><strong>Nautical Imperial (UK)</strong>: knots, nautical miles, feet, Celsius, UK gallons.</li>
</ul>
<h4 id="per-user-settings" class="tsd-anchor-link">Per-User Settings<a href="#per-user-settings" 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>Preferences are stored <strong>per user</strong>. If you log in with your user account, your unit settings will follow you across different devices. If no user is logged in (or for anonymous users), the server's global default preset (configured by the administrator) is used.</p>
<h4 id="custom-presets" class="tsd-anchor-link">Custom Presets<a href="#custom-presets" 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>Advanced users can upload <strong>Custom Presets</strong> to define specific combinations of units that aren't covered by the built-in options.</p>
<h3 id="overriding-specific-paths" class="tsd-anchor-link">Overriding Specific Paths<a href="#overriding-specific-paths" 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>In addition to category-wide settings (e.g., "All speeds in Knots"), you can override units for specific data paths. For example, you might want <em>Boat Speed</em> in Knots but <em>Wind Speed</em> in Meters/Second.</p>
<p>These overrides are typically managed by editing the server configuration. When a specific path has an override, it takes precedence over the general category setting in your active preset.</p>
<hr>
<h2 id="unit-categories" class="tsd-anchor-link">Unit Categories<a href="#unit-categories" 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>Unit categories are the mechanism that allows the server to apply unit preferences to a wide range of data paths without needing configuration for every single path.</p>
<h3 id="how-categories-work" class="tsd-anchor-link">How Categories Work<a href="#how-categories-work" 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><strong>Categorization</strong>: Every numeric Signal K path is assigned to a <strong>Category</strong> (e.g., <code>speed</code>, <code>temperature</code>, <code>depth</code>). This assignment is defined in the server's default configuration but can be customized.</li>
<li><strong>Base Unit</strong>: The category defines the <strong>Base Unit</strong> (usually the SI unit) that the raw data is expected to be in. For example, the <code>speed</code> category expects <code>m/s</code>.</li>
<li><strong>Target Unit</strong>: Your active Preset defines a <strong>Target Unit</strong> for each category. For example, your preset might map the <code>speed</code> category to <code>kn</code> (knots).</li>
<li><strong>Conversion</strong>: When data is requested, the server looks up the path's category, finds the target unit from your preset, and provides the conversion formula.</li>
</ol>
<p>This system means that if you set your <code>speed</code> preference to Knots, it applies to <em>Boat Speeds</em>, <em>Wind Speeds</em> and any other path assigned to the <code>speed</code> category.</p>
<h3 id="standard-categories" class="tsd-anchor-link">Standard Categories<a href="#standard-categories" 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 following categories are available by default:</p>
<ul>
<li><strong>speed</strong>: Speed measurements (Base: m/s). Examples: <code>navigation.speedOverGround</code>, <code>environment.wind.speedTrue</code>.</li>
<li><strong>distance</strong>: Longer distances (Base: m). Examples: <code>navigation.log</code>, <code>navigation.courseRhumbline.nextPoint.distance</code>.</li>
<li><strong>depth</strong>: Vertical distances/depths (Base: m). Examples: <code>environment.depth.belowTransducer</code>, <code>environment.depth.belowKeel</code>.</li>
<li><strong>length</strong>: Dimensions of the vessel or objects (Base: m). Examples: <code>design.length.overall</code>, <code>design.airHeight</code>.</li>
<li><strong>temperature</strong>: Temperature readings (Base: K). Examples: <code>environment.outside.temperature</code>, <code>propulsion.*.temperature</code>.</li>
<li><strong>pressure</strong>: Pressure readings (Base: Pa). Examples: <code>environment.outside.pressure</code>, <code>propulsion.*.oilPressure</code>.</li>
<li><strong>angle</strong>: Angles (Base: rad). Examples: <code>environment.wind.angleApparent</code>, <code>navigation.headingMagnetic</code>.</li>
<li><strong>angularVelocity</strong>: Rate of turn (Base: rad/s). Examples: <code>navigation.rateOfTurn</code>.</li>
<li><strong>volume</strong>: Liquid volumes (Base: m³). Examples: <code>tanks.*.currentLevel</code>.</li>
<li><strong>volumeRate</strong>: Flow rates (Base: m³/s). Examples: <code>propulsion.*.fuel.rate</code>.</li>
<li><strong>mass</strong>: Weight/Mass (Base: kg).</li>
<li><strong>electrical</strong>:
<ul>
<li><strong>voltage</strong> (Base: V). Examples: <code>electrical.batteries.*.voltage</code>.</li>
<li><strong>current</strong> (Base: A). Examples: <code>electrical.batteries.*.current</code>.</li>
<li><strong>charge</strong> (Base: C). Examples: <code>electrical.batteries.*.capacity.stateOfCharge</code>.</li>
<li><strong>power</strong> (Base: W).</li>
<li><strong>energy</strong> (Base: J).</li>
</ul>
</li>
<li><strong>frequency</strong>: (Base: Hz). Examples: <code>propulsion.*.revolutions</code>.</li>
<li><strong>time</strong>: Durations (Base: s).</li>
<li><strong>percentage</strong>: Ratios and levels (Base: ratio 0-1). Examples: <code>tanks.*.currentLevel</code>, <code>electrical.batteries.*.capacity.stateOfCharge</code>.</li>
</ul>
<p>Additional categories include <code>dateTime</code>, <code>epoch</code> for time representations, and <code>unitless</code>/<code>boolean</code> for data that doesn't require conversion.</p>
<h2 id="for-client-application-developers" class="tsd-anchor-link">For Client Application Developers<a href="#for-client-application-developers" 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 Unit Preferences system simplifies client development by managing unit preferences centrally, on the server across all unit preferences aware client applications. As a developer, you don't need to maintain user preference settings in your application and can use the settings and conversion formulas provided by the server.</p>
<h3 id="how-it-works" class="tsd-anchor-link">How it Works<a href="#how-it-works" 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>When you fetch metadata for a path (e.g., <code>vessels.self.navigation.speedOverGround</code>), the server checks the active unit preferences and includes a <code>displayUnits</code> object in the meta data.</p>
<h3 id="rest-api-usage" class="tsd-anchor-link">REST API Usage<a href="#rest-api-usage" 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>Request the metadata for any path:</p>
<p><code>GET /signalk/v1/api/vessels/self/navigation/speedOverGround/meta</code></p>
<p><strong>Response Example:</strong></p>
<pre><code class="json"><span class="hl-0">{</span><br/><span class="hl-0"> </span><span class="hl-3">"units"</span><span class="hl-0">: </span><span class="hl-4">"m/s"</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">"description"</span><span class="hl-0">: </span><span class="hl-4">"Speed over ground"</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">"displayName"</span><span class="hl-0">: </span><span class="hl-4">"SOG"</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">"displayUnits"</span><span class="hl-0">: {</span><br/><span class="hl-0"> </span><span class="hl-3">"category"</span><span class="hl-0">: </span><span class="hl-4">"speed"</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">"targetUnit"</span><span class="hl-0">: </span><span class="hl-4">"kn"</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">"formula"</span><span class="hl-0">: </span><span class="hl-4">"value * 1.94384"</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">"inverseFormula"</span><span class="hl-0">: </span><span class="hl-4">"value / 1.94384"</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">"symbol"</span><span class="hl-0">: </span><span class="hl-4">"kn"</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">"displayFormat"</span><span class="hl-0">: </span><span class="hl-4">"0.0"</span><br/><span class="hl-0"> }</span><br/><span class="hl-0">}</span>
</code><button type="button">Copy</button></pre>
<p>The <code>displayUnits</code> object provides everything you need to display the value:</p>
<ul>
<li><strong>category</strong>: The unit category this path belongs to (e.g., "speed", "depth", "temperature").</li>
<li><strong>targetUnit</strong>: The unit the user wants to see (e.g., "kn" for knots).</li>
<li><strong>formula</strong>: A <a href="https://mathjs.org/">Math.js</a> expression to convert the raw SI value to the target unit. The variable <code>value</code> represents the input.</li>
<li><strong>inverseFormula</strong>: A Math.js expression to convert back from the display unit to SI (useful for user input).</li>
<li><strong>symbol</strong>: The symbol to display next to the value.</li>
<li><strong>displayFormat</strong>: (Optional) A format pattern for consistency (e.g., "0.0" for one decimal place).</li>
</ul>
<h3 id="websocket-stream" class="tsd-anchor-link">WebSocket Stream<a href="#websocket-stream" 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>When subscribing to the WebSocket stream, add <code>sendMeta=all</code> to receive metadata once for each path (sent with the first delta for that path, and again only if it changes):</p>
<pre><code class="javascript"><span class="hl-1">const</span><span class="hl-0"> </span><span class="hl-2">ws</span><span class="hl-0"> </span><span class="hl-1">=</span><span class="hl-0"> </span><span class="hl-1">new</span><span class="hl-0"> </span><span class="hl-7">WebSocket</span><span class="hl-0">(</span><span class="hl-4">'ws://localhost:3000/signalk/v1/stream?subscribe=none'</span><span class="hl-0">)</span><br/><br/><span class="hl-0">ws.</span><span class="hl-7">onopen</span><span class="hl-0"> </span><span class="hl-1">=</span><span class="hl-0"> () </span><span class="hl-1">=></span><span class="hl-0"> {</span><br/><span class="hl-0"> ws.</span><span class="hl-7">send</span><span class="hl-0">(</span><br/><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><br/><span class="hl-0"> context: </span><span class="hl-4">'vessels.self'</span><span class="hl-0">,</span><br/><span class="hl-0"> subscribe: [</span><br/><span class="hl-0"> {</span><br/><span class="hl-0"> path: </span><span class="hl-4">'navigation.speedOverGround'</span><span class="hl-0">,</span><br/><span class="hl-0"> policy: </span><span class="hl-4">'instant'</span><span class="hl-0">,</span><br/><span class="hl-0"> sendMeta: </span><span class="hl-4">'all'</span><br/><span class="hl-0"> }</span><br/><span class="hl-0"> ]</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>
<p><strong>Delta with Metadata:</strong></p>
<pre><code class="json"><span class="hl-0">{</span><br/><span class="hl-0"> </span><span class="hl-3">"context"</span><span class="hl-0">: </span><span class="hl-4">"vessels.urn:mrn:signalk:uuid:..."</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">"updates"</span><span class="hl-0">: [</span><br/><span class="hl-0"> {</span><br/><span class="hl-0"> </span><span class="hl-3">"values"</span><span class="hl-0">: [</span><br/><span class="hl-0"> {</span><br/><span class="hl-0"> </span><span class="hl-3">"path"</span><span class="hl-0">: </span><span class="hl-4">"navigation.speedOverGround"</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">"value"</span><span class="hl-0">: </span><span class="hl-2">5.14</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">"meta"</span><span class="hl-0">: {</span><br/><span class="hl-0"> </span><span class="hl-3">"units"</span><span class="hl-0">: </span><span class="hl-4">"m/s"</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">"description"</span><span class="hl-0">: </span><span class="hl-4">"Speed over ground"</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">"displayUnits"</span><span class="hl-0">: {</span><br/><span class="hl-0"> </span><span class="hl-3">"category"</span><span class="hl-0">: </span><span class="hl-4">"speed"</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">"targetUnit"</span><span class="hl-0">: </span><span class="hl-4">"kn"</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">"formula"</span><span class="hl-0">: </span><span class="hl-4">"value * 1.94384"</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">"inverseFormula"</span><span class="hl-0">: </span><span class="hl-4">"value / 1.94384"</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">"symbol"</span><span class="hl-0">: </span><span class="hl-4">"kn"</span><span class="hl-0">,</span><br/><span class="hl-0"> </span><span class="hl-3">"displayFormat"</span><span class="hl-0">: </span><span class="hl-4">"0.0"</span><br/><span class="hl-0"> }</span><br/><span class="hl-0"> }</span><br/><span class="hl-0"> }</span><br/><span class="hl-0"> ]</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>
<p>Using <code>sendMeta=all</code> eliminates the need for separate REST calls to fetch metadata.</p>
<h3 id="consuming-data" class="tsd-anchor-link">Consuming Data<a href="#consuming-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></h3>
<ol>
<li><strong>Get the value and metadata</strong> - Either subscribe to the WebSocket stream with <code>sendMeta=all</code> (recommended), or poll the REST API and fetch metadata separately.</li>
<li><strong>Check for <code>displayUnits</code></strong> - If present, the user has unit preferences configured.</li>
<li><strong>Convert the value</strong> - Evaluate the <code>formula</code> expression with the SI value as <code>value</code>.</li>
<li><strong>Display the result</strong> - Show the converted value with the provided <code>symbol</code> and <code>displayFormat</code>.</li>
</ol>
<p>This ensures that if the user changes their preferences (e.g., from "Knots" to "m/s" or "km/h") on the server, your application automatically reflects those changes without any code updates.</p>
<h3 id="api-endpoints" class="tsd-anchor-link">API Endpoints<a href="#api-endpoints" 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 unit preferences system exposes the following REST API endpoints:</p>
<table>
<thead>
<tr>
<th>Method</th>
<th>Endpoint</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>GET</td>
<td><code>/signalk/v1/unitpreferences/config</code></td>
<td>Get the current configuration</td>
</tr>
<tr>
<td>PUT</td>
<td><code>/signalk/v1/unitpreferences/config</code></td>
<td>Update the configuration</td>
</tr>
<tr>
<td>GET</td>
<td><code>/signalk/v1/unitpreferences/categories</code></td>
<td>Get all unit categories (merged standard + custom)</td>
</tr>
<tr>
<td>GET</td>
<td><code>/signalk/v1/unitpreferences/definitions</code></td>
<td>Get all unit definitions (merged standard + custom)</td>
</tr>
<tr>
<td>GET</td>
<td><code>/signalk/v1/unitpreferences/custom-definitions</code></td>
<td>Get custom unit definitions only</td>
</tr>
<tr>
<td>PUT</td>
<td><code>/signalk/v1/unitpreferences/custom-definitions</code></td>
<td>Update custom unit definitions</td>
</tr>
<tr>
<td>GET</td>
<td><code>/signalk/v1/unitpreferences/custom-categories</code></td>
<td>Get custom category mappings only</td>
</tr>
<tr>
<td>PUT</td>
<td><code>/signalk/v1/unitpreferences/custom-categories</code></td>
<td>Update custom category mappings</td>
</tr>
<tr>
<td>GET</td>
<td><code>/signalk/v1/unitpreferences/presets</code></td>
<td>List all available presets (built-in and custom)</td>
</tr>
<tr>
<td>GET</td>
<td><code>/signalk/v1/unitpreferences/presets/:name</code></td>
<td>Get a specific preset by name</td>
</tr>
<tr>
<td>PUT</td>
<td><code>/signalk/v1/unitpreferences/presets/custom/:name</code></td>
<td>Create or update a custom preset</td>
</tr>
<tr>
<td>DELETE</td>
<td><code>/signalk/v1/unitpreferences/presets/custom/:name</code></td>
<td>Delete a custom preset</td>
</tr>
<tr>
<td>GET</td>
<td><code>/signalk/v1/unitpreferences/active</code></td>
<td>Get the currently active preset</td>
</tr>
<tr>
<td>GET</td>
<td><code>/signalk/v1/unitpreferences/default-categories</code></td>
<td>Get the default category mappings</td>
</tr>
</tbody>
</table>
<hr>
</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="#for-end-users"><span>For <wbr/>End <wbr/>Users</span></a><ul><li><a href="#changing-unit-settings"><span>Changing <wbr/>Unit <wbr/>Settings</span></a></li><li><a href="#available-settings"><span>Available <wbr/>Settings</span></a></li><li><a href="#overriding-specific-paths"><span>Overriding <wbr/>Specific <wbr/>Paths</span></a></li></ul><a href="#unit-categories"><span>Unit <wbr/>Categories</span></a><ul><li><a href="#how-categories-work"><span>How <wbr/>Categories <wbr/>Work</span></a></li><li><a href="#standard-categories"><span>Standard <wbr/>Categories</span></a></li></ul><a href="#for-client-application-developers"><span>For <wbr/>Client <wbr/>Application <wbr/>Developers</span></a><ul><li><a href="#how-it-works"><span>How it <wbr/>Works</span></a></li><li><a href="#rest-api-usage"><span>REST <wbr/>API <wbr/>Usage</span></a></li><li><a href="#websocket-stream"><span>Web<wbr/>Socket <wbr/>Stream</span></a></li><li><a href="#consuming-data"><span>Consuming <wbr/>Data</span></a></li><li><a href="#api-endpoints"><span>API <wbr/>Endpoints</span></a></li></ul></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>