Window Watcher compares tado room temperatures with nearby outdoor weather for Untergiesing-Harlaching/Giesing so you can decide whether opening the windows will cool the flat. It records readings to a local JSONL history file, shows hoverable trend charts, and bases the recommendation on the outdoor temperature trend.
pnpm install
pnpm devThe app runs on http://localhost:3000 using the standard TanStack Start Vite dev server with Vite reload/HMR.
Copy .env.example to .env if you want to override the defaults.
Important local files:
data/.tado-token.json: local tado OAuth token, ignored by git (.tado-token.jsonis the legacy fallback)data/temperature-history.jsonl: persistent temperature history, ignored by gitSAMPLE_INTERVAL_MS: optional sampler override; defaults to one minute locally and ten minutes on Railway.PREDICTION_HORIZON_MINUTES: comparison window for open versus closed room predictions; defaults to 90 minutes.MIN_FORECAST_COOLING_WINDOW_MINUTES: how long forecast air must remain useful before the dashboard recommends opening later; defaults to 30 minutes.DWD_OBSERVATION_MAX_AGE_MS,DWD_MINIMUM_STATIONS, andDWD_MAXIMUM_SPREAD_C: safety limits for the direct DWD fallback. Defaults require two observations no older than 90 minutes that agree within 3°C.
Authentication:
- Locally, auth is inactive by default so the dashboard can run without Clerk keys.
- On Railway, Clerk auth is inactive until explicitly enabled with the auth flags and Clerk keys.
- Enable Google as a social connection in Clerk.
- Set
VITE_WINDOW_WATCHER_AUTH=true,WINDOW_WATCHER_AUTH=true,VITE_CLERK_PUBLISHABLE_KEY, andCLERK_SECRET_KEY. - Set
AUTHORIZED_EMAILto the single Google account that may access the dashboard. - The server function refuses to return temperature data unless the signed-in Clerk user has a verified Google OAuth account with that email.
- When the tado authorization expires, the dashboard can start and complete a new tado device login. With Clerk enabled, the configured Google account authorizes the action. Without Clerk, production accepts the token only after tado proves that account belongs to the exact configured
TADO_HOME_ID; the short-lived flow is bound to the initiating browser with a hardened cookie. Tokens stay server-side and are saved directly to the Railway volume. - Set
WINDOW_WATCHER_AUTH=trueonly if you want the server to enforce Clerk auth locally too.
pnpm run check
pnpm run typecheck
pnpm run build
pnpm run startRailway is represented by nixpacks.toml. The service should run as an always-on web service so the dashboard remains available; production sampling defaults to every ten minutes on Railway.
Railway setup:
- Deploy from the public GitHub repo.
- To enable Google auth, add
VITE_WINDOW_WATCHER_AUTH=true,WINDOW_WATCHER_AUTH=true,VITE_CLERK_PUBLISHABLE_KEY,CLERK_SECRET_KEY, andAUTHORIZED_EMAILas Railway variables. Leave the auth flags unset orfalseuntil Clerk keys are configured. - In Clerk, enable Google sign-in and add the Railway production domain to the allowed production URLs/redirect configuration for the Clerk application.
- Add the location/tado variables from
.env.exampleas needed. SetTADO_HOME_IDon Railway so a reconnect can never install credentials for a different household. - Attach a Railway volume and set
RAILWAY_VOLUME_MOUNT_PATHto the mount path. The app storestemperature-history.jsonland.tado-token.jsonbelow that path.TADO_TOKEN_JSONmay bootstrap an empty volume once, but remove it after the volume token is proven; later recovery belongs in the deployed reconnect panel. - Start command is
pnpm run start. Keep App Sleeping off, setBACKGROUND_SAMPLER=false, and use the separate ten-minutePOST /api/samplecron service to record samples. - Keep the sampler command identical to
scripts/railway-sampler-command.txt. It treats typed rate-limit, invalid-authorization, and provider-unavailable responses as completed checks with no fresh value. Transport failures, bad trigger credentials, internal errors, edge errors, malformed success responses, and unexpected bodies still fail the cron.
Railway does not replace app-level auth here. Its "Login with Railway" feature is for letting applications authenticate Railway users and access Railway resources, while this dashboard needs Google sign-in for one private user. Clerk is the cleaner fit and is also one of Railway's documented frontend-auth options.
The app uses generated shadcn UI components for controls, including the chart range buttons. It normally reads Bright Sky's dedicated current DWD observation and Bright Sky/DWD forecast data. If Bright Sky has no current value, it queries DWD Open Data directly and only accepts a fresh consensus from at least two nearby stations; stale, missing, or conflicting readings remain unavailable. Predictions integrate the forecast across the configured horizon and only announce a future cooling window when it remains useful for the configured minimum duration.