signalk-server
Version:
An implementation of a [Signal K](http://signalk.org) server for boats.
101 lines (100 loc) • 20.8 kB
HTML
<html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>Source Priority | 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="../Configuration.html">Configuration</a></li><li><a href="" aria-current="page">Source Priority</a></li></ul></div><div class="tsd-panel tsd-typography"><h1 id="source-priority" class="tsd-anchor-link">Source Priority<a href="#source-priority" 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>When multiple data sources publish the same Signal K paths (e.g. two GPS devices both providing <code>navigation.position</code>), Signal K Server needs to decide which source to use. The Source Priority system organises sources into <strong>Priority Groups</strong> and lets you set a ranking per group, with optional per-path overrides.</p>
<p>These features are available in the Admin UI under <em>Data -> Source Priority</em>.</p>
<h2 id="priority-groups" class="tsd-anchor-link">Priority Groups<a href="#priority-groups" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2>
<p>A <strong>Priority Group</strong> is a set of sources that share at least one published path. Groups are derived automatically: whenever two sources publish the same path, they land in the same group. Chains extend transitively — if A and B share a path and B and C share another, A, B and C are all in the same group.</p>
<p>Typical groups you will see on a real boat:</p>
<ul>
<li>A <strong>GPS group</strong>: all devices publishing <code>navigation.position</code>, <code>navigation.courseOverGroundTrue</code>, <code>navigation.speedOverGround</code>, etc.</li>
<li>A <strong>wind group</strong>: masthead transducer, AIS wind reports, derived-data plugin output, etc.</li>
<li>A <strong>depth group</strong>, <strong>heading group</strong>, and so on.</li>
</ul>
<p>For each group you set a <strong>source ranking</strong> by dragging the sources into order. The top source is preferred across every shared path in the group, the second source is the first backup, and so on. In most installations, ranking groups is all you need — per-path tweaks are the exception, not the rule.</p>
<h3 id="sidebar-badge" class="tsd-anchor-link">Sidebar Badge<a href="#sidebar-badge" 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 sidebar shows a yellow warning badge on the <em>Data</em> menu item while any group lacks a saved ranking. The number reflects how many groups are still unranked; it drops to zero once every group has an order saved.</p>
<h2 id="how-rankings-work" class="tsd-anchor-link">How Rankings Work<a href="#how-rankings-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></h2>
<p>Within a group, the top-ranked source is <strong>preferred</strong> — while it is publishing data, its values always win on every shared path. Every other rank has a <strong>Fallback after</strong> value: the number of milliseconds the <strong>currently-winning</strong> source must be silent before that rank is allowed to take over.</p>
<p><img src="../media/source-priority-timeline.svg" alt="Fallback timeline with three sources showing the cascade behaviour"></p>
<p>The important subtlety: each rank's timer is measured against whichever source is <strong>currently winning</strong>, not against rank 1.</p>
<ul>
<li>When the preferred source goes silent, rank 2's Fallback clock starts.</li>
<li>If and when rank 2 takes over, it becomes the winner. From that moment, rank 3's Fallback clock starts ticking against rank 2, not against rank 1.</li>
<li>So if rank 2 keeps actively sending after taking over, rank 3 never wins — the chain cascades one step at a time.</li>
</ul>
<p>The preferred source has no Fallback value because nothing ranks higher. When it returns after any silence, it immediately resumes winning — the backups do not "hold" their position.</p>
<h3 id="a-worked-example" class="tsd-anchor-link">A Worked Example<a href="#a-worked-example" 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>Three GPS devices on the boat all publish <code>navigation.position</code> and related paths. Signal K places them in one group. In the Admin UI the sources appear with human-readable labels; the underlying <code>$source</code> values are CAN Names:</p>
<table>
<thead>
<tr>
<th>Rank</th>
<th>Shown as</th>
<th><code>$source</code> (CAN Name)</th>
<th>Fallback after</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Furuno (<code>can0.c0788c00e7e04312</code>)</td>
<td><code>can0.c0788c00e7e04312</code></td>
<td><em>preferred</em></td>
</tr>
<tr>
<td>2</td>
<td>Garmin (<code>can0.c0328400e7e00a86</code>)</td>
<td><code>can0.c0328400e7e00a86</code></td>
<td><code>15000</code> (15 s)</td>
</tr>
<tr>
<td>3</td>
<td><a href="http://serial0.GP">serial0.GP</a></td>
<td><code>serial0.GP</code></td>
<td><code>30000</code> (30 s)</td>
</tr>
</tbody>
</table>
<p>Scenarios:</p>
<ul>
<li><strong>Furuno is healthy:</strong> only Furuno values reach subscribers on every shared GPS path. Garmin and <a href="http://serial0.GP">serial0.GP</a> are ignored even though they publish continuously.</li>
<li><strong>Furuno unplugged, Garmin healthy:</strong> after 15 s of Furuno silence, Garmin takes over and keeps winning as long as it keeps publishing. <a href="http://serial0.GP">serial0.GP</a> is still ignored — its 30 s clock is measured against Garmin, but Garmin is never silent.</li>
<li><strong>Furuno unplugged AND Garmin unplugged:</strong> after 15 s of Furuno silence, Garmin takes over. 30 s later (measured from Garmin's last value), <a href="http://serial0.GP">serial0.GP</a> takes over.</li>
<li><strong>Furuno returns:</strong> it immediately wins again, regardless of which backup was winning.</li>
</ul>
<h2 id="path-level-overrides" class="tsd-anchor-link">Path-Level Overrides<a href="#path-level-overrides" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2>
<p>A path-level override tells Signal K to use a <strong>different</strong> ranking for one specific path than the group's ranking would imply. Overrides sit inside the group card — they are the exception, not the rule.</p>
<p>A common example: two GPS units land in one group, Furuno is ranked first overall, but the Garmin has a better magnetic-variation (WMM) model. An override on <code>navigation.magneticVariation</code> prefers Garmin on that one path while every other shared path still prefers Furuno.</p>
<h3 id="disabling-a-source-on-a-path" class="tsd-anchor-link">Disabling a Source on a Path<a href="#disabling-a-source-on-a-path" 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>Inside an override, unchecking <strong>Enabled</strong> on a row blocks that source on this path entirely, no matter how silent the others become. The disabled row stays visible in the list so it can be re-enabled later without re-ordering.</p>
<h3 id="ungrouped-overrides" class="tsd-anchor-link">Ungrouped Overrides<a href="#ungrouped-overrides" 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>If a path only has a single publisher today, no group is created for it. You can still add an ungrouped override for that path — useful for pre-configuring ranking before a second source arrives, or for disabling a plugin-only path.</p>
<h2 id="sources-not-listed" class="tsd-anchor-link">Sources Not Listed<a href="#sources-not-listed" 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>Data from a source that is not listed in the priority table for a path is held back until every listed source has been silent for a safety window. This is so an unconfigured new device on the bus doesn't suddenly hijack a path you have not thought about. The window's default is set conservatively; you can tune it via the Admin UI's <em>Default Fallback after</em> control.</p>
<h2 id="what-is-not-filtered" class="tsd-anchor-link">What is Not Filtered<a href="#what-is-not-filtered" 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><code>notifications.*</code> paths bypass source priority entirely — every source's notifications are delivered unchanged. Notifications are events, not measurements, so suppressing one source's alarm because another source is "preferred" is never the right behaviour.</p>
<p>All source data is preserved in the server's data model regardless of priority configuration. Priority only affects which source's values are delivered to subscribers by default. See <a href="#source-priority-in-the-data-browser">Source Priority in the Data Browser</a> for how to view every source's data.</p>
<h2 id="source-priority-in-the-data-browser" class="tsd-anchor-link">Source Priority in the Data Browser<a href="#source-priority-in-the-data-browser" 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 Data Browser (<em>Data -> Browser</em>) has a <strong>Sources</strong> dropdown that controls which source's data is displayed:</p>
<ul>
<li><strong>Priority filtered</strong> (default): shows only the preferred source's data for each path, respecting your priority configuration.</li>
<li><strong>All sources</strong>: shows data from every source. The preferred source for each path is marked with a green checkmark (<strong>✓</strong>) so you can see which one would win under filtering.</li>
</ul>
<p>Use <strong>All sources</strong> to:</p>
<ul>
<li>Verify that priority configuration is working correctly</li>
<li>Compare values from different sources</li>
<li>Debug sensor issues by seeing all incoming data</li>
</ul>
<p>The <strong>View</strong> dropdown lets you switch between a flat path listing (<strong>Paths</strong>) and a source-grouped view (<strong>By Source</strong>) that shows the same full table grouped under source headers.</p>
<h2 id="source-identification" class="tsd-anchor-link">Source Identification<a href="#source-identification" 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 identifies sources differently depending on the connection type:</p>
<h3 id="nmea-2000-sources" class="tsd-anchor-link">NMEA 2000 Sources<a href="#nmea-2000-sources" 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>N2K sources are identified by their <strong>CAN Name</strong> — a globally unique 64-bit identifier derived from the ISO Address Claim (PGN 60928). Each device on the bus has a unique NAME even if the manufacturer and model are identical (the NAME includes a per-device unique number). This is more reliable than the source address (which can change when devices are added or removed from the bus).</p>
<p>The <code>$source</code> field contains the hex-encoded CAN Name (for example <code>can0.c0788c00e7e04312</code>) once the device's Address Claim has been received. Until that point the server may use the source address as a placeholder.</p>
<p>The Admin UI shows a human-readable label derived from the manufacturer and model (PGN 60928 + 126996), e.g. <em>Furuno (can0.c0788c00e7e04312)</em>. You can set a custom alias via the pencil icon next to any source label. Two identical devices (same manufacturer and model) have different CAN Names, so aliases help distinguish them — e.g. "Bow GPS" and "Stern GPS".</p>
<p>See <a href="NMEA_2000_Device_Management.html">NMEA 2000 Device Management</a> for details.</p>
<h3 id="nmea-0183-sources" class="tsd-anchor-link">NMEA 0183 Sources<a href="#nmea-0183-sources" 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>NMEA 0183 sources are identified by the connection name and talker ID, e.g. <code>serial0.GP</code>.</p>
<h3 id="plugin-sources" class="tsd-anchor-link">Plugin Sources<a href="#plugin-sources" 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>Plugin sources use the plugin ID as their <code>$source</code>, e.g. <code>derived-data</code> or <code>signalk-venus-plugin</code>.</p>
</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="#priority-groups"><span>Priority <wbr/>Groups</span></a><ul><li><a href="#sidebar-badge"><span>Sidebar <wbr/>Badge</span></a></li></ul><a href="#how-rankings-work"><span>How <wbr/>Rankings <wbr/>Work</span></a><ul><li><a href="#a-worked-example"><span>A <wbr/>Worked <wbr/>Example</span></a></li></ul><a href="#path-level-overrides"><span>Path-<wbr/>Level <wbr/>Overrides</span></a><ul><li><a href="#disabling-a-source-on-a-path"><span>Disabling a <wbr/>Source on a <wbr/>Path</span></a></li><li><a href="#ungrouped-overrides"><span>Ungrouped <wbr/>Overrides</span></a></li></ul><a href="#sources-not-listed"><span>Sources <wbr/>Not <wbr/>Listed</span></a><a href="#what-is-not-filtered"><span>What is <wbr/>Not <wbr/>Filtered</span></a><a href="#source-priority-in-the-data-browser"><span>Source <wbr/>Priority in the <wbr/>Data <wbr/>Browser</span></a><a href="#source-identification"><span>Source <wbr/>Identification</span></a><ul><li><a href="#nmea-2000-sources"><span>NMEA 2000 <wbr/>Sources</span></a></li><li><a href="#nmea-0183-sources"><span>NMEA 0183 <wbr/>Sources</span></a></li><li><a href="#plugin-sources"><span>Plugin <wbr/>Sources</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>