尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證Submission for Congressional App
翻譯準備中
正在載入完整 README。
檢視完整 README ↗School districts decide heat-related early dismissals from the outdoor forecast. Individual classrooms are never measured, and a second-floor southwest room with no AC can be far hotter than the outdoor reading the decision rests on.
Thermion predicts per-room conditions from building physics, sharpens those predictions with sparse human reports through a per-room Kalman filter, and recommends which classes to move.
A heat-wave scenario toggle (dashboard and plan) runs the same physics on a clearly labeled synthetic June heat wave, so the model can be explored outside heat season. It is never mixed with live data.
Requires Node 20 or newer.
npm install
npm run dev # http://localhost:3000
npm test # vitest: physics, filter, optimizer, NWS client, DB
npm run build # production build (type-checks)
The SQLite database is created at ./data/thermion.db on first request. Migrations run automatically, and the seed adds one school (Morris Hills High School), 16 rooms and 14 classes. No reports are seeded.
Environment variables (all optional):
| Variable | Purpose |
|---|---|
NWS_USER_AGENT | User-Agent sent to api.weather.gov. NWS asks for an app name plus contact info; set this in production. |
THERMION_DB | Path to the SQLite file (default ./data/thermion.db, or /tmp/thermion.db on Vercel). |
The only external network dependency is api.weather.gov. There is no auth.
npx vercel deploy --prod
Vercel's filesystem is read-only apart from /tmp, so the database lives in /tmp/thermion.db there. It is ephemeral per serverless instance: reports survive while an instance stays warm, but a cold start re-seeds an empty database. That is fine for a demo. A production deployment should mount a persistent volume (any Node host) or point THERMION_DB at durable storage.
api.weather.gov
│ /points → forecastHourly (30-min cache, Result<…>, never throws)
▼
┌──────────────────────── lib/nws.ts ─────────────────────────┐
│ hourly periods (temp, RH, sky cover from NWS sky wording) │
└───────────────┬──────────────────────────────────────────────┘
│ logged hourly into weather_hours (past hours stay available)
▼
lib/weather.ts ── live │ stale (logged) │ climatology fallback → banner
│
▼ PURE MODULES (no I/O, unit-tested)
┌────────────────────────────────────────────────────────────────────┐
│ solar.ts NOAA solar position → elevation, azimuth │
│ irradiance.ts Kasten-Young AM, Meinel beam, diffuse, cos θ on a │
│ vertical window, cloud factor → watts into room │
│ thermal.ts dT/dt = invRC·(T_drive − T) + alpha·Q (Euler, 5 min)│
│ kalman.ts EKF on [T, invRC, alpha], χ² gating, ±σ tracks │
│ heatindex.ts NWS Rothfusz + adjustments │
│ thresholds.ts 82 advisory / 88 unusable │
│ hungarian.ts Kuhn-Munkres O(n³) │
│ reassign.ts cost matrix, feasibility, padding, plan │
└────────────────────────────────────────────────────────────────────┘
│ ▲
▼ │
lib/roomModel.ts recordReport(): insert report → propagate → update
│ → room_state + filter_log (one transaction)
│ buildForecast(): per-room tracks with ±σ, re-anchored at
│ each accepted report
▼
app/dashboard app/report (server action) app/plan (+ /plan/export CSV)
│
▼
SQLite (better-sqlite3): schools, rooms, reports, room_state, classes,
weather_hours, filter_log (PRAGMA user_version migrations)
/report posts to a server action, which validates the input (temp 40–130 °F).room_state, and append a filter_log row (accepted or rejected, with NIS and the posterior).State x = [T, invRC, alpha]. The process model is one Euler step of the thermal model. invRC and alpha follow random walks, so the filter learns each room's parameters. The Jacobian is derived analytically in lib/kalman.ts:
⎡ 1 − Δt·k Δt·(T_d − T) Δt·Q ⎤
F = ⎢ 0 1 0 ⎥
⎣ 0 0 1 ⎦
A report observes T directly (H = [1, 0, 0]). Measurement noise is 1.0 °F (1σ) for teachers and staff and 2.0 °F for students. Reports with normalized innovation squared above χ²₁(0.99) = 6.635 are rejected and logged. A rejected reading is accepted later only if a second report within 12 hours agrees with it; that is treated as evidence the model, not the reporters, is wrong.
In a synthetic study (5 rooms × 6 noise seeds, 20 teacher reports each, 2.5 h apart), the learned invRC landed within 20% of truth in 21 of 30 runs, with a normalized-error RMS of 1.4: the filter is mildly overconfident, as EKFs on bilinear models tend to be. The unit test checks the spec case: a synthetic room converges within 20% of its true invRC after 20 observations, and a single 130 °F garbage report is rejected and leaves the estimate unchanged.
For a period: rows are the classes meeting then, columns are rooms. cost = enrollment · max(0, peakHI − 82) + movePenalty·[room ≠ assigned]. Pairs that break capacity or lab requirements are infeasible. The matrix is padded to square (dummy classes cost 0, dummy rooms are infeasible for real classes) and infeasible pairs are encoded as a large finite cost. If the optimal solution uses one, the page says explicitly that no feasible assignment exists, and why. Exposure is reported as student-degree-hours above 82 °F heat index. An option plans against mean + 1σ instead of the mean.
Every modeling assumption, stated plainly:
Thermal model
Solar and sky
Weather
Humidity and heat index
Kalman filter
Schedule and optimizer
Rooms created from /report default to building "Main", 6 m² of windows, capacity 25 and not a lab. Edit them in the database for better predictions.
Deployment: on Vercel the SQLite file lives in /tmp and is lost on cold starts (see above).
app/
dashboard/page.tsx hero, solar sweep, predictions, rooms, filter log
report/ page, client form, server action
plan/ page + export/route.ts (CSV)
components/ SolarSweep, PredictionChart, OutdoorChart, UI bits
lib/
nws.ts heatindex.ts thresholds.ts humidity.ts
solar.ts irradiance.ts thermal.ts kalman.ts
hungarian.ts reassign.ts schedule.ts scenario.ts
db.ts repo.ts weather.ts weatherSeries.ts roomModel.ts
dashboard.ts planService.ts prediction.ts validate.ts time.ts types.ts
tests/ vitest suites for every module above