ITADN
NearlCrews/signalk-crows-nest
README.md

Crow's Nest

npm version npm downloads CI ESLint SignalK Plugin CI License node Buy Me a Coffee

A points-of-interest importer for Signal K: it pulls marinas, ports, anchorages, hazards, aids to navigation, live safety notices, tide and current stations, locks, and chart hazards from eight marine data sources and publishes them as Signal K notes resources, with proximity, route-corridor, and bridge air-draft alarms.

Built on the foundation of signalk-activecaptain-resources by Paul Willems and the Signal K community.

The alarms and the imported data are advisory. They are not certified for safety-of-life navigation: always cross-check against official charts and your primary instruments.

What's new in 0.15.4

  • Bounded upstream responses. Queued ActiveCaptain and Overpass responses now enforce the same 64 MiB limit as one-shot downloads, including streamed bodies without a trustworthy Content-Length.
  • Safer configured endpoints and note links. Overpass configuration accepts only absolute HTTP(S) URLs, and note resources omit unsafe link schemes.
  • Current shared panel UI. The panel now bundles signalk-nearlcrews-ui 0.6.2.
  • Enforced quality floors. Coverage thresholds and complete Knip reporting now fail the gate on regressions.

What it does

Signal K is an open marine data standard that streams a boat's navigation, environment, and AIS data over a single API. Crow's Nest is a Signal K server plugin that fills the chart around that data: it imports points of interest from eight sources, merges duplicates into one corroborated marker, and serves them as standard notes resources that chartplotters such as Freeboard-SK display natively.

It is built for life on a boat: details are cached on disk so the chart keeps working offline, refresh traffic is debounced and sized to each upstream's real update rate, and the same POI data drives three safety alarms (hazard proximity, hazards on the route ahead, and a bridge air-draft check).

Features

  • Eight data sources, merged into one chart layer. Garmin ActiveCaptain is the base; the other seven are opt-in: OpenSeaMap (OpenStreetMap marine data via the Overpass API), the USCG Light List of US Aids to Navigation (US-only), NOAA ENC Direct (US authoritative wrecks, obstructions, and underwater rocks), NOAA CO-OPS tide and current stations (US and territories), USCG Local Notice to Mariners live safety notices (US-only), the NGA World Port Index (worldwide), and USACE locks and dams (US inland waterways). Cross-source duplicates merge into the ActiveCaptain base, and the surviving note records every contributing source as a corroboration signal.
  • A broad point-of-interest overlay as Signal K notes resources: marinas, ports, anchorages, hazards, safety notices, businesses, boat ramps, bridges, dams, ferries, inlets, locks, local knowledge, navigational aids, airports, lighted and unlighted aids, daymarks, racons, tide and current stations, wrecks, obstructions, and underwater rocks.
  • Proximity hazard alarms with hysteresis: a Signal K notification fires when a Hazard point comes within a configurable radius and clears once the vessel moves beyond it.
  • Route-corridor hazard scan: warns about hazards, bridges, and locks on the active Course API route ahead, with along-track distance and ETA.
  • Bridge air-draft check: warns when a bridge's vertical clearance is at or below the vessel air draft (design.airHeight or a configured fallback) plus a safety margin, both as a proximity alarm as the vessel nears a too-low bridge and as a clearance-specific route warning ahead.
  • Rich point detail rendered as plain-English HTML, with the source-specific attribution credit (ODbL for OSM, CC0 for NOAA ENC, US Government public domain for the USCG, NOAA CO-OPS, NGA, and USACE feeds, Garmin ActiveCaptain for the base) published as a structured properties.attribution field on every note, so a client UI can render it in chrome rather than next to the POI text.
  • A normalized detail schema for structured clients: every note also carries a presentation-neutral properties.crowsNest view of the same detail alongside the HTML, documented in the notes-resource integration guide, so a richer chartplotter can render the sections natively and skip the HTML.
  • Persistent, offline caching. ActiveCaptain details and OpenSeaMap, NOAA ENC, and USACE features live in 30-day on-disk stores. OpenSeaMap, NOAA ENC, and USACE can rebuild previously visited markers from those stores after an offline restart; ActiveCaptain can still resolve a known marker's persisted detail, but a new ActiveCaptain list requires its upstream. The USCG Light List index is sharded on disk and queried through an in-memory spatial tile index, while Local Notice to Mariners, NOAA CO-OPS, and World Port Index keep their complete datasets on disk and survive restarts.
  • Refresh debounce per source: each at-runtime source snaps the viewport to a coarse tile and serves stale while revalidating, so a Freeboard refresh burst on a stationary viewport reuses the cached result rather than flooding the upstream.
  • Filters to cut clutter: a minimum-rating filter on ActiveCaptain, a per-source earliest-year filter (SORDAT survey vintage on NOAA ENC, MODIFIED_DATE on USCG, OSM element timestamp on OpenSeaMap), and a freshness warning in the popup for an ActiveCaptain Hazard whose report has not been confirmed in over two years.
  • A React configuration panel with a per-source status bar, an accordion of cards each with a live-status pill, an Alerts section, and shared signalk-nearlcrews-ui controls and themes. Fresh profiles use Auto to follow the host or operating-system color scheme, with Light, Dark, and red-preserving Night available from the theme toggle.

Screenshots

Points of interest from every source land on the chart as Signal K notes, each with a plain-English popup, and the whole plugin is configured from one panel.

ActiveCaptain hazardUSCG Light List aidConfiguration panel
An ActiveCaptain hazard note open in Freeboard-SK, showing the rating, the review text, and a staleness warningA USCG Light List buoy note open in Freeboard-SK, showing the light characteristic and the source citationThe light-themed Crow's Nest configuration panel, showing per-source live status and the data-source cards

Architecture

Crow's Nest is one plugin built from focused modules:

  • TypeScript 6 under strict flags. The Node plugin compiles with tsc; the React configuration panel bundles with webpack 5 as a Module Federation remote that the Signal K admin UI loads. The panel uses signalk-nearlcrews-ui for shared controls and token-driven themes.
  • Inputs and outputs. Every POI source is a self-contained input module (ActiveCaptain, OpenSeaMap, USCG Light List, NOAA ENC Direct, NOAA CO-OPS, USCG Local Notice to Mariners, NGA World Port Index, and USACE locks and dams) and every consumer is an output module (the notes provider, the proximity alarm, the route-corridor scan, and the bridge air-draft check), each registered on one line in the plugin entrypoint.
  • One aggregate source. A registry fans each chart request out to every enabled input, namespaces the ids, unions the results, records per-source health, and runs the dedupe pass that merges duplicates within a configurable radius (default 150 feet).
  • Polite HTTP. Queued, throttled clients with retry and Retry-After handling for the high-volume sources; conditional GET for the bulk-download feeds (USCG Light List, Local Notice to Mariners, and NOAA CO-OPS); Overpass fallback mirrors so a single instance outage does not take the source offline; and a US-waters gate that skips outbound HTTP on the US-only feeds when the vessel is elsewhere.
  • Tested on node:test via tsx, with ESLint 9 and neostandard.

See CLAUDE.md for the full module map.

Signal K paths

Crow's Nest is a well-behaved Signal K citizen: it reads a few vessels.self paths and the Course API, and it writes only notes resources and notifications under its own branch. All values are SI units (position in decimal degrees, distances and heights in meters).

Reads (from vessels.self):

  • navigation.position: the US-waters gate on the US-only feeds and the vessel position for proximity, route, and bridge air-draft scans. Chart resource requests supply their own bounding box or search center.
  • navigation.speedOverGround: ETA math in the route-corridor scan.
  • design.airHeight: the vessel air draft for the bridge-clearance check (a configured fallback is used only when this path is absent).
  • The Course API active route: the route-corridor hazard scan reads the active route to look ahead along the planned track.

Writes:

  • resources/notes: every imported POI is published as a Signal K note resource (with the source-agnostic structured detail on properties.crowsNest alongside the HTML description) so chartplotters such as Freeboard-SK can display it.
  • notifications.navigation.crowsNest.hazard.<id>: proximity hazard alarms.
  • notifications.navigation.crowsNest.route.<id>: route-corridor hazard alarms (including the too-low-bridge verdict).
  • notifications.navigation.crowsNest.bridgeClearance.<id>: bridge air-draft alarms.

The plugin also serves an admin-gated GET status endpoint.

Requirements

  • Signal K server 2.x. The notes layer does not require a GPS because the chartplotter supplies its viewport. A navigation.position source on vessels.self is required for the position-driven alarms and lets the plugin avoid US-only requests when the vessel is clearly outside US waters.
  • Node.js 20.3 or newer.
  • A chartplotter that consumes Signal K notes resources. Freeboard-SK is the reference consumer; any client that reads notes resources will see the markers, including Binnacle, which renders the structured detail natively.
  • The configuration panel needs Signal K admin UI 2.26.0 or newer. On older servers the plugin still works and falls back to the standard settings form.

Installation

Install from the Signal K admin UI under AppStore, then Available, or from npm:

cd ~/.signalk
npm install signalk-crows-nest

From source:

git clone https://github.com/NearlCrews/signalk-crows-nest.git
cd signalk-crows-nest
npm install
npm run build
ln -s "$(pwd)" ~/.signalk/node_modules/signalk-crows-nest

Configuration

In the Signal K admin UI, open Server, then Plugin Config, find "Crow's Nest", and enable the plugin. The defaults work for an ActiveCaptain-only setup; opt in to the other sources from their cards. The panel has these areas:

  1. Theme toggle in the top corner: Auto, Light, Dark, or a red-preserving Night mode for night vision at the helm. Auto is the default for a fresh profile, and an explicit choice persists across visits.

  2. Per-source status bar: reachable, unreachable, or not yet contacted for each enabled source, the last successful upstream list-fetch time, a "checked Ns ago" freshness note, and recent errors. A source-attributed error is clickable and opens the matching source card. Local cache and index reads do not count as proof that an upstream is reachable.

  3. Data sources accordion with one collapsible card per source (ActiveCaptain, OpenSeaMap, USCG Light List, NOAA ENC Direct, NOAA CO-OPS, USCG Local Notice to Mariners, NGA World Port Index, and USACE locks and dams). Each card's body groups its options into bordered fieldsets: import layers, refresh and freshness, filters (when present), and merge with ActiveCaptain. In brief, per card:

    • ActiveCaptain (always on): 13 POI-type toggles, a minimum-rating filter, the detail freshness window (default 24 hours), and the viewport refresh window (default 30 seconds). Selecting no POI types hides the chart notes layer; enabled safety alerts still request the hazard types they require.
    • OpenSeaMap (off by default): four seamark feature-group toggles, an earliest-year filter, the Overpass endpoint with optional fallback mirrors, and the viewport refresh window (default 10 minutes).
    • USCG Light List (off by default, US-only): the background refresh period in hours (default 24) and an earliest-year filter.
    • NOAA ENC Direct (off by default, US-only): wreck and obstruction layer toggles (on), an underwater-rocks toggle (off, heavy), the chart scale band, an earliest survey-year filter, and the viewport refresh window (default 30 minutes).
    • NOAA CO-OPS (off by default, US and territories): tide and current-meter station family toggles (both on) and the background refresh period in hours (default 24).
    • USCG Local Notice to Mariners (off by default, US-only): the background refresh period in seconds (default 900, 15 minutes).
    • NGA World Port Index (off by default, worldwide): the background refresh period in hours (default 24).
    • USACE locks and dams (off by default, US-only): a locks toggle (on), a dams toggle (off, heavy), and the viewport refresh window (default 30 minutes).

    Every card except ActiveCaptain also carries a merge-with-ActiveCaptain toggle (on by default) and its per-source merge radius. For every earliest-year filter, 0 means off; positive values below 1900 normalize to 1900.

  4. Alerts section (collapsed by default, opens automatically when an alarm is enabled): the proximity-alarm, route-corridor scan, and bridge air-draft check controls, each in its own fieldset with an opt-in toggle and its numeric settings.

Per-source enable toggles live on each card's header, alongside the disclosure chevron. Each card carries a small live-status pill on the header: ✓ ok after a successful upstream list fetch, … idle before the first request or during an intentional skip, … waiting when a slow request continues after the five-second aggregate deadline, and ! error after a failure. Idle pills include reasons such as outside US waters, and the ok tooltip carries the longer "N POIs in last fetch, M minutes ago" detail. Disabled cards show a "Disabled." prefix on their summary so an off source never reads as live. Every numeric input clears cleanly mid-edit. Saving applies immediately; the plugin rebuilds its runtime and in-memory viewport caches while retaining the on-disk data used for offline operation.

Documentation

Development

This project targets Node 20.3 or newer and develops against @signalk/server-api 2.30.0 or newer, with TypeScript 6 and the exact shared UI package signalk-nearlcrews-ui 0.6.2 (development only). The full local toolchain uses Node 22.22.2 or newer while the published plugin runtime keeps its Node 20.3 compatibility floor.

git clone https://github.com/NearlCrews/signalk-crows-nest.git
cd signalk-crows-nest
npm install          # install dependencies
npm run build        # compile the plugin and bundle the panel
npm test             # node:test suite via tsx
npm run typecheck    # type-check the plugin, the panel, and the tests
npm run lint         # code, Markdown, and spelling checks
npm run lint:fix     # lint and auto-fix
npm run verify       # full local verification without cross-browser tests
npm run verify:release # full verification and the cross-browser matrix
npm run clean        # remove dist/ and the panel build artifacts

Run npm run verify before committing and npm run verify:release before a release. See the development guide for the full workflow.

License

MIT: see the LICENSE file for the full text. The software is provided "AS IS", without warranty of any kind. Treat the imported data and the alarms as advisory, and always carry independent means of navigation. Bundled dependency licenses are listed in the THIRD_PARTY_NOTICES.md file.

Acknowledgments

Built on the foundation of signalk-activecaptain-resources by Paul Willems and the Signal K community. Full credit to the original author for the initial plugin that imports ActiveCaptain points of interest and exposes them as Signal K resources. Crow's Nest is written and maintained by Nearl Crews.

Crow's Nest pairs well with sibling plugins such as signalk-nmea2000-emitter-cannon and signalk-binnacle.

Support

Find this plugin useful? You can support its continued development by buying me a coffee.