{"id":49490106,"url":"https://github.com/consigcody94/owl-status-apps-script","last_synced_at":"2026-05-01T04:31:12.098Z","repository":{"id":354871966,"uuid":"1225349535","full_name":"consigcody94/owl-status-apps-script","owner":"consigcody94","description":"Single-file Google Apps Script for ASOS network monitoring · Live API METARs · SUAD-spec INTERMITTENT classifier · 11 hazard sources · MapLibre map · 5-min deploy","archived":false,"fork":false,"pushed_at":"2026-04-30T16:44:24.000Z","size":696,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-30T17:14:16.257Z","etag":null,"topics":["apps-script","asos","dashboard","government","metar","monitoring","noaa","nws","single-file","weather"],"latest_commit_sha":null,"homepage":"https://github.com/consigcody94/owl-status-apps-script","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/consigcody94.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-30T07:29:49.000Z","updated_at":"2026-04-30T16:44:29.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/consigcody94/owl-status-apps-script","commit_stats":null,"previous_names":["consigcody94/owl-status-apps-script"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/consigcody94/owl-status-apps-script","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/consigcody94%2Fowl-status-apps-script","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/consigcody94%2Fowl-status-apps-script/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/consigcody94%2Fowl-status-apps-script/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/consigcody94%2Fowl-status-apps-script/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/consigcody94","download_url":"https://codeload.github.com/consigcody94/owl-status-apps-script/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/consigcody94%2Fowl-status-apps-script/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32485297,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-30T13:12:12.517Z","status":"online","status_checked_at":"2026-05-01T02:00:05.856Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["apps-script","asos","dashboard","government","metar","monitoring","noaa","nws","single-file","weather"],"created_at":"2026-05-01T04:31:08.191Z","updated_at":"2026-05-01T04:31:12.088Z","avatar_url":"https://github.com/consigcody94.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# OWL Status — Fidelity Build\n\n\u003e A drop-in replacement for James Glenn's NWS Systems Status Map\n\u003e Apps Script. **Identical front-end** (his exact HTML/CSS/JS, byte-\n\u003e for-byte), with a **rebuilt back-end** that pulls METAR data from\n\u003e live NOAA APIs instead of a manually-curated Google Sheet column.\n\n## ⚠ The single most important change\n\n**This build no longer reads METAR data from a Google Sheet.**\n\nThe legacy app's primary failure mode was that ASOS \"Last Observation\"\ndata was sourced from a sheet column (PIDS Col AX) that humans or a\nseparate export job had to keep refreshed. METARs were minutes-to-hours\nstale by design.\n\nIn this build:\n\n| Data | Legacy source | This build |\n|---|---|---|\n| ASOS METAR (\"Last Ob\") | PIDS Col AX (sheet) | **Live IEM batch CGI**, 5-min refresh |\n| Status classification | PIDS Col AP (sheet, hand-edited) | **Computed live** from the METAR + 6-hour state log |\n| Outage cause / `$` flag detail | PIDS Col AS (sheet free-text) | **Decoded from the METAR's NO-codes** (PWINO, FZRANO, RVRNO, etc.) |\n| Service backup, patching, backup-target | PIDS Cols AT/AU/AV (sheet) | Not populated *(those PIDS fields don't have an API equivalent)* |\n| WWA list popup | NWS Active WWA (by Site) sheet | **Live NWS CAP alerts** |\n| Banners | Banner workbook | Optional `Banners` tab (operator-editable) |\n| Long-missing site list | Not in legacy | **New** — auto-detected from the live scan, every station silent \u003e 14 days |\n\nIf a sheet column was the source of truth in the legacy app, **this\nbuild does not read it**. The only sheets we touch are the ones the\nscript writes to itself for state persistence (`Health`, `History`,\n`StateLog`, `ActiveUsers`, `UserHistory`, `Banners`) — all auto-\ncreated on first run, all internal to this script.\n\n\u003e **Operator UX is unchanged.** Every map, popup, filter, button, and\n\u003e overlay looks the same as before. The data behind them is just live\n\u003e now.\n\n## What's new in the back-end\n\n(See the table above for the full sheet → API mapping.)\n\n- **Live IEM batch CGI** for METAR fetch (5-min refresh)\n- **AWC fallback** for any station IEM didn't return in a batch\n- **NCEI cross-check** validates against the authoritative archive\n  (maintenance-window aware)\n- **SUAD-spec INTERMITTENT classifier** with persistent 6-hour state\n  log — flapping/recovery patterns surface correctly\n- **Decoded $-flag NO-codes** (PWINO / FZRANO / RVRNO / TSNO / PNO /\n  VISNO / CHINO / SLPNO) — feeds into the existing popup\n- **Long-missing alert tier** for stations silent \u003e 14 days\n- **WWA list** populated from live NWS CAP alerts (no sheet upkeep)\n\nThe legacy enum (`Up` / `Down` / `Degraded` / `Patching`) renders\nexactly as before. Internally we use the SUAD-spec enum\n(`CLEAN` / `FLAGGED` / `MISSING` / `INTERMITTENT` / etc.) and\ntranslate via `ourEnumToLegacy_()` before returning to his client.\n\n## File layout\n\nThis is a **multi-file Apps Script project** — same structure as\nthe legacy app. All 13 of his HTML files are unmodified. Only\n`Code.gs` and `appsscript.json` differ.\n\n```\ngas-fidelity/\n├── Code.gs              ~2,200 lines · backend + bridge functions\n├── appsscript.json      manifest\n│\n├── Index.html           his exact file (unmodified)\n├── JavaScript.html      his exact file (unmodified)\n├── Css.html             his exact file (unmodified)\n├── Admin.html           his exact file (unmodified)\n├── About.html           his exact file (unmodified)\n├── RFC.html             his exact file (unmodified)\n├── CWSU.html            his exact file (unmodified)\n├── WFO.html             his exact file (unmodified)\n├── MCC.html             his exact file (unmodified)\n├── Region.html          his exact file (unmodified)\n├── Radar.html           his exact file (unmodified)\n├── WWA.html             his exact file (unmodified)\n└── Timezones.html       his exact file (unmodified)\n```\n\n## Deploy procedure\n\nYou'll be pasting 15 files into an Apps Script project. ~5 minutes.\n\n### 1. Create the Sheet\n\nGo to \u003chttps://sheets.new\u003e, name it \"NWS Systems Status\" or similar.\nThe script auto-creates the tabs it needs (`Health`, `History`,\n`StateLog`, `ActiveUsers`, `UserHistory`, `Banners`).\n\nOptional: pre-create a `Catalog` sheet with three columns —\n`A=ICAO`, `B=lat`, `C=lon` — to override the built-in 30-station\nshortlist. Otherwise we ship with 30 majors covering CONUS+AK+HI.\n\n### 2. Open the bound Apps Script\n\n**Extensions → Apps Script**. The editor opens with an empty\n`Code.gs`.\n\n### 3. Paste `Code.gs`\n\n- Click the existing `Code.gs` file in the left rail.\n- Select all (`⌘A` / `Ctrl+A`), delete.\n- Open this folder's `Code.gs`, copy its contents.\n- Paste into the editor.\n- Save (`⌘S` / `Ctrl+S`).\n\n### 4. Paste `appsscript.json`\n\n- Project Settings (gear ⚙ icon, left rail) → enable\n  *\"Show 'appsscript.json' manifest file in editor\"*.\n- Back to the Editor (`\u003c \u003e` icon).\n- Click `appsscript.json` in the file list.\n- Replace contents with this folder's `appsscript.json`. Save.\n\n### 5. Add each HTML file\n\nFor each of the 13 HTML files (Index, JavaScript, Css, Admin,\nAbout, RFC, CWSU, WFO, MCC, Region, Radar, WWA, Timezones):\n\n1. In the Apps Script file list, click the **`+`** next to \"Files\"\n   → **HTML**.\n2. Name it exactly the file's base name (no `.html` extension —\n   Apps Script adds it automatically). E.g. `Index`, `JavaScript`,\n   `Css`, etc. **Case matters** — match exactly.\n3. Open the corresponding file from this folder, copy its full\n   contents.\n4. Paste into the new Apps Script HTML file. Save.\n\nWhen done, your file list should look like:\n\n```\nFiles\n├── Code.gs\n├── appsscript.json\n├── Index.html\n├── JavaScript.html\n├── Css.html\n├── Admin.html\n├── About.html\n├── RFC.html\n├── CWSU.html\n├── WFO.html\n├── MCC.html\n├── Region.html\n├── Radar.html\n├── WWA.html\n└── Timezones.html\n```\n\n### 6. Set Script Properties\n\nProject Settings → Script Properties → **Add script property**:\n\n| Required | Property | Value |\n|---|---|---|\n| ✅ | `OWL_CONTACT` | your email (e.g. `cody.churchwell@noaa.gov`) — embedded in the User-Agent NWS APIs require |\n\nOptional:\n\n| Property | Value |\n|---|---|\n| `DIGEST_RECIPIENTS` | comma-separated emails for 4-hourly status digest |\n| `AIRNOW_API_KEY` | free key from \u003chttps://docs.airnowapi.org/\u003e |\n| `ASOS_STATIONS` | comma-separated ICAO list to override the built-in 30-station shortlist |\n| `ADMIN_EMAILS` | comma-separated allow-list for `/exec?path=admin` |\n| `NCEI_MAINT_START`, `NCEI_MAINT_END` | ISO timestamps to override the built-in maintenance window |\n\n### 7. Authorize + install triggers\n\n- Function dropdown (top toolbar, next to ▶ Run) → pick\n  **`installTriggers`** → click **Run**.\n- Google asks to **Review permissions**. Pick your account.\n- \"Google hasn't verified this app\" → **Advanced → Go to (unsafe)**\n  → **Allow**.\n- Execution log shows `Installed: runScan/5min, runHazards/10min,\n  runDigest/4h, rotateLogs/daily`.\n\n### 8. Force the first scan\n\n- Function dropdown → **`runScan`** → **Run**.\n- Wait ~30 seconds — Execution log says `completed`.\n- Open another tab and visit\n  `https://script.google.com/d/\u003cSCRIPT_ID\u003e/exec?api=health` — should\n  return JSON with `status: \"ok\"`.\n\n### 9. Deploy as Web app\n\n- **Deploy → New deployment**.\n- Gear icon next to \"Select type\" → **Web app**.\n- Description: `OWL Status — Fidelity Build`.\n- Execute as: **Me**.\n- Who has access: **Anyone with Google account** (or **Anyone in\n  your Workspace** for tighter scope).\n- Click **Deploy**, copy the `/exec` URL.\n\nThat URL serves James Glenn's exact map UI, populated with live API\ndata from our backend.\n\n## Server functions the front-end expects\n\nHis JavaScript.html and overlay HTML files call these via\n`google.script.run` / `callServer_`. All are defined in `Code.gs` §12:\n\n| Function | What it returns | Source in our backend |\n|---|---|---|\n| `getPointsPayload(pass, force)` | GeoJSON FeatureCollection wrapped in his expected shape with `ok`, `features`, `banners`, `wwaWfos`, `expirationTimestamp`, etc. | `readScanCache_()` — live IEM/AWC METAR scan |\n| `getWfoGeojsonText()` | WFO footprint GeoJSON | Drive file lookup; empty FeatureCollection if absent |\n| `getRfcGeojsonText()` | RFC footprint GeoJSON | Drive file lookup; empty FeatureCollection if absent |\n| `getCwsuGeojsonText()` | CWSU footprint GeoJSON | Drive file lookup; empty FeatureCollection if absent |\n| `getMccGeojsonText()` | MCC footprint GeoJSON | Drive file lookup; empty FeatureCollection if absent |\n| `getRegGeojsonText()` | NWS Region GeoJSON | Drive file lookup; empty FeatureCollection if absent |\n| `getWwaListChunk(offset, limit)` | Paginated WWA list rows | Live NWS CAP alerts |\n| `getWwaListTablePage(offset, limit)` | Same, alternate signature his older client uses | Same as above |\n\nIf you want the polygon overlays (RFC / CWSU / WFO / MCC / Region)\nto render: drop the GeoJSON files in your Google Drive root with the\nfilenames `rfc.geojson`, `cwsu.geojson`, `wfo.geojson`, `mcc.geojson`,\n`region.geojson`. The script's Drive lookup picks them up\nautomatically. Without those files the overlay toggles still work\nbut render no geometry.\n\n## Status enum mapping\n\nHis client renders four colors for the legacy enum. Our backend\ninternally uses the SUAD-spec enum and translates before returning:\n\n| Our enum (internal) | Legacy enum (rendered) | Color |\n|---|---|---|\n| `CLEAN` | `Up` | green |\n| `RECOVERED` | `Up` | green |\n| `FLAGGED` | `Degraded` | yellow |\n| `INTERMITTENT` | `Degraded` | yellow |\n| `MISSING` | `Down` | red |\n| `OFFLINE` | `Down` | red |\n| `NO DATA` | `Down` | red |\n\nThe internal SUAD-spec enum is also exposed on each feature's\nproperties as `owl_status` (string), `owl_state_log` (array),\n`owl_flag_codes` (array), and `owl_evidence` (object) — his client\nignores these but they're there for any future popup enhancements.\n\n## Iterating\n\nCode edits in the editor take effect for the next trigger run\nimmediately. The Web app URL is pinned to a deployment version —\nto update the public URL, **Deploy → Manage deployments → ✎ →\nVersion: New version → Deploy**.\n\nFor local development with `clasp`:\n\n```bash\nnpm install -g @google/clasp\nclasp login\nclasp clone \u003cSCRIPT_ID\u003e\nclasp push --watch       # auto-push on save\nclasp logs --watch       # tail logs in real time\n```\n\n## What's NOT changed from his original\n\n- Visual layout\n- Sidebar (filters, regions, programs, overlays, search)\n- Map (Esri ArcGIS JavaScript API, his exact basemap, his exact\n  popup template)\n- Admin page (counters, active users, history table)\n- About page\n- WFO/RFC/CWSU/MCC/Region/Radar/WWA/Timezones overlay templates\n- Header (current time, last updated, refresh timer)\n- Banner area\n- Down sites table\n- Type breakdown\n- Right sidebar\n- All keyboard shortcuts\n\nOperators trained on the legacy app will see no functional\ndifference except: data is fresh, and the cause of any anomaly\nshows up in the popup with decoded NO-codes.\n\n## Author\n\nCody Churchwell — `cody.churchwell@noaa.gov`\nNOAA / National Weather Service — SUAD / ASOS Operations\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fconsigcody94%2Fowl-status-apps-script","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fconsigcody94%2Fowl-status-apps-script","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fconsigcody94%2Fowl-status-apps-script/lists"}