-
Notifications
You must be signed in to change notification settings - Fork 0
Vessel Management System
The Vessel Management System (VMS) is the umbrella term for the Pi-based hardware/software stack that manages Defiant's operational state, sensors, and automation. It comprises three Raspberry Pis at the nav desk, the Victron Cerbo GX, and a network of MQTT and REST data flows that converge on Home Assistant as the single source of truth for boat state.
The stack assembled in the nav desk
The state plane. See Home-Assistant for hardware and sensor details.
- Standard HA web UI / REST API; the
defiantCLI uses the REST API for state reads/writes. - Hosts the Mosquitto MQTT broker that all onboard sensor publishers feed into.
- Long-lived access tokens issued from the HA profile page for programmatic clients.
The navigation plane. See Nav for AIS / N2K / autopilot wiring.
- Signal K with the
signalk-mqtt-home-assistantplugin (despite the name, it publishes RAW SK deltas — not HA-discovery configs — see Nav § Signal K → HA bridge). - Publishes
navigation.position,navigation.speedOverGround,navigation.courseOverGroundTrueto bare MQTT topics on the HA broker; minimum interval 60 s. - Mirrors the chartplotter view to the helm tablet.
The agent plane. Headless Pi 5 running an ironclaw instance ("Stubb", First Mate persona aboard Defiant) with telegram + web channels.
- Reaches HA over the LAN for state queries via the
defiantCLI. - Reachable remotely via Tailscale Funnel (deploy / hostname details kept out of this wiki).
The energy plane.
- Multi/SmartShunt data via the Cerbo's built-in MQTT (HA broker).
-
sensor.gx_device_ac_active_input_sourceis the canonical shore-power signal (unknown | grid | generator | shore_power | not_connected); MPPT data still pending the BLE proxy path (see Electrical).
HA is the source of truth for everything the agent and any future dashboards need to know about the boat:
| Field | HA entity | Source | Domain |
|---|---|---|---|
| Latitude | input_number.defiant_latitude |
Auto-fed by Signal K (~60 s) | input_number |
| Longitude | input_number.defiant_longitude |
Auto-fed by Signal K (~60 s) | input_number |
| Location name | input_text.defiant_location_name |
Manual | input_text |
| Mode | input_select.defiant_mode |
Auto-set by automations (or manual) | input_select |
| Destination | input_text.defiant_destination |
Manual (only meaningful when mode=underway) | input_text |
| Destination lat/lon | input_number.defiant_destination_latitude/_longitude |
Manual | input_number |
| ETA | input_datetime.defiant_eta |
Manual | input_datetime |
Mode enum values: underway | anchored | moored | docked | hauled-out | unknown.
Created by the Signal K → HA bridge via MQTT discovery; used by automations and exposed for any consumer that wants raw nav data:
-
sensor.defiant_signal_k_defiant_latitude(°) -
sensor.defiant_signal_k_defiant_longitude(°) -
sensor.defiant_signal_k_defiant_speed_over_ground(kn) -
sensor.defiant_signal_k_defiant_course_over_ground(°, normalised 0–360) -
device_tracker.defiant_signal_k_defiant(zone-friendly tracker for the HA UI)
| Automation | Trigger | Action |
|---|---|---|
defiant_shore_power_docked |
sensor.gx_device_ac_active_input_source → shore_power or grid, mode != docked |
Set mode = docked
|
defiant_shore_power_lost_notice |
shore power → not_connected while mode = docked |
Logbook entry only — disconnect is ambiguous (underway / cord-pulled / hauled) |
defiant_sync_signal_k_position_to_helpers |
SK lat/lon sensor change | Mirror to input_number.defiant_latitude/_longitude
|
defiant_sog_sustained_underway |
SoG > 1.0 kn for 5 min, mode != underway | Set mode = underway
|
defiant_sog_stopped_while_underway_notice |
SoG < 0.3 kn for 10 min while mode = underway | Logbook entry only — arrival type ambiguous |
Two non-actions are deliberate:
- Mode auto-clear on shore-power loss: disconnect could mean leaving the slip (underway), pulling the cord (still docked), or hauling out — auto-clearing would be wrong as often as right.
- Mode auto-clear on SoG drop: arrival type (anchor / mooring / slip / drifting) cannot be inferred from SoG alone.
NMEA 2000 / NMEA 0183 / GPS ──→ OpenPlotter (Signal K)
│
▼ MQTT (signalk-mqtt-ha plugin)
navigation.position, .speedOverGround, .courseOverGroundTrue
│
Cerbo GX ─────────→ MQTT ────────→ Mosquitto on HAOS Pi ←──── ESPHome devices
│
▼ HA MQTT discovery
sensor.* / device_tracker.* / binary_sensor.*
│
▼ automations
input_select.defiant_mode, input_number.defiant_latitude, ...
│
▼ REST
`defiant` CLI on ironclaw
Setup scripts and automation JSONs live in scripts/ha_setup/ in the refit repo:
-
create_helpers.py— idempotent; creates thedefiant_*helper entities via the HA WebSocket API. -
signalk_mqtt_discovery.py— publishes retained MQTT discovery messages so HA picks up the SK MQTT topics assensor.defiant_signal_k_*anddevice_tracker.defiant_signal_k_defiant. -
automations.json/automation_*.json— one file per automation listed above.
The defiant CLI uses HOME_ASSISTANT_ACCESS_TOKEN from environment or repo .env to talk to HA.
HA already runs on the LAN with a UI, history, auth, and physical-world auto-detection (Victron, Signal K, ESPHome). Multiple consumers — the agent, future dashboards, automations, scripts on other Pis — read the same REST endpoint for free. Hand-rolling a TOML on the ironclaw filesystem would duplicate all of that and never get the auto-detection.
The defiant state CLI keeps a write-through cache at ~/.defiant/state-cache.toml so reads survive HA being briefly unreachable; writes always go to HA, and a write failure exits non-zero rather than silently caching (a write that only made it to the cache would desync from every other consumer).
- HA hardware + sensor inventory: Home-Assistant
- Navigation hardware (AIS, N2K, autopilot, OpenPlotter): Nav
- Network architecture (Starlink, LAN, switch): Connectivity
- Victron / energy details: Electrical