One-shot readings
Run it bare and get an AQI headline plus a full metric table. Exits non-zero when the device is unreachable, so it drops straight into scripts and monitoring.
A fast Rust CLI and live TUI dashboard for your local AirGradient monitor. Reads the same config as the desktop app, talks straight to the device on your LAN, and never phones home.
curl --proto '=https' --tlsv1.2 -sSf \
https://worxbend.github.io/airgradient-cli/install.sh | sh
Verifies the SHA256 checksum before installing.
The installer resolves the latest release, downloads the archive
for your architecture, checks it against the release’s
SHA256SUMS, and drops the binary in
~/.local/bin.
Pipe it to sh, or download and read it first.
airgradient-cli config set-url 192.168.1.201
airgradient-cli or -t for the dashboard.
curl --proto '=https' --tlsv1.2 -sSf \
https://worxbend.github.io/airgradient-cli/install.sh | sh
curl --proto '=https' --tlsv1.2 -sSf \
https://github.com/worxbend/airgradient-cli/releases/download/v0.2.0/install.sh \
| sh -s -- --version v0.2.0
curl --proto '=https' --tlsv1.2 -sSf \
https://worxbend.github.io/airgradient-cli/install.sh \
| sh -s -- --dir /usr/local/bin
curl -fsSLO https://worxbend.github.io/airgradient-cli/install.sh
less install.sh
sh install.sh --help
Linux only. Published binaries cover
x86_64-unknown-linux-gnu and
aarch64-unknown-linux-gnu. On anything else, build
from source with cargo build --release — see the
release boundary.
Run it bare and get an AQI headline plus a full metric table. Exits non-zero when the device is unreachable, so it drops straight into scripts and monitoring.
-t opens an auto-refreshing Ratatui dashboard with
gauges, trend arrows, and status colors that mirror the device’s
own LED.
--json emits every metric with its raw value,
formatted value, unit, status, and trend — ready for
jq, Prometheus textfile, or a cron job.
Nord, Dracula, Gruvbox, Catppuccin, Tokyo Night, and more — including a TTY-safe mono theme that leaves your terminal palette alone.
j/k, gg/G, Ctrl-d/Ctrl-u, : for the command line, and Space as an AstroNvim-style which-key leader. Or just scroll and click.
Talks to your device over the LAN and nothing else. A malformed config warns per field instead of failing, so a bad value never locks you out of the tool that fixes it.
Real output from airgradient-cli fetch against a
device serving the standard /measures/current payload.
Device: http://192.168.1.201/ | Fetch: 2ms
AQI 41 - Good
+-------------+-------+----------+----------+-------+
| Metric | Value | Unit | Status | Trend |
+===================================================+
| AQI | 41 | | Good | -- |
|-------------+-------+----------+----------+-------|
| CO2 | 612 | ppm | Good | -- |
|-------------+-------+----------+----------+-------|
| PM2.5 | 7.4 | ug/m3 | Good | -- |
|-------------+-------+----------+----------+-------|
| PM1.0 | 4.2 | ug/m3 | Good | -- |
|-------------+-------+----------+----------+-------|
| PM10 | 11.8 | ug/m3 | Good | -- |
|-------------+-------+----------+----------+-------|
| PM0.3 count | 1234 | count/dL | Elevated | -- |
|-------------+-------+----------+----------+-------|
| TVOC | 83 | index | Good | -- |
|-------------+-------+----------+----------+-------|
| NOx | 2 | index | Moderate | -- |
|-------------+-------+----------+----------+-------|
| Temperature | 22.6 | C | Good | -- |
|-------------+-------+----------+----------+-------|
| Humidity | 48.1 | % | Good | -- |
+-------------+-------+----------+----------+-------+
{
"device_url": "http://192.168.1.201/",
"fetch_duration_ms": 2,
"last_update": null,
"metrics": [
{
"formatted_value": "41",
"key": "aqi",
"label": "AQI",
"status": "good",
"status_label": "Good",
"trend": "unknown",
"unit": "",
"value": 41.0
},
{
"formatted_value": "612",
"key": "co2",
"label": "CO2",
"status": "good",
"status_label": "Good",
"trend": "unknown",
"unit": "ppm",
"value": 612.0
}
]
}
Set one with airgradient-cli config set-theme nord, or
press t in the dashboard to preview them live. An
unknown id falls back to the default rather than erroring.
| Command | What it does |
|---|---|
airgradient-cli | Fetch once and render the metric table |
airgradient-cli -t | Open the live TUI dashboard |
airgradient-cli fetch --json | Emit one JSON document of all metrics |
airgradient-cli themes | List built-in theme ids and labels |
airgradient-cli config path | Print the resolved config file path |
airgradient-cli config show | Print the effective config as JSON |
airgradient-cli config set-url <URL> | Save a device URL (bare hosts become http://) |
airgradient-cli config set-refresh <S> | Save a refresh interval, 5–3600 seconds |
airgradient-cli config set-theme <ID> | Save a TUI theme id |
| Flag | Effect |
|---|---|
--url <URL> | Override the device URL for this run only; not written to config |
--refresh <SECONDS> | Override the TUI refresh interval for this run |
--theme <ID> | Override the theme for this run |
--config <PATH> | Use a different config file |
--json | JSON instead of the table |
--no-color | Strip ANSI color |
-v, --verbose | Add error source chains; repeat for more |
Bindings follow vim, and AstroNvim where it has a convention.
<Space> is the leader and opens a which-key popup
listing what the next key does.
| Key | Action |
|---|---|
<Space> | Which-key popup (leader) |
<Space> then r t c : q | Refresh · themes · config · palette · quit |
r | Refresh now |
+ / - | Lengthen or shorten the refresh interval |
: | Command palette |
t / F2 | Theme picker with live preview |
c | Config editor |
q / Esc / Ctrl-c | Quit |
| Input | Action |
|---|---|
j / k | Move down / up in a list |
gg / G | Jump to first / last |
Ctrl-d / Ctrl-u | Half-page down / up |
Enter / l | Apply, edit, or toggle |
Ctrl-w / Ctrl-u | Delete word / clear line while typing |
| Scroll wheel | Move the cursor through a list |
| Left click | Select the row you clicked |
The CLI reads and writes the same JSON file as
airgradient-desktop, at
$XDG_CONFIG_HOME/airgradient-desktop/config.json
(falling back to ~/.config). Fields it does not know
about are preserved on write.
{
"server_url": "http://192.168.1.201/",
"refresh_interval_secs": 30,
"notifications_enabled": true,
"start_minimized": false,
"theme": "default"
}