smooth-app
A collaborative, free and open database of ingredients, nutrition facts and information on food products from around the world
SkyWindow sits on a windowsill at Princeton High School. It reads the sky outside and the air in the room, then tells every classroom whether to open the windows. hackPHS 2026.
HealthJavaScript · HTMLGitHub @MahitPOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Loading the full README. The saved excerpt is shown below.
☁️ SkyWindow: Should I let the sky in? Try it: https://mahitp.github.io/phs-hackathon/ (showcase mode: the live sky over Princeton High School and a simulated room sensor, no Raspberry Pi needed). It's published from main by .github/workflows/pages.yml on every push. On June 7, 2023, wildfire smoke from Canada turned Princeton's sky orange. That day, opening a window was the worst thing you could do. On most other days, opening a window is the best thing you can do for a stuffy room.Read the full README ↗
hackPHS 2026 · Theme: "Into the Skies" · Built by Mahit's Team
Try it: https://mahitp.github.io/phs-hackathon/ (showcase mode: the live sky over Princeton High School and a simulated room sensor, no Raspberry Pi needed). It's published from main by .github/workflows/pages.yml on every push.
On June 7, 2023, wildfire smoke from Canada turned Princeton's sky orange. That day, opening a window was the worst thing you could do. On most other days, opening a window is the best thing you can do for a stuffy room.
SkyWindow is a small device that sits on your windowsill. It watches the sky above you and the air in your room, then gives you one clear answer:
| LCD | Verdict | When |
|---|---|---|
| 🟢 | OPEN THE WINDOW | The sky is cleaner than your room (clean outdoor air, or moderate outdoor air and a stale room) |
| 🟡 | EITHER WAY | Inside and outside are about the same (moderate outdoor air, room not stale) |
| 🔴 | KEEP IT SHUT | Smoke, haze, ozone or particles in the sky (AQI > 100, PM2.5 > 35, or heavy haze) |
| 🟣 | VENTILATE NOW | Your room just spiked (cleaners, markers, cooking, sanitizer) |
Press Read it aloud and it reads the verdict to the classroom: "SkyWindow update: the sky is hazy with pollution, so please keep the windows shut…"
T = exp(−AOD / sin(sun elevation)). That's about 88% on a clear day with the sun high, and about 5–30% under the 2023 smoke depending on the sun angle.SKYWINDOW_AUTO_ANNOUNCE=1 the device announces every time the verdict changes.ml/train.py) on it. The dashboard shows what it thinks is happening in the room. Accuracy is cross-validated by labeling session, so it isn't inflated by near-identical back-to-back samples. The model and labeled data stay on the device (ml/model.joblib, data/skywindow.db); run python ml/train.py on the Pi after labeling.Verdict thresholds have hysteresis (for example, KEEP IT SHUT starts above AQI 100 and only ends below 95), so readings that hover around a boundary don't make the LCD or the announcements flip back and forth.
Honesty note: the Grove Air Quality v1.3 is a VOC gas sensor with relative output. We never call its reading AQI. It becomes a 0–100 "stale index" measured against the room's own clean-air baseline. The outdoor AQI comes from real atmospheric data.
web/ has two pages: a 3D story that explains the project (index.html, the home page) and the live dashboard (app.html).
The story is a scroll-driven 3D film in one continuous flight, from 824 km up to a classroom windowsill. It is built with three.js, GSAP and Lenis (all bundled, so it works offline):
Scroll snaps to each hero pose. Sound is generated in the browser and follows the real wind. Rendering uses a post-processing chain chosen per device: ambient occlusion, god rays, depth of field, bloom, filmic tone mapping, anti-aliasing and film grain. scripts/fetch_story_assets.sh re-downloads and compresses the imagery, star catalogue and classroom models. The story adapts to the device (lighter effects on phones and slower GPUs), respects reduced-motion settings, and becomes a plain text article if WebGL isn't available. scripts/bake_story_data.py re-creates the map and smoke data files.
The live dashboard (app.html, reached through the dive from the story):
Map controls: every map view has the same small control in the corner: recenter, satellite/map and NASA fires. 3. Forecast — "When can PHS open its windows?" An hour-by-hour strip for the next 24 hours: weather icon, temperature, AQI, rain chance and a window verdict per hour (open, either, shut for bad air, shut for rain). It also highlights the best daytime window to air out and shows sunrise, sunset, max UV, clouds and ozone. On the device it also charts the last hour of the room vs the sky from the Pi's history. Hourly rules: shut if the forecast AQI is over 100, PM2.5 is over 35 or there's heavy haze; shut if rain is 60%+ likely; open if AQI is 50 or less and it's dry. 4. Earth (global context): city dots on the 3D globe in EPA colors, a breakdown of how many of 43 cities are Good, Moderate, Unhealthy and so on, the median AQI, and region jumps, with each city's name and AQI next to its dot. Tap anywhere for a side-by-side comparison with PHS (AQI, PM2.5, haze, weather, temperature, humidity, wind, local time). Earth never shows the classroom sensor or a windows verdict. Those belong to PHS Campus, and clicks more than 25 km from PHS on the campus map are sent to Earth.
The June 7, 2023 smoke day and how SkyWindow works are told by the story, so the dashboard keeps to these four views.
Real alerts:
Fires (NASA FIRMS): the Pi downloads the public VIIRS active-fire file every hour and keeps detections within 300 km of PHS, dropping low-confidence points. It works out which ones are upwind from the live wind direction. These detections include small crop and brush burns and some industrial heat sources, so the site reports their size (fire radiative power) and only warns when the upwind fire power is significant.
The site runs in one of two modes:
http://<pi-ip>:8000 (story) or http://<pi-ip>:8000/app.html (dashboard). Both the story and the dashboard read the Pi's /api/now, so the Pi's verdict, room reading, forecast and fires show everywhere. The status chip says which source is live: DEVICE LIVE (Raspberry Pi sensors), DEVICE · SENSOR OFFLINE (Pi running but the Grove HAT/sensor isn't answering, so the verdict uses outside air only), DEVICE · BACKUP FEED (the backup backend on port 8001) or DEVICE · DEV MODE (laptop with mock sensors). The page must be opened from the server's own address: a copy of web/ served by anything else can't reach the Pi and runs in showcase mode.web/ from any static host, or run python -m http.server -d web. The page fetches the sky straight from Open-Meteo and simulates the room sensor, so judges can try it on their own phones.Pi backend — server/, device/ (port 8000) | Backup backend — simulator/ (port 8001) | |
|---|---|---|
| Indoor air | The Pi's Grove sensors only | Scenario-driven classroom (simulator/scenarios.py) |
| If a sensor fails | Shows SENSOR OFFLINE and decides on outside air only. It never substitutes made-up numbers, and it reconnects automatically | n/a |
| Outside air, weather, NASA fires | Real | The same real data, unless the chosen scenario overrides it |
| LCD / GPIO | Real | Never touched |
| Database | data/skywindow.db (real readings only) | data/sim.db |
| Scenario controls | None | Operator page at /sim |
| Dashboard label for the room reading | RASPBERRY PI / LIVE (or SENSOR OFFLINE) | BACKUP FEED |
simulator/ (a test enforces this). The backup runs as its own process and wraps its own copy of the server code, so nothing it does can reach the Pi backend's readings, verdict or database.SKYWINDOW_MOCK=1 is set explicitly. scripts/dev.py sets it for laptop development, and the dashboard then says DEV MODE.http://<pi>:8001/sim, not part of the dashboard):
Grove sensors ──► device/hw.py ─┐
├─► server/app.py (FastAPI, 1 Hz loop) ──► device/lcd.py (verdict + color)
Open-Meteo ────► server/sky.py ─┤ │ └─► web/ dashboard (phone, any browser)
2023 replay ───► server/replay.py┘ ├─► server/decide.py (verdict engine)
├─► server/clarity.py (sun position, clear-sky, Beer-Lambert)
├─► server/report.py (Gemini classroom announcement)
├─► server/voice.py (ElevenLabs TTS)
└─► server/store.py (SQLite history + labels) ──► ml/train.py
On the Raspberry Pi:
git clone <this repo> ~/skywindow && cd ~/skywindow
bash scripts/setup_pi.sh # enables I2C, installs deps + grove.py, starts the service on boot
nano .env # optional: GEMINI_API_KEY, ELEVENLABS_API_KEY
sudo systemctl restart skywindow
Then open http://<pi-ip>:8000/app.html (the dashboard) or http://<pi-ip>:8000 (the story page) on any phone on the same network. The site's libraries, fonts and Earth textures are bundled in web/vendor/, so it renders even when the phone has no internet (for example on a Pi hotspot); only the live sky data needs a connection.
Hardware checks:
python device/hw.py # live sensor values
python device/lcd.py --test # cycles the 4 verdict colours
On a laptop (no hardware, simulated sensors):
python -m venv .venv
.venv/bin/pip install -r requirements.txt # macOS / Linux (Windows: .venv\Scripts\pip)
.venv/bin/python scripts/dev.py # http://localhost:8000 - use the "Mock" buttons under Setup
Tests: .venv/bin/pip install -r requirements-dev.txt && .venv/bin/python -m pytest
| Method | Path | What it does |
|---|---|---|
| GET | /api/now | Full live state: verdict, indoor, sky, clarity, replay |
| GET | /api/history?minutes=60 | Logged readings |
| POST | /api/report {"speak": true} | Generate the spoken announcement (+ ElevenLabs audio). Repeat requests within 15 s reuse it |
| POST | /api/replay {"on": true} | Start or stop the Smoke Day replay |
| POST | /api/calibrate {"what": "air"|"light"} | Set the clean-air baseline, or calibrate the light sensor to the sky |
| POST | /api/label {"label": "chemical"} | Record a labeled sample for the classifier |
If SKYWINDOW_TOKEN is set in .env, every POST needs an X-SkyWindow-Token header. Open the dashboard once as http://<pi-ip>:8000/app.html?token=<token> and the phone remembers it. Reads stay open.
Sky data: Open-Meteo (CC BY 4.0), CAMS air-quality and ERA5 reanalysis. The dashboard's 3D Earth is adapted from TerraShift's EarthGlobe (MIT License, Copyright (c) 2026 TerraShift), with NASA Blue Marble imagery from the three.js example textures. Story imagery: NASA Earth Observatory (Blue Marble Next Generation, Black Marble 2016, Blue Marble clouds, GEBCO/BMNG topography) and NASA/Goddard Scientific Visualization Studio (Deep Star Maps 2020). Star catalogue: HYG database v4.1 (CC BY-SA 4.0). Satellite model: NASA 3D Resources. Classroom models, textures and lighting: Poly Haven (CC0). Map data: © OpenStreetMap contributors (ODbL). Built in 24 hours at hackPHS 2026.
simulator/room.pysetup_pi.sh installs both services. On a laptop, run python scripts/dev.py (8000) and python scripts/sim.py (8001).