Receiver ​
The receiver connects to one or more readsb TCP streams (raw ADS-B format), parses each frame to extract the ICAO hex identifier, wraps the message in a typed InboundMessage envelope, and routes it to the appropriate RabbitMQ queue based on a modulo-bucketing scheme. When RabbitMQ is unavailable the receiver writes to a local SQLite fallback queue and drains it automatically on reconnect. One receiver container handles all configured sources concurrently (one thread per source).
Configuration (settings.json) ​
Top-level fields ​
| Field | Type | Default | Description |
|---|---|---|---|
sources | array | — | List of readsb source objects (see below). At least one is required. |
processor_count | integer | 1 | Total number of processor containers. Must match the number of active processor services. Used to compute queue_name = adsb-{int(icao_hex, 16) % processor_count}. Increment this when adding a processor. |
rabbitmq | object | — | RabbitMQ connection settings (see below). |
mqtt | object | — | MQTT broker settings (see below). Omit the key entirely to disable MQTT. |
telemetry_interval_seconds | integer | 30 | How often (seconds) the receiver publishes MQTT statistic messages. |
data_dir | string | "/app/data" | Host-mounted directory where queue.db (the RabbitMQ offline fallback) is written. |
log_level | string | "info" | Log verbosity. Set to "debug" for verbose output. |
sources[] object ​
| Field | Type | Description |
|---|---|---|
host | string | Hostname or IP of the readsb instance. |
port | integer | TCP port of the readsb raw output (e.g. 30002 for 1090 MHz, 30978 for 978 MHz UAT). |
source | string | Tag applied to every message from this stream. One of "1090", "978", or "MLAT". |
Example with three sources:
{
"sources": [
{ "host": "192.168.1.10", "port": 30002, "source": "1090" },
{ "host": "192.168.1.10", "port": 30978, "source": "978" },
{ "host": "mlat-server.example.com", "port": 30105, "source": "MLAT" }
]
}An MLAT source does not need to be co-located with the receiver's SDR hardware — it's a plain TCP connection like any other source, so host can point at a remote MLAT-results feed (e.g. a readsb instance receiving results from an mlat-client). MLAT frames use the same raw Mode S format as 1090, so no separate parsing is required.
rabbitmq object ​
| Field | Type | Default | Description |
|---|---|---|---|
host | string | — | RabbitMQ hostname or IP. |
port | integer | 5672 | RabbitMQ AMQP port. |
username | string | — | RabbitMQ username. |
password | string | — | RabbitMQ password. |
mqtt object ​
| Field | Type | Default | Description |
|---|---|---|---|
host | string | — | MQTT broker hostname or IP. |
port | integer | 1883 | MQTT broker port. |
username | string | — | MQTT username. Optional — omit both username and password to connect anonymously. |
password | string | — | MQTT password. |
RECEIVER_ID Environment Variable ​
RECEIVER_ID is an optional integer environment variable (default 0). It distinguishes multiple receiver containers publishing to the same MQTT broker and is included in every MQTT topic published by the receiver.
environment:
RECEIVER_ID: "0"Routing ​
Each incoming message is routed to a durable RabbitMQ queue named adsb-{n} where:
n = int(icao_hex, 16) % processor_countThis ensures all messages for a given aircraft always go to the same processor, preserving per-aircraft flight state without coordination between processors. On RabbitMQ connect the receiver pre-declares all queues (adsb-0 through adsb-{processor_count - 1}).
Fault Tolerance ​
When RabbitMQ is unavailable (at startup or after a disconnect), messages are written to queue.db (SQLite WAL mode) in data_dir. Each row stores the target queue_name, the JSON payload, and the received_at timestamp. When the RabbitMQ connection is re-established, the fallback queue is drained oldest-first before new messages are forwarded. If RabbitMQ drops mid-drain, draining stops cleanly and resumes on the next reconnect.
MQTT Topics Published ​
All topics use the root SkyFollower.
| Topic | Payload | Retained |
|---|---|---|
SkyFollower/receiver/{receiver_id}/status | ONLINE or OFFLINE | Yes |
SkyFollower/receiver/{receiver_id}/statistics | JSON (see fields below) | Yes |
Statistics payload fields:
| Field | Type | Description |
|---|---|---|
messages_1090_per_second | float | Average 1090 MHz message rate since last report |
messages_978_per_second | float | Average 978 MHz UAT message rate since last report; only present if a 978 source is configured |
messages_MLAT_per_second | float | Average MLAT message rate since last report; only present if an MLAT source is configured |
local_queue_depth | integer | Messages queued in the local SQLite fallback (queue.db) |
rabbitmq_connected | boolean | true when an active RabbitMQ connection is held |
started_at | string | UTC ISO-8601 timestamp of process start |
A messages_{source}_per_second field is generated for every source tag present in sources[] — the table above lists the currently supported tags, not a fixed schema.
All statistics are published as a single retained JSON payload. Telemetry is published every telemetry_interval_seconds.
Home Assistant autodiscovery payloads are published to homeassistant/sensor/SkyFollower_receiver_{receiver_id}_{field}/config on MQTT connect. Each sensor uses state_topic: SkyFollower/receiver/{receiver_id}/statistics with a value_template to extract its field.
Adding or Changing readsb Sources ​
- Update the
sourcesarray insettings.json— add, remove, or edit entries. - Restart the receiver container.
Each source runs in its own thread; adding a source does not affect others. The source tag you choose is stamped on every message and carried through to the archived flight record.