What it does
This bot watches PurpleAir sensors for the locations people subscribe to and sends a Telegram message the moment the air quality category changes — good → moderate, moderate → unhealthy, and so on, in either direction. No app besides Telegram, no account, no cost.
Get started in under a minute:
- Open the bot and tap Start.
- Send
/subscribe leadville-co— Leadville, CO ships out of the box. - Want a different town?
/addlocation boulder-cofinds the nearest active sensor automatically.
You can subscribe to more than one location, check /status any time, and
/unsubscribe whenever you want. Full command reference (including how to point it at a
specific sensor by hand, and how to flag a sensor that looks wrong) is under
Using the bot below.
Why the numbers may differ from PurpleAir's own map
If you check a sensor on PurpleAir's map and compare it to what this bot reports, don't be surprised if the numbers don't match — often by a meaningful margin. That's expected, not a bug. Here's why.
PurpleAir sensors are low-cost laser particle counters. They're great at detecting relative change in real time, but on their own they systematically overestimate true PM2.5 concentration compared to EPA reference-grade monitors — and the size of that overestimation gets worse in dry air and at high altitude, which describes plenty of the mountain towns this bot was built for. PurpleAir's own map, by default, shows AQI computed straight from the raw sensor reading, with no adjustment for this known bias.
This bot instead applies the correction formula published by Barkjohn, Norris & Clements (2021) — developed specifically for PurpleAir sensors, using co-located reference monitors, and the correction the US EPA itself recommends and uses on its AirNow Fire and Smoke Map. In plain terms: it takes the average of the sensor's two PM2.5 channels plus the local humidity and temperature, and produces a value closer to what a reference-grade monitor would read at that spot.
The formula
That corrected PM2.5 value then goes through the 2024-revised EPA breakpoint table (below) to get the final AQI this bot reports — which is why every AQI value it sends is labeled (EPA-corrected).
Try it yourself
This chart plots the exact formula above: raw PurpleAir AQI (uncorrected) vs. the EPA-corrected AQI this bot actually reports, across a range of PM2.5 readings. Drag the sliders — notice how the gap between the two lines grows in drier air, which is exactly the mismatch people notice when comparing this bot to PurpleAir's map in a place like Leadville, CO.
A real example: Leadville, CO
We pulled live data on a dry summer afternoon from the sensor this bot uses in Leadville, plus three others within a couple hundred meters of it (conditions varied slightly sensor to sensor, so each row uses its own actual humidity/temperature reading):
| Sensor | Raw PM2.5 (µg/m³) | RH | Temp | Raw / uncorrected AQI | EPA-corrected AQI |
|---|---|---|---|---|---|
| Sloan_flex-f877 (used by this bot) | 38.0 | 11% | 83°F | 107 | 79 |
| Sloan_flex-d54e | 38.1 | 10% | 85°F | 107 | 79 |
| East 4th | 35.0 | 10% | 80°F | 99 | 76 |
| Sloan_zen-2 | 33.8 | 12% | 92°F | 97 | 74 |
All four sensors agree closely with each other once corrected. The ~20-30 point gap between each sensor's raw and corrected AQI isn't sensor disagreement — it's the same known overestimation bias, showing up consistently across every nearby sensor, in exactly the dry/high-altitude conditions where it's most pronounced.
AQI levels this bot alerts on
You get a message any time a subscribed location crosses one of these boundaries, in either direction:
| Level | AQI range | What it means |
|---|---|---|
| 🟢 Good | 0–50 | Air quality is fine for everyone. |
| 🟡 Moderate | 51–100 | Fine for most people; take it easier outside if you have asthma or another breathing condition. |
| 🟠Unhealthy for Sensitive Groups | 101–150 | Kids, older adults, and anyone with heart or lung conditions should limit time outdoors. |
| 🔴 Unhealthy | 151–200 | Everyone may start to notice effects. Limit outdoor activity. |
| 🟣 Very Unhealthy | 201–300 | Health alert — avoid outdoor activity if you can. |
| 🟤 Hazardous | 301+ | Emergency conditions — stay indoors. |
More detail on any level: airnow.gov/aqi/aqi-basics
Sensor health checks
Individual PurpleAir sensors can go wrong in more than one way, and this bot checks for three of them on every scheduled poll, automatically switching a location to a nearby healthy sensor whenever it confirms one:
Diverging channels. Each sensor has two independent PM2.5 sensors that normally agree closely. Occasionally one fails (dust, insects, moisture) and reports wildly different numbers from the other — this bot checks for that disagreement before trusting a reading.
Flatlined. A sensor can keep reporting right on schedule — so it never looks offline — while its value has effectively stopped moving for hours. Confirmed against nearby sensors' current reading first, so a genuinely calm, stable-weather day doesn't get mistaken for a stuck sensor.
Erratic. The opposite problem — a sensor's own reading swings wildly while sensors a few meters away stay calm the whole time. Confirming this pulls each nearby sensor's own recent history from PurpleAir directly (not just a single live snapshot, which an erratic sensor could pass or fail depending on the exact moment it's checked), and only acts if several of them were genuinely stable over the same window — a real, shared event that made everything swing doesn't trigger a switch.
Subscribers can also flag a location directly with /reportissue <slug> — the bot
re-runs all of these checks immediately and either fixes it on the spot or logs it for review, no
manual intervention required to file or triage a report.
A successful switch happens quietly in the background — the bot just keeps using the healthy sensor
going forward, the same as it always has. (If you check /status or file a
/reportissue right around when it happens, it'll mention the switch — but there's no
proactive alert for it, since routine self-healing doesn't need anyone's attention.) If a sensor is
confirmed bad and there's genuinely no healthy replacement nearby, the bot says so rather than
silently reporting a broken reading.
Using the bot
Everything below happens by DMing the bot on Telegram — no account, no website, no cost. If you don't have Telegram yet, it's a free app (App Store, Google Play, or web.telegram.org with no download at all) — sign-up takes about a minute with just a phone number.
| Command | What it does |
|---|---|
/start | Welcome message and a quick command list. |
/locations | List every location currently tracked. |
/subscribe <slug> | Get alerts for a location, e.g. /subscribe leadville-co. |
/addlocation <slug> | Register a new town and subscribe to it in one step — finds the nearest active PurpleAir sensor automatically, e.g. /addlocation boulder-co. |
/addlocation <slug> <sensor_index> <City, ST> | Same, but pointing at a specific sensor by hand — the fallback for when auto-discovery can't find anything (small town, unusual name). |
/removelocation <slug> | Remove a location — only the chat that added it can. |
/unsubscribe <slug> | Stop alerts for a location (the location itself stays available for others). |
/status | Show every location you're subscribed to and its current AQI. |
/reportissue <slug> | Think a location's sensor looks wrong? Flag it — see Sensor health checks above. |
/documentation | Links back to this page. |
A slug is always lowercase and hyphenated, ending in the 2-letter state (or Canadian
province) code — boulder-co, salt-lake-city-ut. The bot reads the city and
state straight from it, so there's nothing else to fill in for the common case.
You can subscribe to as many locations as you want from one chat — there's no one-location limit. Privacy-wise, the bot stores only your Telegram chat ID and which location(s) you've subscribed to — no name, phone number, or other personal information — and unsubscribing stops messages immediately.
Sources & further reading
- Barkjohn, K. K., Gantt, B., & Clements, A. L. (2021), Atmospheric Measurement Techniques 14, 4617–4637 The correction formula this bot uses, developed and validated against reference-grade monitors specifically for PurpleAir sensors.
- US EPA — PM NAAQS AQI Fact Sheet (2024 revision) The official AQI breakpoint table used to convert corrected PM2.5 into the 0–500 AQI scale.
- AirNow — AQI Basics Plain-language explanation of what each AQI level means for your health.
- PurpleAir API documentation The sensor data source this bot polls every 10 minutes.
- PurpleAir Map Browse sensors directly, including the raw (uncorrected) readings this page compares against.