Runbook: telematics-gateway
Prerequisites
- PostgreSQL with OmniTrack schema applied (run the main app once so
ensureSchemacreates telematics tables). - By default the gateway auto-creates a stub
devicesrow for new IMEIs (profileunknown). SetTELEM_GATEWAY_ALLOW_UNKNOWN_IMEI=falseto require pre-registered IMEIs only.
Environment variables
| Variable | Default | Description |
|---|---|---|
DATABASE_URL | — | Required — same connection string as OmniTrack API |
TELEM_GATEWAY_PORT | 5027 | TCP listen port |
TELEM_GATEWAY_BIND | 0.0.0.0 | Bind address |
TELEM_GATEWAY_ALLOW_UNKNOWN_IMEI | true (unless set to false) | If not false, accept handshake and insert a stub device row for unknown IMEIs. Set to false for strict allowlists. |
METRICS_PORT | 9092 | HTTP port for /metrics (set 0 to disable) |
TELEM_COMMAND_MAX_ATTEMPTS | 5 | After this many on-wire sends, a timeout/CRC/close marks the row failed (no further retries) |
TELEM_COMMAND_TIMEOUT_MS | 45000 | Wait for Codec 12 0x06 response after sending a command |
Supported TCP codecs (ingest)
| Codec ID | Meaning |
|---|---|
0x08 | Codec 8 AVL (positions + IO) — stored in Postgres / Kafka |
0x8E | Codec 8 Extended AVL (FMBxxx IO layout) — same persistence path |
0x0C | Codec 12 GPRS command channel — 0x06 responses update the command queue; other types are consumed to keep the stream aligned |
Other codec IDs increment telematics_unknown_codec_packets_total and the frame is skipped (see /metrics).
Live map (/api/buses)
After each successful AVL batch, the gateway updates bus_locations_live for any bus whose imei matches the tracker. The web map reads positions from that table — unlinked trackers never draw a bus marker (only fleet inventory / device detail). Until a Socket.IO push is wired from the gateway process, clients may need a refresh to see new coordinates after GPS ingest.
Run locally
From repo root:
npx tsx services/telematics-gateway/src/main.ts
Or via npm script (see root package.json: npm run telematics-gateway).
Fake device (laptop → gateway)
With the stack up (docker compose up) and port 5027 reachable:
npm run simulate-tracker
# or
npx tsx scripts/simulate-teltonika-tracker.ts --host 127.0.0.1 --port 5027 --once
Sends a real Teltonika-style IMEI preamble + Codec 8 AVL; use --help for options.
Docker Compose
The optional service telematics-gateway is defined in docker-compose.yml. The production image runs npm ci --omit=dev so the pg package is present (the gateway bundle marks pg as external to esbuild).
Build/run the full stack:
docker compose up --build
Expose TCP 5027 only as needed (firewall / VPN).
Health checks
- Process logs:
listening,imei_connected,avl_records_written. - HTTP
GET http://127.0.0.1:9092/metrics— Prometheus text format (counters includetelematics_codec12_*).
Troubleshooting
| Symptom | Check |
|---|---|
| Device reconnects constantly | Ack count wrong; verify parser against wire capture |
| Connection refused | Port not exposed / firewall |
| IMEI rejected | Insert devices row first, or ensure TELEM_GATEWAY_ALLOW_UNKNOWN_IMEI is not false |
| DB errors | DATABASE_URL, migrations, disk space |
Logs & retention
- Optional table
device_ingest_rawstores hex for debugging; trim with a scheduled job in production.