尚未检测到更新。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