Skip to main content

AIS Vessel Tracking

Heimdall tracks nearby vessels via aisstream.io, a WebSocket-based AIS (Automatic Identification System) data provider. Vessel positions are streamed in real time to connected frontend clients.

How It Works

  1. The AisClient (in heimdall-websocket) connects to wss://stream.aisstream.io/v0/stream.
  2. It subscribes with a bounding box centered on the latest GPS position, updated every 60 seconds if the vessel moves more than 1 km.
  3. Two message types are processed:
    • PositionReport — updates position, speed, heading.
    • ShipStaticData — updates name, type, dimensions.
  4. Vessel data is maintained in an in-memory HashMap<MMSI, Vessel>.
  5. Updates are throttled to 1/sec and broadcast to WebSocket channel "vessels".
  6. Stale vessels (no update for 30 minutes) are pruned every 30 seconds.

Configuration

[ais]
enabled = false
api_key = "" # env: HEIMDALL__AIS__API_KEY
radius_km = 10.0
ignore_mmsi = [] # MMSI blocklist (e.g. own vessel)

Environment: HEIMDALL__AIS__API_KEY=your-key

WebSocket Channel

There are no REST or GraphQL endpoints for AIS data. Subscribe to channel "vessels" via WebSocket.

interface VesselsMessage {
type: 'vessels';
data: {
vessels: Vessel[];
bbox: {
center: [number, number];
radius_km: number;
sw: [number, number];
ne: [number, number];
};
};
}

interface Vessel {
mmsi: number;
name: string;
shipType: number | null;
navStatus: number | null;
length: number | null;
beam: number | null;
lat: number;
lng: number;
heading: number | null; // null when unavailable (AIS code 511)
course: number | null;
speedKmh: number; // converted from knots (* 1.852)
lastUpdate: string; // ISO 8601
}

See the WebSocket API for connection details.

Frontend Integration

Use the useVessels hook and VesselMarker component from @elcto/ui:

import { useVessels, VesselMarker } from '@elcto/ui';

const { vessels, bbox, connected } = useVessels(wsUrl);

VesselMarker renders a color-coded dot on the map:

  • Orange — moving vessel
  • Gray — stationary or moored

The marker includes a directional arrow (heading) and a cycling info badge (name, speed, ship type).

Vessel Data Notes

  • Speed is stored and transmitted in km/h (converted from AIS knots: knots × 1.852).
  • Heading value 511 in the AIS protocol means "unavailable" — mapped to null.
  • The bounding box subscription is GPS-position-dependent. If no GPS data exists, the AIS client waits before subscribing.
  • Ship type and navigation status codes are translated to German labels via translateShipType() and translateNavStatus() utilities in @elcto/ui.

Reconnection

The client uses exponential backoff (3s → 60s max) on disconnect.