AWS Builder Center
School Air Alert: Forecasting Delhi's school-day air on AWS

School Air Alert: Forecasting Delhi's school-day air on AWS

How I built a serverless system that warns Delhi schools the evening before a toxic-air day, using Lambda, EventBridge, SNS and SAM, and why it caught 236 of 267 bad school days while a global forecast caught 79.

The problem: a decision made by looking out of the window

Every winter, Delhi's air turns toxic. Stubble burning in Punjab and Haryana, cold nights and still winds push PM2.5 into the Very Poor and Severe range for weeks.
And every school morning, a principal has to decide: does assembly happen outside? Does PE? Break?
Today that decision is usually made on the morning itself often by looking out of the window when children are already on the ground. AQI apps show the air right now, which is too late to plan. Global forecasts exist, but they miss Delhi's worst days.
So I built School Air Alert for the WeMakeDevs × AWS Environmental Hacks (Air track): every evening at 6 PM it forecasts the air during tomorrow's school hours (7 AM–2 PM) for each area of Delhi, and turns it into a plain answer assembly, PE and break: outdoors, shorter, or indoors in English and Hindi.

What it does

  • Pick your school's area and see tomorrow as a school timetable, not an AQI number.
  • Subscribe once and get one email every evening for your area(s).
  • Forward it to your staff or parents' group with a one-tap WhatsApp share.

The data

Four free sources:
  • OpenAQ hourly PM2.5 from CPCB/DPCC government monitors
  • Open-Meteo historical weather, tomorrow's weather forecast, and the CAMS global air-quality forecast (my baseline to beat)
  • NASA FIRMS satellite crop-fire detections over Punjab and Haryana (77,820 of them in two years)
About two years of hourly data for 6 Delhi areas.

The model

For each area and day, at 6 PM, I build ~25 features: pollution so far today, the last 6 hours, yesterday and the last week; tomorrow's school-hours weather (wind, rain, humidity, temperature, boundary-layer height); tonight's weather (calm, shallow nights trap smoke until morning); crop fires and whether the wind blows from Punjab toward Delhi; the CAMS forecast; season and area.
The target is the average PM2.5 between 7 AM and 2 PM the next day. The model is LightGBM — 600 gradient-boosted decision trees. With ~2,300 station-days of tabular data, boosted trees beat deep networks, train in seconds, and are easy to explain.

Testing it honestly

I only had one full winter of data, so a normal train/test split would either train without winter or test without it. Instead I used blocked cross-validation by month: each month is predicted by a model that never saw that month, or the 7 days either side of it.
Last winter (Oct–Jan) there were 267 school days with Very Poor or Severe air (above 120 µg/m³):
Forecast
Bad days warned the evening before
Missed
School Air Alert
236 (88%)
31
"Tomorrow = today"
222
45
CAMS global forecast
79 (30%)
188
86% of School Air Alert's warnings were right. Average error was 19 µg/m³ against 49 for CAMS. One real example: on the evening of 12 Nov 2025 it would have forecast Severe air at three monitors (334, 327, 324); the monitors measured 319, 353 and 342.
Two honest caveats. In testing, "tomorrow's weather" was the weather that actually happened, but the live system only has a forecast adding realistic forecast errors moved the average error from 19.3 to just 19.8. And the fire data didn't measurably improve accuracy with only one stubble season, so I use it to explain why a day is bad, not as a claimed gain.

The AWS architecture

Everything runs serverless and is defined in one AWS SAM template:
  • Amazon EventBridge Scheduler fires every day at 6 PM with  ScheduleExpressionTimezone: Asia/Kolkata , so no UTC math.
  • A forecast Lambda (Python 3.13) pulls live data, builds the features, runs the model, saves  latest.json  and a dated archive to Amazon S3, and publishes alerts.
  • Amazon SNS emails each principal only their chosen areas, using subscription filter policies on a single topic.
  • An API Lambda behind Amazon API Gateway (HTTP API) serves  GET /forecast ,  GET /stations  and  POST /subscribe .
  • The bilingual website is on AWS Amplify Hosting.
  • CloudWatch Logs for every run; least-privilege IAM per function.
One trick I liked: I didn't ship LightGBM to Lambda at all. I exported the 600 trees as JSON and wrote a ~60-line plain-Python tree walker. It matches LightGBM's predictions to 12 decimal places, keeps the package small, and costs almost nothing to run.

What fought back

1. NASA FIRMS silently returned nothing. My fire download came back empty even for peak stubble season. The API caps requests at 5 days; I was asking for 10, and my script swallowed the error. Switching to 5-day chunks returned 77,820 fire detections.
2. Government monitors arriving a day late. On launch day only 2 of 6 areas produced a forecast. Several DPCC monitors were reaching OpenAQ 40 hours late. Waiting wouldn't fix it, so the system now checks freshness: if a monitor is more than 6 hours behind, it switches to the nearest real-time monitor that tracks it well (correlation ≥ 0.6 over 30 days), calibrated to the main monitor's level — and says so on the site. If no good backup exists, it shows "data unavailable" instead of guessing.
3. SNS wouldn't let one email follow two areas. Re-subscribing with a different filter policy fails with "Subscription already exists with different attributes". I changed the API to find the existing subscription and add the area to its filter policy. Then that failed too: CloudWatch Logs showed  GetSubscriptionAttributes  being authorised against the topic ARN, not the subscription ARN. One line in the SAM template fixed it and one  sam deploy  shipped it.
4. Windows quirks. Git Bash rewrote  /aws/lambda/...  into a Windows path (fixed with  MSYS_NO_PATHCONV=1 ), and  aws.exe  output ended lines with  \r , which broke shell scripts until I stripped it.
Every one of these fixes was a small template or code change and a single redeploy which is exactly why I'd use SAM again.

What's next: from warning to cleaning the air

School Air Alert is part of my climate-tech startup, Matiyari Technology, whose product KAAI is a microalgae photobioreactor that cleans air using living algae. The per-area archive in S3 shows where children face the worst air during school hours last winter, 74% of school days in East Delhi were Very Poor or worse, against 41% in South-West Delhi. That data will decide where KAAI units go first, near the schools that need
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article