airq — CLI Air Quality Checker
Check air quality for any city from the terminal. Sensors primary, model as reference. Event detection, pollution fronts, source attribution. No API keys needed.
Installation
First check if airq is already installed:
airq --version
If not installed, detect the user's platform:
macOS (Homebrew)
brew tap fortunto2/tap && brew install airq
Linux (prebuilt binary)
curl -LO https://github.com/fortunto2/airq/releases/latest/download/airq-linux-x86_64.tar.gz
tar xzf airq-linux-x86_64.tar.gz
sudo mv airq /usr/local/bin/
Any platform (Rust/cargo)
cargo install airq
Configuration
airq init --city <city-name>
Config: ~/.config/airq/config.toml
default_city = "berlin"
cities = ["berlin", "tokyo", "istanbul"]
Commands
Current air quality
airq # default city
airq --city tokyo # any city
airq --city tokyo --full # + pollen, earthquakes, geomagnetic
airq --lat 55.75 --lon 37.62 # coordinates
Output: PM2.5, PM10, CO, NO2, O3, SO2, UV, humidity, pressure, wind, comfort (0-100).
Data merge: Sensor.Community (real sensors) primary. Open-Meteo (CAMS model) as fallback. Dynamic weight by divergence — if model differs >5x from sensors, model is ignored.
Comfort index (14 signals, sigmoid/gaussian)
airq comfort --city berlin
Signals: air, temperature, wind, sea, UV, earthquake, fire, pollen, pressure, geomagnetic, humidity, daylight, noise, moon. All normalized with smooth sigmoid curves.
History
airq history --city istanbul --days 7
Rank cities
airq top --country turkey
airq top --country russia --count 10
10,000+ cities built-in.
Pollution front detection
airq front --city hamburg --radius 150 --days 3
Z-score spikes → cross-correlation → haversine speed/direction. Dual-source: model + sensors.
Source attribution (blame)
airq blame --city moscow --radius 20 --days 7
CPF (Conditional Probability Function): wind direction × PM2.5 threshold. Auto-discovers factories/plants from OpenStreetMap.
Event detection
cargo run --example detect_events
Three-layer detection:
- EWMA baseline — adaptive threshold per sensor (α=0.1)
- Concordance — 2+ sensors confirm = event (not noise)
- Directional — anomaly sensors in same wind sector = point source
Dual-channel PM2.5 + PM10. Source classification by ratio:
- ratio >4 → dust/sand storm
- ratio 2.5-4 → construction dust
- ratio <1.5, PM2.5 >55 → smoke/wildfire
- ratio ~1, PM2.5 >35 → combustion/traffic
Serve (headless monitoring daemon)
airq serve --city gazipasha --radius 15 --port 8080
airq serve --city moscow --city istanbul --interval 600
Runs a background daemon: polls Sensor.Community every N seconds, stores readings in SQLite, runs event detection, exposes REST API with Swagger UI at /swagger-ui/.
API endpoints: /api/status, /api/readings, /api/sensors, /api/events, /api/cities.
Dashboard (desktop app)
cargo install airq-dashboard
# or from source:
cargo run -p airq-dashboard
Dioxus 0.7 desktop app (Air Signal). Same collector + detector as serve, but with a native UI. Phone-first layout (480x800). Shows live readings, sensor map, events timeline.
Both serve and dashboard share the same SQLite DB (~/.local/share/airq/airq.db).
HTML/PDF report
airq report --city hamburg --radius 150 --pdf
Leaflet map + heatmap + front arrows + CPF table + source markers.
JSON output
airq --city tokyo --json
airq top --country usa --json
Core library (airq-core)
Use in your own project:
airq-core = "2.0"
4 modules:
matrix— SignalMatrix (macro-driven, 14 signals, time-series, ML vector 44-dim)event— EWMA + concordance + directional event detectionmerge— sensor/model dynamic weightingsignal— sigmoid/gaussian normalize functions
WASM-ready: wasm-pack build --target web --features wasm --no-default-features
130 tests.
How it works
Sensor.Community (real sensors, ground truth) → primary. Open-Meteo CAMS model → fallback with dynamic weight. When sources diverge (model says 130, sensors say 7), sensors win.