EN | BG below
Keywords: AIS software, Automatic Identification System, NMEA 0183, AIVDM, AIVDO, multiplexer, deduplication, tag block, s/c/g, UDP, secure UDP, ECDSA, AES‑GCM, Raspberry Pi.
TL;DR
AISMixer merges multiple AIS receiver feeds, de‑duplicates messages, reliably reassembles multipart via Tag Blockg, and forwards a clean, unified stream.
It is tag‑aware: readss/c/gon ingress and (per policy) preserves / normalizes / overwrites them on egress — e.g., pass throughcor replace with server time; keep/normalizes; emit compactg.
AISMixer is a Python service that aggregates AIS NMEA‑0183 (AIVDM/AIVDO) from multiple receivers, removes duplicates, reassembles multipart messages, and forwards a single logical feed to marine platforms (e.g., MarineTraffic / AISHub / VesselTracker) or your own services.
- 🔐 Supports plain UDP and encrypted inputs via an ECDSA handshake + AES‑GCM transport (with the lightweight client proxy
nmea_sproxy). - 🧩 Tag‑aware end‑to‑end (reads/manages
s/c/g). - 📦 Clean output as if from one logical station.
- Multiple AIS receivers (hardware/software) send NMEA to AISMixer (UDP or secure via
nmea_sproxy). - AISMixer de‑duplicates identical payloads from different sources.
- AISMixer reassembles multipart AIVDM using Tag Block
g. - AISMixer forwards a unified stream downstream (per‑forwarder tag policy).
+------------+ UDP +-----------+ +----------------+
| Receiver A | ----------> | | ---> | MarineTraffic |
+------------+ | | | AISHub |
| AISMixer | ---> | VesselTracker |
+------------+ Encrypted | | | etc. |
| nmea_sproxy| ----------> | | +----------------+
+------------+ +-----------+
AISMixer parses Tag Block on ingress and manages what to emit on egress per policy:
g(group) — used to reliably reassemble multipart AIVDM.
When needed, AISMixer generates its own group IDs to ensure contiguous reassembly.s(source) — preserve incomings, map by IP/authorized key, or set a server‑defined station ID.c(timestamp) — pass through incoming time or replace it with server time (for clock normalization).
preserve— pass through incoming field (if present).normalize— rewrite into canonical form (e.g., compactg, sanitizeds).overwrite— ignore ingress and emit server value (e.g., server time forc).
station_id: mixstation_1 # if non-empty, it always becomes s=
debug: true
sec_inputs:
- id: secA # optional; if station_id empty, s=secA
listen_ip: "::"
listen_port: 29999
udp_inputs:
- listen_ip: "0.0.0.0"
listen_port: 17777
id: udpA # optional; if station_id empty, s=udpA
- listen_ip: "::"
listen_port: 17777
forwarders:
- host: 203.0.113.10
port: 5000
udp_alias_map_file: udp_alias_map.yaml # optional
# (beta) Optional tag policy — may land as per-forwarder or global
# tag_policy:
# s: preserve # preserve | normalize | overwrite
# c: overwrite # use server time
# g: normalize # server-formed compact groups when reassembledPriority:
- If
station_idis non‑empty → s = station_id - Else, if the input has an
id(incl.sec_inputs[].id) → s = input.id - Else:
- UDP: if remote IP exists in
udp_alias_map.yaml→ s = alias - SEC: if a name exists in
authorized_keys.yaml→ s = client_name (elseANONYMOUS)
- UDP: if remote IP exists in
- Else, if the incoming line already carries
\s:…\→ s = that value - Else → s = IP (dots/colons replaced with
_)
All variants are sanitized to [A–Za–z0–9_] and limited to 15 characters.
"127.0.0.1": "lo_alias"
"2001:db8::1234": "dock_gate"| Module/Dir | Role |
|---|---|
aismixer.py |
Main mixer process (UDP + secure inputs) |
aismixer_secure.py |
ECDSA handshake, decryption, authentication |
nmea_sproxy/ |
Lightweight client-side secure UDP proxy |
assembler.py |
Multipart reassembly using Tag Block g |
dedup.py |
Duplicate detection/removal |
meta_writer.py |
Adds NMEA tag block/prefix and CRC |
meta_cleaner.py |
Removes non-standard meta headers |
forwarder.py |
Sends the clean output to destinations |
config.yaml |
Inputs/outputs, station ID, debug, (tag policy — beta) |
authorized_keys.yaml |
Allowed client public keys (for secure inputs) |
python3 aismixer.pyOr install as a systemd service using install.sh (copies unit to /etc/systemd/system/).
- Handshake: ECDSA-based mutual check; clients are authorized via
authorized_keys.yaml. - Transport: AES-GCM for integrity + confidentiality over UDP.
- Replay resistance: nonces/timestamps in handshake (client proxy
nmea_sproxy).
Ключови думи: AIS софтуер, Automatic Identification System, NMEA 0183, AIVDM, AIVDO, multiplexer, deduplication, tag block, s/c/g, UDP, secure UDP, ECDSA, AES‑GCM, Raspberry Pi.
TL;DR
AISMixer обединява няколко AIS приемни потока, премахва дубликати, надеждно сглобява мултипарт чрез Tag Blockgи излъчва чист, обединен поток.
Системата е tag‑aware: четеs/c/gна вход и (според политика) preserve / normalize / overwrite на изход — напр. запазваcили го заменя със сървърно време; запазва/нормализираs; излъчва компактенg.
AISMixer е Python услуга, която агрегира AIS NMEA‑0183 (AIVDM/AIVDO) от няколко приемника, премахва дубликати, сглобява мултипарт съобщения и препраща един логически поток към външни платформи или ваши услуги.
- 🔐 Поддържа обикновен UDP и защитен вход чрез ECDSA handshake + AES‑GCM транспорт (клиентско прокси
nmea_sproxy). - 🧩 Tag‑aware от край до край (чете/управлява
s/c/g). - 📦 Чист изход сякаш е от една логическа станция.
- Няколко приемника (хардуерни/софтуерни) изпращат NMEA към AISMixer (UDP или защитено чрез
nmea_sproxy). - AISMixer дедупликира еднакви полезни товари от различни източници.
- AISMixer сглобява мултипарт AIVDM чрез Tag Block
g. - AISMixer форурдва обединения поток (per‑forwarder tag политика).
+------------+ UDP +-----------+ +----------------+
| Receiver A | ----------> | | ---> | MarineTraffic |
+------------+ | | | AISHub |
| AISMixer | ---> | VesselTracker |
+------------+ Encrypted | | | и др. |
| nmea_sproxy| ----------> | | +----------------+
+------------+ +-----------+
AISMixer чете Tag Block на входа и решава какво да излъчи на изхода по политика:
g(group) — за надеждно сглобяване на мултипарт AIVDM.
При нужда AISMixer генерира собствени group ID‑та за последователно сглобяване.s(source) — запази входнияs, мапни по IP/ключ, или задай сървърен station ID.c(timestamp) — пропусни входното време или замени със сървърно време (нормализация на часовниците).
preserve— запази входното поле (ако е налично).normalize— пренапиши в канонична форма (напр. компактенg, sanitizeds).overwrite— игнорирай входа и издай сървърна стойност (напр. сървърно време заc).
station_id: mixstation_1 # ако е непразно → винаги става s=
debug: true
sec_inputs:
- id: secA # по избор; ако station_id е празно, s=secA
listen_ip: "::"
listen_port: 29999
udp_inputs:
- listen_ip: "0.0.0.0"
listen_port: 17777
id: udpA # по избор; ако station_id е празно, s=udpA
- listen_ip: "::"
listen_port: 17777
forwarders:
- host: 203.0.113.10
port: 5000
udp_alias_map_file: udp_alias_map.yaml # по избор
# (beta) По избор — политика за тагове (per‑forwarder или глобална)
# tag_policy:
# s: preserve
# c: overwrite # сървърно време
# g: normalize # компактни групи при сглобяванеПриоритет:
- Ако
station_idе непразно → s = station_id - Иначе, ако входът има
id(вкл.sec_inputs[].id) → s = input.id - Иначе:
- UDP: ако remote IP е в
udp_alias_map.yaml→ s = alias - SEC: ако има име в
authorized_keys.yaml→ s = client_name (иначеANONYMOUS)
- UDP: ако remote IP е в
- Иначе, ако входящият ред вече носи
\s:…\→ s = тази стойност - Иначе → s = IP (точки/двуеточия →
_)
Всички варианти се sanitize‑ват до [A–Za–z0–9_] и лимит 15 символа.
"127.0.0.1": "lo_alias"
"2001:db8::1234": "dock_gate"| Компонент | Роля |
|---|---|
aismixer.py |
Основен процес (UDP + secure входове) |
aismixer_secure.py |
ECDSA handshake, дешифриране, автентикация |
nmea_sproxy/ |
Леко клиентско secure UDP прокси |
assembler.py |
Сглобяване на мултипарт чрез Tag Block g |
dedup.py |
Премахване на дубликати |
meta_writer.py |
Добавя NMEA tag block/префикс и CRC |
meta_cleaner.py |
Премахва нестандартни мета‑хедъри |
forwarder.py |
Изпраща изчистения изход към дестинациите |
config.yaml |
Входове/изходи, station ID, debug, (tag политика — beta) |
authorized_keys.yaml |
Публични ключове на разрешените клиенти |
python3 aismixer.pyИли като systemd услуга чрез install.sh.
- Handshake: ECDSA взаимна проверка; клиентите се описват в
authorized_keys.yaml. - Транспорт: AES‑GCM за целост и конфиденциалност по UDP.
- Anti‑replay: nonces/времеви маркери в handshake (клиент
nmea_sproxy).