chmod +x your boat · marine edition

$ Keel as .sh

Not a distro, not an OS — one executable script that turns the Linux you already run into a marine instrument bridge. It asks what's on board, then installs only the capabilities that setup needs: CAN bus, NMEA 2000, J1939 engine profiles, J1587/J1708, standard NMEA 0183 over RS-422, MTU RS-422, documented proprietary PGNs, a passive smart CAN sniffer, and gauges at the helm.

One command. A few questions. Underway.

The script interrogates your boat, not your patience. Answer what's on board and it resolves, installs, and configures only what those answers require.

pi@helm: ~
$ curl -fsSL "https://keelas.sh/?dl=Keelas.sh&raw=1" -o Keelas.sh && chmod +x Keelas.sh && sudo ./Keelas.sh

Keelas.sh v0.BETA-pi45.13-rs422-smart-sniffer-kiosk-autoboot — marine bridge deployment
Detected: Raspberry Pi 5 · aarch64 · apt · systemd

[1/11] Which hardware is physically installed?
      1) Waveshare RS485 CAN HAT (12 MHz)     5) Waveshare 2-CH CAN HAT (non-Plus)
      2) Waveshare RS485 CAN HAT (8 MHz)      6) PiCAN-M (MCP2515 + NMEA 0183)
      3) Waveshare 2-CH CAN FD HAT Rev2.1+    7) USB SocketCAN (gs_usb)
      4) Waveshare 2-CH CAN HAT+  ← Pi 5      8) None — serial / virtual CAN only
> 4   → hardware profile exposes 2 CAN channel(s)

[2/11] Enable a physical NMEA 2000 network?  [Y/n]  > Y
[3/11] Enable a physical J1939 network?  [y/N]  > y  · bitrate > 250 kbit/s
[4/11] Enable NMEA 2000 <-> J1939 conversion?  [Y/n]  > Y
[5/11] Select J1939 engine family/families.
      1 Generic · 2 Cummins NIM · 3 Cummins Tier 4 · 4 John Deere · 5 CAT C32/ADEM
      6 Scania · 7 Yamaha · 8 Suzuki · 9 FPT · 10 MAN
> 5,6  · source:instance map > 0x80:0,0x81:1 · raw proprietary capture [Y/n] > Y
[6/11] Documented proprietary NMEA 2000 compatibility output?  [y/N]  > y
[7/11] Legacy SAE J1708/J1587 -> NMEA 2000 conversion?  [y/N]  > y  · port > auto
[8/11] RS422 input mode for conversion to NMEA 2000?
      1) Standard NMEA 0183 over RS422   2) MTU ECS-5 RS422   3) BOTH   4) None
> 3
      NMEA 0183 > Waveshare Port A · 4800 8N1 · RMC/GGA/GLL/VTG/heading/depth/wind/temp → N2K
      MTU ECS-5  > Waveshare Port B · 19200 8N1 · monitoring1 · point/alarm map loaded; framing pending
[9/11] Enable passive CAN sniffer / protocol discovery?  [y/N]  > y
      1) Auto classify   2) NMEA 2000   3) J1939   4) NMEA 2000 + J1939
      5) Mercury SmartCraft / proprietary CAN   6) Raw CAN
> 1  · interfaces > auto
      receive-only · unknown traffic remains RAW · rotating NDJSON capture enabled
[10/11] Install/run Signal K?  [Y/n]  > Y
[11/11] Boot into kiosk gauge dashboard?  [Y/n]  > Y

Resolving dependencies for YOUR answers only:
  + capability: NMEA2000=y J1939=y convert=y engines=cat_c32,scania propN2K=y CAN-sniffer=y
  + CAN roles:  can0:n2k:250k · can1:j1939:250k
  + translator: can0 <-> can1 · engine map 0x80:0,0x81:1 · bounded raw PGN capture enabled
  + prop N2K:   Maretron 65284/65286/65287/130823/130840 under verified-data rules
  + J1587->N2K: engine/transmission/fuel/electrical/navigation data + standard alarm bits
  + RS422 mode: BOTH · FT4232HL Port A=NMEA 0183 · Port B=MTU ECS-5
  + 0183->N2K: 4800 8N1 · position/COG-SOG/heading/depth/wind/sea temperature -> can0
  + MTU RS422:  FT4232HL Port B @ 19200 8N1 -> can0 (ECS-5 point/alarm map loaded; framing pending)
  + CAN sniff:   can0,can1 · auto classify · receive-only · rotating NDJSON capture
  + runtime:    Node 22.23.2 + Signal K/canboatjs (full installed N2K PGN decode database)


Done. Reboot if required. Re-run anytime — it's idempotent.

Installs what you need. Nothing you don't.

No golden image to flash, no fork of your OS to trust. Your system stays yours — the script just rigs it.

Hardware-first Q&A wizard

Eleven questions: hardware first, capabilities second. Pick physical NMEA 2000/J1939 buses, conversion, engine profiles, proprietary output, J1708/J1587, then choose RS-422 mode: standard NMEA 0183, MTU ECS-5, BOTH, or none — followed by the passive CAN sniffer, Signal K and kiosk. Channel-aware so one-CAN hardware is never misrepresented as two physical networks.

NMEA 0183 over RS-422 → NMEA 2000

A new stdlib-only bridge reads ordinary NMEA 0183 from an RS-422 adapter and publishes direct NMEA 2000 equivalents for position, COG/SOG, vessel heading, water speed, depth, wind and sea temperature. It validates checksums when present and never transmits back onto the 0183 pair.

MTU ECS-5 over RS-422

The Series 2000 Monitoring I/II point, scaling, gear, and alarm maps are built in — raw values decode straight to NMEA 2000 fields. Native support for the Waveshare USB TO 4CH RS485/422 gateway (FT4232HL, Ports A/B). Capture-safe until the E 531 652 framing spec arrives: it records, never guesses frame boundaries.

NMEA 2000 ⇄ J1939, both ways

An embedded stdlib-Python translator bridges verified engine, transmission, fuel, trip, battery and static-identification data in both directions — fast-packet and J1939 TP included. Selectable engine profiles add manufacturer-specific inventory and bounded raw discovery. Unverified proprietary layouts are captured, never fabricated.

J1587/J1708 diesels, bundled

The legacy-bridge daemon is built into the script now: read-only on the 9600 bit/s bus, converting MID/PID data and standard diagnostic alarms into NMEA 2000 status bits. Self-tests run at install; the port is wizard-chosen or auto-detected.

Engine profiles + proprietary PGNs

Built-in profiles cover Generic J1939, Cummins NIM/Tier 4, John Deere, Caterpillar C32/ADEM, Scania, Yamaha, Suzuki, FPT and MAN. Optional raw capture records unknown/profile-specific traffic, while the proprietary NMEA 2000 publisher emits only documented Maretron-compatible messages from verified values.

Smart passive CAN sniffer

Optional receive-only SocketCAN discovery asks what you're sniffing: Auto, NMEA 2000, SAE J1939, both, Mercury SmartCraft/proprietary CAN, or raw CAN. It classifies known PGNs conservatively, extracts source/destination and manufacturer/profile hints, keeps unknown payloads raw, writes rotating NDJSON captures, and never transmits onto the monitored bus.

Verified Signal K runtime

Node 22.23.2 fetched from nodejs.org, SHA-256 checked against the official sums, isolated under /opt/keelos — only if your system Node is too old. Preflight proves socketcan + canboatjs load before anything is enabled.

Idempotent & reversible

Re-run to add hardware later — it converges instead of clobbering, down to Signal K provider config. Keelas.sh --uninstall removes everything it added and nothing it didn't.

Runs on what you've got

Raspberry Pi OS, Armbian, Ubuntu Server, whatever's already on the card. Detects apt, dnf, or pacman; keelos-can.service raises every interface with per-role bitrates in strict order before the translators and dashboard.

Supported PGNs & conversions

What Keelas.sh supports out of the box. Green-direction rows are real semantic conversions in the current bridge. Capture-only rows are intentionally not decoded until the exact manufacturer byte layout is verified.

10 selectable J1939 engine profilesGeneric SAE J1939, Cummins NIM, Cummins Tier 4, John Deere, CAT C32/ADEM, Scania, Yamaha, Suzuki, FPT, MAN.
Full installed NMEA 2000 decode pathSignal K / canboatjs uses its installed PGN database for normal N2K decoding. Cross-protocol transmission is deliberately limited to the verified mappings below.
NMEA 0183 → NMEA 2000Direct RS-422 translation for common navigation, heading, depth, wind, water-speed and sea-temperature sentences.
Manufacturer-aware discoveryOptional j1939_raw_capture: y writes bounded NDJSON records with PGN, source, engine instance, matching profile, and raw payload.
Smart passive CAN snifferAuto / NMEA 2000 / J1939 / both / SmartCraft / raw modes. Receive-only, rotating NDJSON capture, source + PGN inventory, profile/manufacturer hints.
Conservative proprietary outputMaretron manufacturer code 137 / marine industry group 4. Configuration/control PGNs are never synthesized from guesses.

J1939 ⇄ NMEA 2000 semantic bridge

current cross-protocol set

DM1 policy: an active J1939 DM1 asserts generic NMEA 2000 Check Engine in PGN 127489. Keelas.sh does not invent SPN-specific NMEA alarm bits when there is no defensible standard equivalent.

J1939 PGNData convertedNMEA 2000 PGNDirection
61444 · EEC1Engine speed127488 · Engine Parameters, Rapid UpdateBIDIRECTIONAL
61444 · EEC1Actual engine torque127489 · Engine Parameters, DynamicBIDIRECTIONAL
61443 · EEC2Percent engine load127489 · Engine Parameters, DynamicBIDIRECTIONAL
65270 · IC1Turbo / boost pressure127488 · Engine Parameters, Rapid UpdateBIDIRECTIONAL
65262 · ET1Coolant temperature · oil temperature127489 · Engine Parameters, DynamicBIDIRECTIONAL
65263 · EFL/P1Fuel pressure · oil pressure · coolant pressure127489 · Engine Parameters, DynamicBIDIRECTIONAL
65266 · LFE1Instantaneous fuel rate127489 · Engine Parameters, DynamicBIDIRECTIONAL
65271 · VEP1Battery / alternator voltage127489 · Engine Dynamic + 127508 · Battery StatusBIDIRECTIONAL
65253 · HOURSTotal engine hours127489 · Engine Parameters, DynamicBIDIRECTIONAL
65257Trip fuel used127497 · Trip Parameters, EngineBIDIRECTIONAL
65242Software identification127498 · Engine Parameters, StaticJ1939 → N2K
65260VIN / vehicle identification127498 · Engine Parameters, StaticJ1939 → N2K
61445 · ETC2Current transmission gear127493 · Transmission Parameters, DynamicBIDIRECTIONAL
65272 · TRF1Transmission oil pressure · oil temperature127493 · Transmission Parameters, DynamicBIDIRECTIONAL
65276 · DD1Fuel tank level127505 · Fluid LevelBIDIRECTIONAL
65226 · DM1Active diagnostic presence127489 · generic Check Engine statusJ1939 → N2K
65280 · Cummins NIMGenset load percentage127489 · Engine Parameters, DynamicJ1939 → N2K

Selectable J1939 engine profiles

profile-aware inventory

Profiles do not magically decode undocumented manufacturer data. They tell the bridge which PGNs belong to the selected engine family and which traffic should be retained for safe discovery. Multiple profiles can be enabled together.

1 · Generic SAE J1939 2 · Cummins Onan NIM 3 · Cummins Tier 4 4 · John Deere PowerTech 5 · Caterpillar C32 / ADEM 6 · Scania 7 · Yamaha Marine 8 · Suzuki Marine 9 · FPT Industrial 10 · MAN standard J1939

Cummins NIM-only installs default to the documented fixed source-to-instance map 234→0 · 158→1 · 179→2 · 203→3 unless you override it. Other profiles accept explicit mappings such as 0x80:0,0x81:1.

Recognized / capture-only J1939 inventory

never guessed
PGNKnown familyCurrent handling
65030Cummins NIM generator AC quantitiesPROFILE CAPTURE
65031Engine exhaust temperatureRAW UNTIL LAYOUT VERIFIED
65172Auxiliary coolantPROFILE CAPTURE
65214Rated speed / engine configuration familyPROFILE CAPTURE
65227DM2 historical diagnosticsRECOGNIZED · NOT ACTIVE ALARM
65248 · 65252 · 65256 · 65265 · 65279Distance · shutdown/indicators · navigation speed · vehicle speed · water-in-fuel familiesPROFILE CAPTURE
64775 · 64891 · 64892 · 65110 · 65269Cummins Tier 4 / FPT aftertreatment, DEF/SCR and OEM familiesPROFILE CAPTURE
65247 · 65376 · 65409 · 65414 · 65415 · 65416 · 65435 · 65464Scania profile-specific / proprietary inventoryPROFILE CAPTURE
any other unknown PGNUnclassified traffic on the selected J1939 busBOUNDED RAW CAPTURE WHEN ENABLED

J1708 / J1587 → NMEA 2000

read-only legacy bridge
NMEA 2000 outputLegacy inputs handledExamples
127488Engine rapid dataPID 190 RPM · PID 102 / 439 boost
127489Engine dynamic + statusOil/coolant/fuel pressure · temperatures · voltage · fuel rate · hours · load · alarms
127493Transmission dynamic + statusSelected/attained gear · oil pressure/temp · diagnostic status
127497Trip engineTrip fuel · average fuel rate
127498Engine staticRated speed · VIN · software ID
127505 · 127508Fuel tanks · batteryPrimary/secondary fuel · battery voltages/current
127250 · 128259 · 128275 · 129025Heading · speed · distance · positionCompass bearing · road speed · trip/total distance · latitude/longitude
130312 · 130314Temperature · actual pressureInside/outside/exhaust temperature · barometric pressure

J1587 alarm mappings:

Smart passive CAN sniffer

receive-only discovery

Safety policy: the sniffer opens CAN_RAW sockets for reception and does not transmit discovery frames. Auto classification is conservative. Ambiguous manufacturer traffic stays UNKNOWN/RAW; SmartCraft mode labels candidates without pretending the payload is decoded.

Sniffer modeWhat Keelas.sh doesUseful output
Auto classifyUses configured bus roles and known 29-bit PGN families to distinguish NMEA 2000, J1939 and proprietary candidates.PGN, priority, source, destination, known name, raw payload
NMEA 2000Uses NMEA 2000 context and recognizes the built-in N2K PGN inventory, including documented Maretron messages.N2K PGN + manufacturer hints
SAE J1939Uses J1939 context and recognizes standard plus selected Cummins, Scania, FPT and engine-profile PGN families.J1939 PGN + SA/DA + profile hints
NMEA 2000 + J1939Sniffs both configured SocketCAN interfaces at the same time on dual-bus installations.One timestamped capture across both buses
Mercury SmartCraftExperimental passive labeling for SmartCraft/proprietary CAN. Payload semantics remain raw until verified.CAN ID + raw bytes + timing for reverse mapping
Raw CANNo protocol assumption; preserves standard/extended IDs and payloads exactly as received.CAN ID, DLC, payload, FD/classic flag, interface, timestamp

Default capture: /var/log/keelos-can-sniffer.ndjson · rotates at 25 MB · journal summary every 30 seconds · configurable with sniffer_max_mb and sniffer_summary.

NMEA 0183 / RS-422 → NMEA 2000

direct read-only bridge

The serial bridge accepts standard NMEA 0183 talker IDs, validates a checksum when one is present, and publishes only fields with a direct NMEA 2000 equivalent. Default is 4800 baud 8N1; 38400 and supported custom rates can be selected.

NMEA 0183 sentenceData convertedNMEA 2000 output
RMCLatitude/longitude · COG · SOG129025 · 129026
GGA · GLLLatitude/longitude129025 · Position, Rapid Update
VTGCourse over ground · speed over ground129026 · COG & SOG, Rapid Update
HDT · HDM · HDGTrue/magnetic heading · deviation/variation when supplied127250 · Vessel Heading
VHWVessel heading · speed through water127250 · 128259
DPT · DBTDepth below transducer · DPT offset when present128267 · Water Depth
MWVApparent or true boat-referenced wind angle/speed130306 · Wind Data
MTWSea water temperature130312 · Temperature

RS-422 mode selector: choose nmea0183, mtu, both, or none. With a Waveshare USB TO 4CH RS485/422 and BOTH selected, automatic channel selection uses Port A for NMEA 0183 and Port B for MTU so the two talkers never contend for one serial channel.

Documented proprietary NMEA 2000 output

Maretron-compatible
NMEA 2000 PGNMessageKeelas.sh behavior
65284DC Relay CurrentConfigured only from an explicit verified relay/bank current — ordinary battery current is not substituted.
65286Fluid Flow RateAutomatically derived from standard N2K 127489 fuel-rate data when proprietary output is enabled.
65287Trip VolumeAutomatically derived from standard N2K 127497 trip-fuel data.
130823Temperature, High RangeAutomatically published from matching exhaust-temperature data in standard 130312 / 130316.
130840Generic SensorExact verified raw/data-format configuration only. No arbitrary sensor payload is invented.

Catalog-known proprietary families 126720, 128720, 130817–130822, 130824–130826, 130828–130830, 130832–130837 are known to the publisher, but command/configuration messages are not synthesized. Verified passive/status raw payloads are accepted only through the explicit allow-list.

MTU Series 2000 ECS-5 over RS-422

Monitoring I / II maps
NMEA 2000 PGNMapped MTU dataStatus
127488Engine speed · charge/boost air pressureMTU → N2K
127489Lube-oil pressure/temp · coolant temp/pressure · fuel pressure · engine hours · engine alarmsMTU → N2K
127493Ahead/neutral/astern · gear lube-oil pressure · gear temperature · transmission alarmsMTU → N2K
130316Exhaust temperature bank A/B · extended rangeMTU → N2K

Transport status: the ECS-5 point, scaling, gear and alarm maps are present, but live semantic framing remains capture-safe until the MTU E 531 652 RS-422 framing/checksum/encoding specification is supplied. The recommended adapter path is the Waveshare USB TO 4CH RS485/422 using RS-422-capable Ports A/B.

Get the BetaBeta

The Pi 4/5-hardened build is live for testing. Under active development — dry-run it first, keep backups, and don't make it the only instrumentation between you and the water.

⇩ Download Keelas.sh Donate

v0.BETA-pi45.13-rs422-smart-sniffer-kiosk-autoboot · 256.2 KB · updated 2026-08-14 UTC
SHA-256 33b8fafa429dd86235a970641888e83895de84de07db7fc5ec0d2eb436314275

curl curl -fsSL "https://keelas.sh/?dl=Keelas.sh&raw=1" -o Keelas.sh && chmod +x Keelas.sh && sudo ./Keelas.sh --dry-run
verify echo "33b8fafa429dd86235a970641888e83895de84de07db7fc5ec0d2eb436314275 Keelas.sh" | sha256sum -c

Beta means Beta: the script asks before touching anything, records every change to a manifest, and --uninstall reverses it. Start with --dry-run, verify the checksum, read the script — it's one file on purpose.

Ship's logChangelog

What changed, when, and what it means at the helm. Every release below stays downloadable and checksummed.

v0.BETA-pi45.13-rs422-smart-sniffer-kiosk-autoboot 2026-08-14 current
v0.BETA-pi45.7-mtu-rs422-ecs5-map 2026-08-10 download

SHA-256 936aa9078c63528f49b55b2cf0b095dbede77d7e882803eff4d7d925a6906b41

v0.BETA-pi45.5-j1587-n2k 2026-08-10 download

SHA-256 a338c304e254972e69121295dd93eab96b7dbb08b69e785af1eacda1be858c08

v0.MAYBE-pi45.1 archived
v0.MAYBE the before-times

Hardware support

Everything below is what the current Keelas.sh build actually configures — same options and caveats as its built-in --hat-guide. Hardened for Raspberry Pi 4/5; anything else runs with a warning.

CAN / serial interfaceWhat the script configuresStatus
•Waveshare RS485 CAN HAT (12 MHz)MCP2515 · SPI0 · GPIO25 · can0 + UARTAuto-config
•Waveshare RS485 CAN HAT (legacy 8 MHz)MCP2515 · 8 MHz osc · can0 + UARTAuto-config
•Waveshare 2-CH CAN FD HAT Rev2.1+MCP2518FD ×2 · Mode A · can0 + can1Auto-config
Pi 5: best-effort — not on Waveshare's list
•Waveshare 2-CH CAN HAT+ ← Pi 5 pickMCP2515 ×2 · 16 MHz · SPI1 CS1/CS2 · can0 + can1Auto-config
•Waveshare 2-CH CAN HAT (non-Plus)MCP2515 ×2 · 16 MHz · can0 + can1Auto-config
Documented through Pi 4B only
•PiCAN-MMCP2515 · 16 MHz · can0 · pulls in the 0183 stackAuto-config
•USB SocketCAN adaptergs_usb / candleLight · no overlay needed · can0 · can also be dedicated to passive SmartCraft/raw sniffingAuto-config
•No CAN hardwareSerial translation can still feed a private vcan / Signal K path; a physical NMEA 2000 output requires a CAN interface.Auto-config
•Waveshare USB TO 4CH RS485/422 (FT4232HL)NMEA 0183 / MTU RS-422 gateway · Ports A/B only for RS-422 · BOTH mode can dedicate A=0183, B=MTU · stable by-id pathsAuto-config
•J1587/J1708 legacy dieselBundled read-only translator → NMEA 2000 (data + diagnostic alarms) · port auto-detectAuto-config
•Standard NMEA 0183 via RS-422RMC/GGA/GLL/VTG · heading · water speed · depth · wind · sea temperature → NMEA 2000 PGNsAuto-config
•MTU Series 2000 (ECS-5) via RS-422Monitoring I/II point + alarm maps → NMEA 2000 · Waveshare 4CH gateway (Ports A/B) or generic RS-422 adapter · mandatory baudAuto-config
Capture-safe: E 531 652 serial framing pending
•NMEA 2000 ⇄ J1939 conversionBidirectional translator for matched PGNs · vcan auto-created when only one physical bus existsAuto-config
•Passive CAN protocol snifferNMEA 2000 · J1939 · both · SmartCraft candidate · raw CAN · multi-interface capture · no CAN transmissionAuto-config
•Pi Zero 2 W, Orange Pi, other SBCsScript runs but warns: hardened for Pi 4/5 onlyWarns

Status legend: AUTO-CONFIG = the wizard writes overlays, network config, translators, and services end-to-end · WARNS = proceeds at your own risk. Tip from the script itself: read the exact PCB name, chip marking (MCP2515 vs MCP2518FD), and oscillator before choosing — not the connector shape.