npm.io
0.2.4 • Published 6h ago

signalk-autopilot-provider-garmin

Licence
Apache-2.0
Version
0.2.4
Deps
0
Size
59 kB
Vulns
0
Weekly
0
Stars
1

signalk-autopilot-provider-garmin

A Signal K v2 Autopilot Provider for Garmin Reactor autopilots over NMEA 2000.

It registers with the Signal K server's built-in Autopilot API (registerAutopilotProvider), so the server owns the REST API, auth, the steering.autopilot.* (v1 + v2) deltas, and the UI. This plugin translates those calls to/from Garmin's proprietary PGN 126720, and decodes the CCU's broadcast of the same PGN back into live state / engaged / target.

Status: working, verified live underway on a Reactor 40. Garmin's autopilot runs entirely over PGN 126720, which had not been publicly decoded — the command and status protocols here were reverse-engineered from live bus captures. See garmin-reactor-126720-findings.md for the full writeup.

Hardware (reference vessel: Buttercup)

  • Reactor 40 CCU — N2K source address 2
  • GHC control head (source 5) — sends the hold-mode commands
  • GPSMAP chartplotter (source 4) — sends the route/Go-To command + nav PGNs
  • Wind instrument, GPS, NMEA 2000 backbone @ 250 kbit/s

What works (all verified live)

Capability Notes
Engage / standby state = auto / standby
Heading hold hold current compass heading
Apparent wind hold hold current apparent wind angle
Target adjust ±1 / ±10° heading or wind angle, context-dependent
Live readback of head-unit changes mode + target track what you do on the GHC/plotter, not just commands from this plugin
Tack & gybe one V2 call each; auto-picks the correct turn direction from the apparent wind
Powerboat patterns zigzag, circles, U-turn, Williamson (+ time / amplitude params)
GPS patterns orbit, cloverleaf, search (require an active route on the plotter)
Route / Go-To follow nav-follow engage (see limitations re: nav-source arbitration)
Live status state, mode, engaged, target published to steering.autopilot.*
How the mode is known

The CCU never broadcasts its own discrete mode. Instead, every controller (GHC, chartplotter, or this plugin) sets the mode with a command on the bus, and the plugin watches those:

E5 98 10 17 04 04 05 0A 00 <code>   02=standby 05=heading 11=wind 0D=route  08/09/0A/0B/0E/0F/10=patterns

So mode (compass/wind/route) is correct regardless of which device engaged it. Engaged-vs-standby comes from the CCU's broadcast markers (00 A2 / 02 74 / 00 72 at ~2 Hz). The desired heading/wind target is reconstructed from the bus target-adjust steps (26 <code>) seeded from the sensor value at engage — because the CCU does not broadcast the target either.

API

Standard Signal K v2 autopilot endpoints (/signalk/v2/api/vessels/self/autopilots/garminReactor/…): state (auto/standby), mode (compass/wind/route), target/adjust, engage / disengage, tack/{port|starboard}, gybe/{port|starboard}, and courseCurrentPoint (engages nav-follow toward the active waypoint). dodge steers off the held course with quantized heading nudges (the Reactor has no native dodge PGN). courseNextPoint and setTarget are throwing stubs — the Reactor advances waypoints at the chartplotter and has no absolute-target PGN.

The provider also publishes an actions list (tack, gybe, courseCurrentPoint, dodge, …) with available flags that track the current state and mode, so clients like Freeboard can show only what's usable.

Garmin-specific operations the v2 standard doesn't cover are exposed as v1 PUT paths:

  • steering.autopilot.rudder.pattern — value "<name>:<dir>", e.g. circles:stbd, uturn:port, williamson:stbd, orbit:port, cloverleaf:stbd, search:port, zigzag, tack, gybe
  • steering.autopilot.route.goto — value "lat,lon" (drive a waypoint from the plugin side)
  • steering.autopilot.route.stop

Protocol summary (PGN 126720)

Container: E5 98 (Garmin / Marine) + 10 17 04 04 (Reactor AP group), then:

Operation Bytes
Set state / mode 05 0A 00 <code>02 standby, 05 heading, 11 wind, 0D route, 13 tack/gybe, patterns below
Target adjust 26 <code>00 −1°, 01 −10°, 02 +1°, 03 +10°
Pattern selector 04 <sel> 00 <dir> — circles 34, U-turn 6F, Williamson 47, orbit 5B, cloverleaf 3E, search 65, tack/gybe A2; dir 00=stbd turn, 01=port turn
Controller keepalive 15 03 0X 00 C8 00 (~2 Hz; required to be accepted as a controller)

Commands must be sent through the Signal K server's NMEA 2000 output (canboatjs); the CCU ignores raw cansend injection. Full field-level decode is in the findings doc.

Architecture

  • index.js — registers the v2 provider and maps API methods to the device module.
  • garmin_pilot.js — Garmin device logic: command encodings, CCU auto-discovery (matches Reactor in Product Info), a direct can0 reader (via candump) that reassembles the CCU's fast-packet 126720 broadcasts, the bus mode-set / target-adjust command watch, and the v1 PUT handlers for patterns + route.

Requirements

  • Linux host with SocketCAN (e.g. a Raspberry Pi with a CAN HAT) — the status RX path shells out to candump, which must be on PATH, on the interface the CCU is on (default can0).
  • A Signal K server with NMEA 2000 output (canboatjs) — commands are sent via nmea2000out; the CCU ignores raw cansend.
  • Signal K server ≥ 2.x with the Autopilot API (developed/tested on server 2.28, @signalk/server-api with the courseCurrentPoint / actions additions). Node ≥ 18.

Install

cd ~/.signalk/node_modules        # or your server's plugin dir
npm install signalk-autopilot-provider-garmin
# or symlink a checkout for development

Enable in the Signal K plugin config; the CCU address is auto-discovered (override available). A Node-RED Dashboard 2.0 control page is included under nodered/ (modes, target adjust, tack/gybe, patterns, live status).

registerController keepalive: the plugin broadcasts a GHC-style controller keepalive so the CCU accepts heading-adjust commands. If a physical GHC head is already on the bus, consider disabling this option (plugin config) to avoid controller-arbitration conflicts.

Known limitations

  • Target / mode are inferred, not read. The CCU doesn't broadcast them. state is exact (from the command stream); target is reconstructed from adjust steps and can drift a degree over a long session — re-engaging the mode resyncs it.
  • Plugin-side route follow (route.goto) is blocked while the chartplotter is the CCU's bonded nav source; route-follow engaged from the plotter works and is reported correctly.
  • Powerboat patterns require the appropriate vessel hull profile; GPS patterns require an active route on the plotter.

Credits / license

  • Provider structure: Signal K autopilot provider template (panaaj / SignalK).
  • Original command bytes: jorgen-k/signalk-autopilot-garmin (Apache-2.0).
  • Full PGN 126720 command + status reverse engineering and live verification: Buttercup project.
  • Tooling: canboat, signalk-autopilot.

Licensed under Apache-2.0.

Keywords