Open-source project
wiedehopf/graphs1090 avatar
wiedehopf/graphs1090

graphs1090 keeps ADS-B receiver history on your own Raspberry Pi

Graphs for readsb / dump1090-fa / dump1090 (based on dump1090-tools by mutability)

531 stars52 forksShellMIT

At a glance

What is it?
graphs1090 collects the stats feed from readsb, dump1090-fa and other dump1090 variants into collectd and rrdtool databases and serves the resulting graphs over nginx from the machine doing the receiving. The install is one piped shell script, the trade-off is a set of Python and configuration files that only the author fully understands, and the graphs live in memory until they are written to the SD card at night.
Who is it for?
graphs1090 fits a home lab operator or a small club station that wants long term ADS-B receiver history on hardware it controls, and it does not fit anyone who wants a hosted map, a supported product or a configurable dashboard.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 4 days ago.
What is it written in?
Mainly Shell, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Long term graphs from the receiver you already run

An ADS-B receiver running readsb or dump1090 already produces a live map and a stream of statistics. What it does not produce is history you can look back through. graphs1090 fills that gap: it reads the statistics feed from the receiver, stores it in time series databases, and serves the graphs as web pages from the same machine.

The README states the compatibility plainly. The project is for readsb, the fork maintained by the same author, and for dump1090-fa, and it also works with other dump1090 variants that supply a stats.json file. The graphs are based on dump1090-tools by mutability, which is where the original graphing approach came from.

The audience is a Raspberry Pi operator running a receiver at home or at a field station. The value is that the history stays on your own hardware: you can see how many aircraft were in range over the last month, what the signal counts look like over a week, how the noise floor changes with weather and antenna placement. The graphs are plain HTML pages served by nginx, and there are three entry points, the graphs page, a performance page, and a port for the live view.

bash
http://192.168.x.yy/graphs1090

That is a very different shape from the hosted aggregation services that show a global picture. Here you are looking at one antenna, one receiver and one site, which is exactly the data you need for placement decisions and exactly the data that says nothing about the wider airspace.

Installation is one piped script and it needs root

The install and update path is a single command that pipes a remote script into bash, which is convenient and is worth understanding before you run it.

bash
sudo bash -c "$(curl -L -o - https://github.com/wiedehopf/graphs1090/raw/master/install.sh)"

The same command serves as the update, so keeping it around in your notes is the whole upgrade procedure. Two other paths exist for people who want to see what they are running. A forced reinstall is done by downloading install.sh and running bash install.sh reinstall, and local changes can be tested by cloning the repository, making the change and running ./install.sh test, which installs from the local copy instead of the remote one.

The script installs a set of moving parts. The repository root shows what they are: a collectd configuration, nginx configuration files for the graphs and for a non-standard port, an html directory for the generated pages, a Python module called dump1090.py that collectd imports, an install.sh, uninstall.sh, and a set of helper scripts for pruning, tagging, backing up and restoring the round robin databases. There is also a version file, and an uninstall script, which is a good sign for a script that reaches this far into a system.

One point of friction is worth flagging: there is no package manager entry and no repository of your own. Everything lands in system paths such as /usr/share/graphs1090, and the configuration lives in /etc/default/graphs1090. That is normal for this kind of appliance script and it does mean you should snapshot the configuration before upgrading.

collectd and rrdtool do the storage work

The mechanism is a standard Unix one. collectd is the collector daemon, its python plugin imports the dump1090 module shipped with the project, and the module polls the receiver's local map URL for statistics. Those numbers become time series in rrdtool databases, and a set of scripts render the pages under html/.

The plugin configuration shows the wiring in full.

code
<Plugin python>
        ModulePath "/usr/share/graphs1090"
        LogTraces true
        Import "dump1090"
        <Module dump1090>
                <Instance localhost>
                        URL "http://localhost/dump1090-fa"
                </Instance>
        </Module>
</Plugin>

The URL is the single point where the receiver is addressed, and it is the one thing you have to change if your setup is not standard. If your local map is not reachable at /dump1090-fa or /dump1090, the README tells you to edit the collectd configuration to point at the right place, and then to restart the collector.

bash
sudo systemctl restart collectd

The receiver's own location setting matters for the range graph, because a range plot needs to know where the receiver is to convert counts into distance. The README says you configure the location in dump1090-fa or readsb, and points at editing /etc/default/dump1090-fa or /etc/default/readsb, or using the online stats page for a piaware image.

There is also an option to fold non-ADS-B positions, such as ADS-C or HFDL, into the range graph, but it is applied by editing a file in place.

bash
sed -i -e 's/range_include_nonadsb = False/range_include_nonadsb = True/' /usr/share/graphs1090/dump1090.py

The catch is stated as well: the command has to be rerun after each update of graphs1090, because the installer rewrites the file. That is the shape of the whole project, a set of small scripts that assume a single author knows the details.

The SD card write policy, and what it costs you

The most interesting engineering decision in the project is about flash wear, not graphs. By default the collected data is written to the SD card only once every 24 hours, with the systemd service reconfigured to keep the graph data in /run, which is memory, and to write it to disk at night. On reboot or shutdown the data is written and loaded back into /run when the machine boots.

The cost of that choice is stated in plain language: up to 24 hours of data is lost on a power loss. The README repeats the warning in the installation section, saying that when you remove or lose power you will lose graph data generated after 23:42 of the previous day, and that you should run sudo shutdown now before unplugging the Pi. Reboots and clean shutdowns do not lose data.

The schedule is a cron entry in /etc/cron.d/collectd_to_disk, and the README shows the three options it ships with.

code
# every day at 23:42
42 23 * * * root /bin/systemctl restart collectd

# every Sunday
42 23 * * 0 root /bin/systemctl restart collectd

# every 6 hours
42 */6 * * * root /bin/systemctl restart collectd

Editing that file changes the schedule, although running the install script again resets it to the default. The same behaviour can be turned off and on with two helper scripts, one that stops the mechanism and one that re-enables it.

bash
sudo bash /usr/share/graphs1090/git/stopMalarky.sh
bash
sudo bash /usr/share/graphs1090/git/malarky.sh

There is a second, system wide lever for people who have the nightly write disabled. The round robin databases are written every minute, which the README puts at roughly 100 megabytes per hour, and the Linux page cache write delay can be increased to cut that. The documented change is a sysctl file, and the README is explicit that you should not apply it if you mind losing the last ten minutes of data.

bash
sudo tee /etc/sysctl.d/07-dirty.conf <<EOF
vm.dirty_ratio = 40
vm.dirty_background_ratio = 30
vm.dirty_expire_centisecs = 60000
EOF

Changing the graph layout

Layout options live in a single configuration file, /etc/default/graphs1090, and the README's instruction for changing something such as the graph size is to edit it directly.

bash
sudo nano /etc/default/graphs1090

The save-and-exit sequence is spelled out as well: ctrl-x to exit, then y and enter to save. The full set of available options is published as a plain file in the repository, so you can read what the file supports before you edit it, and one of the recently added options is a dark color scheme.

To go back to the shipped defaults, the README gives a copy command rather than an in-place edit.

bash
sudo cp /usr/share/graphs1090/default-config /etc/default/graphs1090

This is a pleasantly small configuration surface, and it is a reminder of how the rest of the project works: the layout options are a static file, and everything that behaves dynamically is either a cron entry or a systemd unit. There is no web interface for the settings and no database of preferences, which keeps the install simple and keeps the moving parts to the collector, the databases and nginx.

For a database that has accumulated in an older format, the README describes a reset procedure that retains the data but can cause anomalies, and it recommends taking a backup first, noting that the script does create one automatically. That is the point where the project asks the most trust of the reader, and it is worth understanding before running it rather than after.

Where graphs1090 stops being the right tool

The honest limitations come from the design rather than from bugs. The first is that it assumes a specific stack: a systemd host with root access, collectd, rrdtool, nginx and a Python module, on a Raspberry Pi or similar. It is not portable to a locked down appliance, and it is not something you can run unprivileged, since the install script writes to system directories and manages services.

The second is that it is a shell and configuration project without releases. The repository publishes no GitHub releases, so there is no version to pin and no changelog to diff against. There is a version file in the root, and the install script pulls the current master, which means the behaviour on your machine can change when you update, including the file that the non-ADS-B sed command edits, which the README explicitly warns you about.

The third is the hard dependency on the receiver's web interface. If your local map is not at a standard path, the collection breaks until you edit the collectd configuration, and the range graph additionally needs a location configured in the decoder. Those are the two failure modes the README spends most of its space on, which tells you where the sharp edges are.

The alternative is a hosted aggregation service, and the README itself points at adsb.im when the range graph will not work. The difference in approach is direct: a hosted service does the collection, the storage and the graphing on someone else's hardware, so you have no SD card to protect and no cron schedule to reason about, and in exchange you send your position data to a third party and you see their aggregation rather than your own site. For a receiver whose location is public anyway and whose history is mostly for fun, that is a reasonable trade. For a site where the graph history is the point, running collectd yourself is the reason this project exists.

Editorial conclusion

graphs1090 fits a home lab operator or a small club station that wants long term ADS-B receiver history on hardware it controls, and it does not fit anyone who wants a hosted map, a supported product or a configurable dashboard. Before installing it, confirm that your receiver's web interface is reachable at the local map path, and decide whether the default nightly write is acceptable, because the README states that data generated after 23:42 of the previous day is lost on power loss. The last push was on 2026-10-19, the project publishes no GitHub releases, and the licence is MIT.

Frequently asked questions

How do I install graphs1090?

The README gives a single command that pipes the install script into bash with sudo, and the same command updates an existing installation. A forced reinstall is done by downloading install.sh and running bash install.sh reinstall, while local changes can be installed with ./install.sh test from a cloned repository.

Which receivers does graphs1090 work with?

The README states it is for readsb, the fork maintained by the same author, and for dump1090-fa, based on dump1090-tools by mutability. It also works with other dump1090 variants that supply a stats.json file.

Why is my graph data missing after a power loss?

To reduce writes to the SD card, the data is kept in /run and written to disk only every 24 hours, which the README says means up to 24 hours of data is lost on a power loss. Running sudo shutdown now before unplugging the Pi avoids it, and the write schedule can be changed in /etc/cron.d/collectd_to_disk.

Why is the range graph empty in graphs1090?

The range graph needs the location configured in your decoder, in dump1090-fa or readsb. The README says to edit /etc/default/dump1090-fa or /etc/default/readsb, or to set the location on the online stats page for a piaware image, and it also requires the local map URL to be reachable from the collectd configuration.

How do I change the graph size or colors in graphs1090?

Edit /etc/default/graphs1090, for example with sudo nano /etc/default/graphs1090, and save with ctrl-x, then y and enter. The available options are published in the default file in the repository, and the shipped configuration can be restored with sudo cp /usr/share/graphs1090/default-config /etc/default/graphs1090.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. wiedehopf/graphs1090 on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/wiedehopf-graphs1090.svg)](https://hysenlabs.com/projects/wiedehopf-graphs1090)

Was this useful?