Deploy "ultrafeeder"
The "ultrafeeder" container is the heart of our "adsb" application. It receives 1090MHz ADS-B ES signals from your SDR, and demodulates ADS-B messages, making them available for all other containers.
It also provides a website with a map based on tar1090, station statistics (graphs1090), mlat-client, and an mlat-hub to aggregate MLAT results.
In your favorite text editor, create a file named docker-compose.yml in your application directory (/opt/adsb if you've been following along verbatim).
nano docker-compose.ymlservices:
ultrafeeder:
# ultrafeeder combines a number of functions:
# - it retrieves and decodes 1090MHz Mode A/C/S data from the SDR(s) using Wiedehopf's branch of readsb
# - it implements a `tar1090` based map on port 80 (mapped to port 8080 on the host)
# - it includes graph1090 (system statistics website) on http://xxxxx/graphs1090
# - it sends ADSB data directly (without the need of additional containers) to the
# "new" aggregators, and, if desired, also to ADSBExchange
# - it includes mlat-client to send MLAT data to these aggregators
# - it includes an MLAT Hub to consolidate MLAT results and make them available to the built-in map and other services
image: ghcr.io/sdr-enthusiasts/docker-adsb-ultrafeeder
container_name: ultrafeeder
hostname: ultrafeeder
restart: unless-stopped
device_cgroup_rules:
- 'c 189:* rwm'
ports:
- 8080:80 # to expose the web interface
environment:
# --------------------------------------------------
# general parameters:
- LOGLEVEL=error
- TZ=${FEEDER_TZ}
# --------------------------------------------------
# SDR related parameters:
- READSB_DEVICE_TYPE=rtlsdr
- READSB_RTLSDR_DEVICE=${ADSB_SDR_SERIAL}
- READSB_RTLSDR_PPM=${ADSB_SDR_PPM}
#
# --------------------------------------------------
# readsb/decoder parameters:
- READSB_LAT=${FEEDER_LAT}
- READSB_LON=${FEEDER_LONG}
- READSB_ALT=${FEEDER_ALT_M}m
- READSB_RX_LOCATION_ACCURACY=2
- READSB_STATS_RANGE=true
#
# --------------------------------------------------
# Sources and Aggregator connections:
# Note - remove the ones you are not using / feeding
# Make sure that each line ends with a semicolon ";"
# if you are not using dump978, feel free to remove the first line
- ULTRAFEEDER_CONFIG=
adsb,dump978,30978,uat_in;
adsb,feed.adsb.fi,30004,beast_reduce_plus_out;
mlat,feed.adsb.fi,31090;
adsb,in.adsb.lol,30004,beast_reduce_plus_out;
mlat,in.adsb.lol,31090;
adsb,feed.airplanes.live,30004,beast_reduce_plus_out;
mlat,feed.airplanes.live,31090;
adsb,feed.planespotters.net,30004,beast_reduce_plus_out;
mlat,mlat.planespotters.net,31090;
adsb,feed.theairtraffic.com,30004,beast_reduce_plus_out;
mlat,feed.theairtraffic.com,31090;
adsb,data.avdelphi.com,24999,beast_reduce_plus_out;
adsb,skyfeed.hpradar.com,30004,beast_reduce_plus_out;
mlat,skyfeed.hpradar.com,31090;
adsb,dati.flyitalyadsb.com,4905,beast_reduce_plus_out;
mlat,dati.flyitalyadsb.com,30100;
adsb,feed1.adsbexchange.com,30004,beast_reduce_plus_out;
mlat,feed.adsbexchange.com,31090;
mlathub,piaware,30105,beast_in;
mlathub,rbfeeder,30105,beast_in;
mlathub,radarvirtuel,30105,beast_in;
mlathub,planewatch,30105,beast_in;
# --------------------------------------------------
- UUID=${ULTRAFEEDER_UUID}
- MLAT_USER=${FEEDER_NAME}
- READSB_FORWARD_MLAT_SBS=true
#
# --------------------------------------------------
# TAR1090 (Map Web Page) parameters:
- UPDATE_TAR1090=true
- TAR1090_MESSAGERATEINTITLE=true
- TAR1090_PAGETITLE=${FEEDER_NAME}
- TAR1090_PLANECOUNTINTITLE=true
- TAR1090_ENABLE_AC_DB=true
- TAR1090_FLIGHTAWARELINKS=true
- HEYWHATSTHAT_PANORAMA_ID=${FEEDER_HEYWHATSTHAT_ID}
- HEYWHATSTHAT_ALTS=${FEEDER_HEYWHATSTHAT_ALTS}
- TAR1090_SITESHOW=true
- TAR1090_RANGE_OUTLINE_COLORED_BY_ALTITUDE=true
- TAR1090_RANGE_OUTLINE_WIDTH=2.0
- TAR1090_RANGERINGSDISTANCES=50,100,150,200
- TAR1090_RANGERINGSCOLORS='#1A237E','#0D47A1','#42A5F5','#64B5F6'
- TAR1090_USEROUTEAPI=true
#
# --------------------------------------------------
# GRAPHS1090 (Decoder and System Status Web Page) parameters:
- GRAPHS1090_DARKMODE=true
#
# --------------------------------------------------
volumes:
- /opt/adsb/ultrafeeder/globe_history:/var/globe_history
- /opt/adsb/ultrafeeder/graphs1090:/var/lib/collectd
- /proc/diskstats:/proc/diskstats:ro
- /dev/bus/usb:/dev/bus/usb:rw
tmpfs:
- /run:exec,size=256M
- /tmp:size=128M
- /var/log:size=32MIn the file above, you will find several parameters that have values denoted as ${xxxx}. These values are read from a file in the same directory named .env that we created earlier. Alternatively, you can simply replace ${xxxx} with the value you want to use, for example READSB_RTLSDR_DEVICE=${ADSB_SDR_SERIAL} --> READSB_RTLSDR_DEVICE=0000001090.
The docker-compose.yml file above will:
Create a few mapped docker volumes to store historic message values (
/var/globe_history), statistics for the graphs (/var/lib/collectd), and make the disk statistics (/proc/diskstats) and USB devices (/dev) available to the container.Create a service named
ultrafeederthat will run theghcr.io/sdr-enthusiasts/docker-adsb-ultrafeedercontainer.We're mapping TCP port
8080through to the container so we can access the web interface.The variable
READSB_RTLSDR_DEVICEtellsreadsbto look for an RTL-SDR device with the serial of1090(that we re-serialized in an earlier step).We're passing several environment variables through, including our timezone, latitude and longitude from the
.envfile (denoted by${VARIABLE}).
We're using
tmpfsfor volumes that have regular I/O. Any files stored in atmpfsmount are temporarily stored outside the container's writable layer. This helps to reduce:The size of the container, by not writing changes to the underlying container; and
SD Card or SSD wear
You can find an expanded example of the docker-compose.yml file that you can download and edit here if you want to see other options, but the sample above is a good start.
Feeding directly from Ultrafeeder
There are several aggregators, both non-profit and commercial, that can directly be sent data from ultrafeeder without the need for an additional feeder container. We have added them in the example docker-compose.yml file above. Here is a partial list of these aggregators. All of them use the beast_reduce_plus format for feeding ADS-B data, and mlat-client for feeding MLAT:
Name
(C)ommercial/ (N)on-profit
Description
Feed details
Airplanes.live
N
Run by volunteers that used to be related to adsbexchange
adsb:feed.airplanes.live port 30004
mlat: feed.airplanes.live port 31090
ADSB.fi
N
Run by a Finnish IT and aviation enthusiast
adsb:feed.adsb.fi port 30004
mlat: feed.adsb.fi port 31090
ADSB.lol
N
Run by an aviation enthusiast located in the Netherlands
adsb:in.adsb.lol port 30004
mlat: in.adsb.lol port 31090
Planespotters
N
planespotters.net
adsb:feed.planespotters.net port 30004
mlat: mlat.planespotters.net port 31090
The Air Traffic
N
Run by an aviation enthusiast
adsb:feed.theairtraffic.com port 30004
mlat: mlat.theairtraffic.com port 31090
AVDelphi
N
Aviation data-science company (non-profit)
adsb:data.avdelphi.com port 24999
mlat: no MLAT
ADSB Exchange
C
Large aggregator owned by JetNet
adsb:feed1.adsbexchange.com port 30004
mlat: feed.adsbexchange.com port 31090
Fly Italy ADSB
N
Run by a few aviation enthusiasts in Italy
adsb: dati.flyitalyadsb.com port 4905
mlat: dati.flyitalyadsb.com port 30100
When feeding AdsbExchange, Ultrafeeder will send statistics to adsbexchange.com by default. See the description of the ADSBX_STATS parameter on how to disable this.
Using the MLAT results
A working MLAT configuration is already provided in the example above. See https://github.com/sdr-enthusiasts/docker-adsb-ultrafeeder/blob/main/README.md#configuring-the-built-in-mlat-hub for more details on how to configure more advanced features.
Deploying ultrafeeder
ultrafeederOnce the docker-compose.yml file is created, issue the command docker compose up -d to bring up the environment.
You should see the following output:
We can view the logs for the environment with the command docker compose logs, or continually "tail" them with docker compose logs -f. At this stage, the logs will be fairly extensive and unexciting and look like this:
We can see our container running with the command docker ps:
We can see the adsb_default network with the command docker network ls:
Ultrafeeder Web Pages
If configured and started using the example above, the container will make a website available at port 8080 of your host machine. Here are a few web pages that are generated (replace my_host_ip with the name or IP address of your host machine):
http://my_host_ip:8080/:tar1090map and table of all aircraft receivedhttp://my_host_ip:8080/graphs1090/: page with graphs and operations statistics of your stationhttp://my_host_ip:8080?pTracks: showing all aircraft tracks received in the last 24 hourshttp://my_host_ip:8080?heatmap&realheat: showing a heatmap of all aircraft in the last 24 hourshttp://my_host_ip:8080?replay: showing a time-lapse replay of the past few days
Viewing Live Data in Text Format
To see the data being received and decoded by our new container, run the command docker exec -it ultrafeeder viewadsb. This should display a real-time departure-lounge-style screen showing all the aircraft being tracked, for example:
Press CTRL-C to escape this screen.
You should also be able to point your web browser to http://docker.host.ip.addr:8080/ to view the web interface (change docker.host.ip.addr to the IP address or hostname of your docker host). You should see a map showing your currently tracked aircraft, and a link to the "Performance Graphs".
UUID security
The example files above use the same UUID for all feeders. Doing so makes it possible that your information from one site could be tracked on another. An alternative approach is to generate a unique UUID for each website, load those into a variable in .env, and append the UUID to the row in the ULTRAFEEDER_CONFIG section. For example:
Preparing and setting up ultrafeeder with Prometheus and Grafana
ultrafeeder with Prometheus and GrafanaSee readme-grafana.MD at the container's Github repository web page.
Minimalist setup
If you want to use ultrafeeder only as a SDR decoder but without any mapping or stats/graph websites, without MLAT connections or MLAT-hub, etc., for example to minimize CPU and RAM needs on a low CPU/memory single board computer, then do the following:
in the
ULTRAFEEDER_CONFIGparameter, remove any entry that starts withmlatormlathub. This will prevent anymlat-clients ormlathubinstances to be launched. If you want to connect themlat-client(s) to external MLAT servers but you don't want to run the overhead of a MLATHUB, you can leave any entries starting withmlatin theULTRAFEEDER_CONFIGparameter, and setMLATHUB_DISABLE=trueSet the parameter
TAR1090_DISABLE=true. This will prevent thenginxweb server and any websites from being launchedMake sure not to use the
ghcr.io/sdr-enthusiasts/docker-adsb-ultrafeeder:telegraflabel as Telegraf adds a LOT of CPU, disk, and memory use to the container
Advanced
If you want to look at more options and examples for the ultrafeeder container, you can find the repository here.
Last updated
Was this helpful?