RadarB is a focused, scan‑friendly weather operations board for the Cleveland/Lake Erie corridor. It fuses live station data, ODOT sensors, camera feeds, radar tiles, and DWML/NDFD forecast grids into a single, modern dashboard optimized for quick decisions.
- Current conditions + wind card (Ambient Weather: temp, feels‑like, wind/gust/max gust)
- Compact 5‑day strip with Today integrated (today high/low + current PWS data, days 1–4 to the right)
- Sun‑track bar (midnight → midnight) with dawn/dusk + sunrise/sunset hatches and cloud‑aware sky gradient
- Sun‑track countdown to the next light phase (dawn/sunrise/sunset/dusk)
- Hourly forecast strip (DWML):
- Temperature + feels‑like (wind chill / heat index overlays when applicable)
- Wind + gusts
- Precip potential + sky cover
- Weather type bands (legend only shows active precip types)
- Accumulated snowfall line (NDFD time‑series, with GFS tail extension)
- Accumulated rainfall line
- ODOT sensors and camera tiles (OHGO)
- Alerts + advisories panel (DWML hazards)
- School closings (Lakewood City Schools only; shown only when a closure exists)
- OHGO incidents (nearby traffic incidents; cached)
- Image grids: GOES16 satellite, NWS/WJW/CLE radar, AccuWeather mosaic (proxied), GLERL ice, NWS storm total snow, CPC 8–14 day outlooks, and Pivotal maps
- Ambient Weather (station data)
- NWS DWML (digital forecast grids)
- NDFD XML time‑series (snow accumulation)
- OHGO (ODOT cameras + sensors)
- Sunrise‑Sunset API (civil twilight + sunrise/sunset)
- Spectrum News closings feed (school closings)
- CPC 8–14 day outlooks (temp/precip)
- AccuWeather mosaic (proxied via Cloud Function)
- Pivotal Weather (model imagery)
- Open‑Meteo (GFS point forecast for snow tail extension)
- Cloud Functions (2nd gen) target Node.js 24 via
functions/package.json.
public/— frontend HTML/CSS/JSfunctions/— Firebase Cloud Functions (CORS proxies, secrets)docs/— implementation notes (seedocs/sun-track-line.md)
- Lint:
npm run lint - Format:
npm run format
Primary endpoints consumed by the dashboard (see public/scripts/config.js):
getAmbientWeatherDatav2getCameraDatav2getSensorDatav2getOhgoIncidentsv1getSchoolClosingsv1getFlightDelaysv2getDwmlForecastv1getNdfdSnowv1getTwilightTimesv1getRadarProxyv1grabPivotalHRRR6hQPFv2
Other functions exist but are currently unused by the UI:
getWeatherDatav2(OpenWeather One Call)getTomorrowMinutelyPrecipv1(Tomorrow.io minutely precip cache)getGroundStopInfov2,getCityNamev2
Functions read secrets from Google Secret Manager:
openweathermap(OpenWeather)tomorrow-io-api-key(Tomorrow.io)ambient-weather-application-key,ambient-weather-api-keyohgo-apiaeroapigoogle-maps-apivertex(Gemini fallback for closings parsing)
- Serve
public/with Firebase hosting or any static server. - Use Firebase emulators for Functions if you need local API testing.
- Ports (from
firebase.json): Functions5005, Hosting5400, Emulator UI enabled.
- Ports (from
- Hosting:
firebase deploy --only hosting
- Functions:
firebase deploy --only functions
- The NDFD snow feed is proxied via
getNdfdSnowv1to avoid browser CORS. - DWML hazards are de‑duplicated and displayed as alert cards.
- Closings are hidden unless Lakewood City Schools is explicitly listed as closed/remote/virtual.
- Closings lookups are skipped between April 15 and December 1 (seasonal gate).
- AccuWeather mosaic is served through
getRadarProxyv1to avoid ORB/CORS issues. - Firestore is not used; rules deny all reads/writes by default.
- Sun‑track sky uses exact civil‑twilight boundaries (dawn/sunrise/sunset/dusk) with cloud‑aware color stops.
- Snow accumulation tail (days 4–7) is extended using a scheduled GFS point forecast job via Open‑Meteo.
- Accumulation charts are shown only when their precip types are present (>0).
RadarB uses layered caching to keep the dashboard fast without losing freshness. There are three levels:
-
Server‑side (Cloud Functions, in‑memory)
- Caches reset on cold start or new instances.
- Current TTLs:
getDwmlForecastv1: 30 min + ETag revalidationgetNdfdSnowv1: 1 hourgetTwilightTimesv1: 6 hoursgetOhgoIncidentsv1: 5 min (per map bounds)getSchoolClosingsv1: 6 hoursgetTomorrowMinutelyPrecipv1: 4 min (shared Firestore cache, prewarmed every 3 min)
-
Client‑side (localStorage)
forecastData: JSON snapshot for the 5‑day strip (used immediately on load)- Legacy cleanup: the old
forecastHtml/forecastHtmlTimekeys are removed on startup dwmlForecast: raw DWML XML (used immediately on load)twilightTimes: dawn/dusk/sunrise/sunset (6 hours)incidentsCache: OHGO incidents (5 min)closingsCache: school closings (10 min)
Deferred media loading
- Large image tiles (radar/satellite/Pivotal) are loaded after initial paint via
data-src+requestIdleCallback. - Panels use a
.panel-loadingskeleton and remove it after image load.
Image refresh cadence
- OHGO camera tiles: ~6s
- Radar tiles (CLE/WJW/AccuWeather): 3 minutes
- Slow tiles (GOES16, GLERL, storm total snow, CPC, Pivotal): 1 hour
How to control caching
- Server TTLs live in the handlers under
functions/lib/handlers/. - Client TTLs live alongside each module (see
public/scripts/modules/). - To bypass caches during debugging, clear localStorage keys or add a cache‑busting query param to the function URL.
RadarB extends snow accumulation beyond the NDFD/DWML window using a scheduled GFS point‑forecast job.
- Job code:
jobs/gfs_snow_tail/ - Output:
gs://radarb-forecast-358874041676/snow_tail.json(public, cached 30m) - Schedule: every 4 hours 6:30–22:30 ET during Nov–May
The frontend blends NDFD/DWML accumulation first, then appends the GFS tail.
RadarB can proxy a shared Tomorrow.io minutely precipitation forecast for 41.48,-81.82 using:
- Endpoint:
getTomorrowMinutelyPrecipv1 - Upstream fields:
precipitationIntensity,precipitationProbability - Cache store: Firestore document
weatherCache/tomorrowMinutelyPrecipV1 - Refresh cadence: every 3 minutes from 6:00 AM ET through 11:57 PM ET (
*/3 6-23 * * *)
The endpoint serves the cached payload first and only refetches Tomorrow.io when the cache is missing or older than 4 minutes.
- Add DWML hazard time‑layout parsing to display effective windows.
- Consider adding observed cloud cover (METAR/GOES) for earlier‑day sun‑track segments.