ClassAir: Verifying Classroom Air Purifiers When a New AWS Account Starts You at Zero
I built an ML-powered tool to verify Delhi's school air purifiers are actually working, then spent half the hackathon fighting Lambda's Linux binaries, mixing up AWS Builder ID with a real AWS account, and discovering Bedrock gives new accounts a 0 token-per-minute quota. Here's what we built and what fought back.
The Problem
Every winter, when Delhi's air quality hits GRAP Stage III or IV, primary classrooms (up to Class V) shut down, sometimes for 15 days at a stretch. To keep children in school through these periods, the Delhi government is installing air purifiers in 10,000 classrooms in its first phase, out of 38,000 total.
But installing a purifier isn't the same as verifying it's working. Filters clog based on actual usage, not a fixed schedule. Doors opening during class let outdoor pollution straight back in. There was no system to check whether a purifier was actually protecting a room, or to tell staff what to fix when it wasn't.
What We Built
ClassAir takes PM2.5 sensor readings over a 30-minute window and estimates a classroom's air changes per hour (ACH) against CEEW's recommended target of 5. If the room falls short, it estimates whether a clogged filter or an open door is the bigger cause, and generates a plain-language report explaining what's wrong and what to do about it.
Since we didn't have physical sensor hardware to calibrate within the hackathon timeframe, we built a physics-based simulator instead: it generates synthetic PM2.5 decay curves for classrooms under varying filter clog %, door-open %, room size, purifier rating, and sensor noise. We trained Random Forest models on 500 of these simulated scenarios to predict ACH and door-open % directly, and derived filter clog % algebraically from those two, since the relationship is physically known rather than needing to be learned from scratch. We say this openly in our repo: the clog % estimate is our least certain output, with roughly 12.6 percentage points of average error, and a real deployment would need a calibration pass against actual hardware.
The Stack
- Backend: Python, Flask, scikit-learn (Random Forest regressors)
- Frontend: plain HTML/CSS/JavaScript, with a dark/light mode toggle and a built-in manual for first-time users
- AI reporting: originally Amazon Bedrock (Converse API, Amazon Nova), later Google Gemini
- Hosting: AWS EC2
What Fought Back
Lambda's Linux binaries, built from Windows. Our first deployment attempt was AWS Lambda. scikit-learn and its dependencies need to be compiled for the exact OS they'll run on, and packaging Linux-compatible wheels from a Windows machine kept failing — pip tried to build from source and needed a C compiler we didn't have. We eventually gave up fighting cross-compilation and moved to EC2, where we could install every dependency directly on the actual Linux machine the app would run on. No mismatch, no packaging step at all.
AWS Builder ID is not an AWS account. This one cost real time. The hackathon requires an AWS Builder Center profile with university enrollment verified — and it's easy to assume that's the same login you use to access the Console and deploy anything. It isn't. A Builder ID is a lightweight identity for learning content and labs; it cannot obtain IAM credentials to access the Console, CLI, or SDKs. You need a separate, full AWS account (the one tied to billing and the free tier) to actually build anything. We didn't realize this until we tried to find Bedrock on Builder Center and it simply wasn't there.
A new AWS account starts Bedrock at a quota of zero. Once we had a real AWS account and got EC2 running, we built our AI report-generation layer entirely around Amazon Bedrock, using the Converse API with Amazon Nova. During testing, every call failed with a
ThrottlingException . The AWS Bedrock Quotas dashboard confirmed why: every model showed 0 tokens per minute and 0 requests per minute for our account, across every Nova variant, pending AWS's own account review process. There's no clear warning about this anywhere obvious — you only discover it when your first real call fails.Rather than wait on a review timeline we had no control over, mid-hackathon, we made a call: keep the Bedrock integration code in the repository as-is (it's a drop-in swap once quota is approved), and rebuild the exact same report-generation interface using Google's Gemini API instead. We also added a rule-based fallback report generator, so the app never breaks even if the AI call fails or is rate-limited for any reason — AI-generated text when it's available, a clear and honest templated report when it's not.
What We'd Do With More Time
Calibrate against real PM2.5/CO2 sensor hardware instead of simulated data. Expand the training set and test the model's behavior at the edges of its input range more rigorously — we found during testing that the model struggles to produce very low door-open estimates for high-CADR purifiers, a real limitation we documented rather than hid. And, if Bedrock's quota clears, switch the live report generation back, since it was the integration we originally designed around.
Built solo for WeMakeDevs Environmental Hacks (Bharat Builds Tour), Air track. Repo: https://github.com/sumitnathani/classair-sim-WeMakeDevs-Env\_Hacks\ , Demo video:* https://youtu.be/r5gmLyl1eug?si=F2P3TY2udSCOyFSn\*.\
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article