EAS Station logo EAS STATION
Version 2.71.40

Professional Emergency Alert System

Emergency alert system for Putnam County, OH

Build Information
Commit: af7d0e9d
Branch: main
Date: 2026-04-03T12:41:54Z
Message: Update repository statistics [skip ci]

What's New in 2.71.40

Latest Release

Release History

v2.71.40 Current
v2.71.40 Current
2026-04-03
Fixed (2)
  • USB tower light (`TowerLightController`) and NeoPixel controller were
  • On-air broadcast overlay (global countdown timer popup) could disappear
v2.71.39
2026-04-01
Fixed (5)
  • `ssl_utils.get_ssl_certificate_info()` incorrectly reported a Let's Encrypt
  • `update.sh` nginx config refresh silently reverted a Let's Encrypt certificate back
  • `update.sh` showed the "Do you want to continue with the update?" welcome dialog a
  • `update.sh` backup whiptail dialog did not call `redraw_screen` on the "No" path,
  • `update.sh` migration-error prompt used a plain `read` command whose text was buried
v2.71.38
2026-04-01
Added (1)
  • Alert History table now has server-side sortable columns: clicking any column header
Fixed (4)
  • `GET /eas_messages/<id>/summary` returned HTTP 500 because `EASMessage` has no
  • Light theme: table column headers were nearly invisible because the `table-light`
  • Removed two orphaned `</div>` closing tags at the end of `alerts.html` that
  • Added `flex-shrink: 0` to the footer so it is never compressed by the flex layout,
v2.71.37
2026-04-01
Added (5)
  • **`app_utils/alert_sources.py`** — Two new canonical source-identifier constants:
  • **`app_core/models.py`** + migration — `received_eas_alerts` table gains an
  • **`eas_monitor.py`** — Resolves the canonical source when an alert is decoded:
  • **`templates/audio_received.html`** + detail page — Ingest Path **badge** (RF /
  • **`webapp/received.py`** — Wires up the `alert_source` query filter to support the
v2.71.36
2026-04-01
Fixed (1)
  • **`webapp/admin/coverage.py`** — SAME look-ups store county names as
v2.71.35
2026-04-01
Fixed (1)
  • **`eas_monitoring_service.py`** — The variable rename from `configured_fips` to
v2.71.34
2026-04-01
Added (3)
  • **Relay audio** — OTA-received alerts that are forwarded now attach the original
  • **Live location config reload** — The EAS monitor service re-reads
  • **Alert metadata enrichment** — Forwarded alert objects now carry `event_type` and
Fixed (3)
  • SAME header forwarding now preserves statewide wildcard codes (e.g., `039000`)
  • FIPS code lists are validated at intake to reject malformed or out-of-range values
  • New unit-test coverage for location-code filtering, wildcard preservation, and
v2.71.33
2026-03-31
Fixed (1)
  • **`eas_monitoring_service.py`** — A confidence threshold of **0.25** is now applied
Changed (2)
  • **`eas_monitoring_service.py`** — Audio resampling for hardware-controlled sources
  • Waveform and spectrogram visualisations in the diagnostics panel are disabled;
v2.71.32
2026-03-31
Fixed (4)
  • **`eas_monitoring_service.py`** — `UnifiedEASMonitorService` previously shared a
  • Ring buffer is updated **before** `process_samples()` so audio is captured in the
  • `get_status()` now aggregates `decoder_synced`, `in_message`, and `bytes_decoded`
  • The `_current_source_context` mutable field is removed; source identity is carried
v2.71.31
2026-03-31
Fixed (2)
  • **`app_utils/eas.py`** — `_extract_text_from_payload()`: removed `"headline"` from
  • **`app_utils/eas.py`** — Improved punctuation, whitespace, and special-character
v2.71.30
2026-03-31
Fixed (2)
  • **`app_core/eas_storage.py`** — Added `ensure_eas_settings_columns()` following the
  • **`app.py`** — Imports and calls `ensure_eas_settings_columns(logger)` as step 5b in
v2.71.29
2026-03-31
Added (2)
  • **`app_utils/eas_encoding.py`** — When building the SAME header for a forwarded
  • **Admin dashboard** — New **Auto-Forward Event Filter** section with grouped
v2.71.28
2026-03-31
Added (2)
  • **`docs/guides/TTS_NORMALIZATION.md`** — New reference guide documenting
  • **`tests/test_tts_text_normalization.py`** — 26 tests covering all
Fixed (9)
  • **`app_utils/eas.py`** — `_normalize_text_for_tts()`: added Layer 2 NWS-specific
  • Alternate-timezone slash notation (`/5 PM CDT/`) is stripped to plain
  • `ST.` abbreviation is expanded to "Saint" (e.g. "ST. JOSEPH" →
  • Indiana county-name disambiguation: `IN` is replaced with "Indiana"
  • **`app_utils/eas.py`** — Extended `_ACRONYM_MAP` (Layer 3) with:
  • `MI` → "Michigan" — NWS county-disambiguation state code; TTS
  • `OH` → "Ohio" — NWS county-disambiguation state code; TTS reads bare
  • `AFD` → "Air Force Depot" — facility abbreviation used in SAME area
  • **`app_utils/eas.py`** — Aligned inline Layer comment numbering (0–3 →
Changed (3)
  • **`templates/admin/tts_pronunciation.html`** — Info banner now explains
  • **`templates/admin/tts.html`** — Pronunciation Preview panel now shows a
  • **`templates/help.html`** — New "Text-to-Speech Normalization &
v2.71.27
2026-03-30
Changed (2)
  • **`templates/terms.html`** — Replaced the "Jenga tower" fragility callout with three-paragraph
  • **`docs/policies/TERMS_OF_USE.md`** — Markdown source updated to match.
v2.71.26
2026-03-30
Added (2)
  • **`templates/terms.html`** — New `alert-danger` callout in Section 4b explaining that EAS was
  • **`docs/policies/TERMS_OF_USE.md`** — Mirrored callout added to markdown source.
v2.71.25
2026-03-30
Changed (2)
  • **`templates/terms.html`** — Removed **ORC § 2921.13** (Falsification) from the Ohio-specific
  • **`docs/policies/TERMS_OF_USE.md`** — Updated markdown source to match.
v2.71.24
2026-03-30
Changed (2)
  • **`templates/terms.html`** — Added three additional Ohio-specific statutes to the Section 4a
  • **`docs/policies/TERMS_OF_USE.md`** — Updated markdown source to match.
v2.71.23
2026-03-30
Changed (2)
  • **`templates/terms.html`** — Added **ORC § 2909.04** (Disrupting Public Services,
  • **`docs/policies/TERMS_OF_USE.md`** — Updated markdown source to match.
v2.71.22
2026-03-30
Changed (2)
  • **`templates/terms.html`** — Expanded Section 4a "State and local laws" bullet to add an
  • **`docs/policies/TERMS_OF_USE.md`** — Updated markdown source to match the above changes.
v2.71.21
2026-03-27
Added (4)
  • **`app_core/models.py`** — `ManualEASActivation` gains two new nullable columns:
  • **`webapp/eas/workflow.py` `manual_eas_generate()`** — Captures the client IP
  • **`webapp/eas/workflow.py` `manual_eas_send()`** — Same IP capture at broadcast
  • **`app_core/migrations/versions/20260327_add_ip_to_manual_eas_activations.py`** —
v2.71.20
2026-03-27
Changed (3)
  • **`templates/terms.html`** — Strengthened Section 3 (Disclaimer of Liability & Indemnification)
  • **`templates/terms.html`** — Added new Section 4a (Criminal Liability & Federal Law Violations)
  • **`docs/policies/TERMS_OF_USE.md`** — Updated markdown source to match all changes above.
v2.71.19
2026-03-27
Fixed (3)
  • **`webapp/admin/coverage.py`** — Census TIGER fallback for county coverage now
  • **`webapp/admin/coverage.py`** — Step 3 Boundary-table fallback (`Boundary.query
  • **`webapp/admin/api.py` `_detect_county_wide()`** — `short_with_list` heuristic
v2.71.18
2026-03-27
Fixed (2)
  • **`webapp/routes_debug.py`** — `.cast("geography")` called directly on a SQLAlchemy
  • **`templates/alert_detail.html`** — The debug panel rendered the full errors array with
v2.71.17
2026-03-27
Fixed (3)
  • **`webapp/routes_debug.py`** — Both `/debug/alert/<id>` and `/debug/boundaries/<id>`
  • **`templates/alert_detail.html`** — Debug panel "Boundary Intersection Results" table
  • **`webapp/admin/intersections.py`** — `fix_county_intersections` was computing
v2.71.16
2026-03-27
Fixed (2)
  • **`app_core/alerts.py`** — `_fetch_bulk_intersections` filtered boundaries with
  • **`webapp/admin/intersections.py`** — `fix_county_intersections` (the backend for
v2.71.15
2026-03-27
Fixed (1)
  • **`webapp/admin/intersections.py`** — Wrong import path `from app_core.coverage import
v2.71.14
2026-03-27
Fixed (2)
  • **`templates/alert_detail.html`** — The `debugBoundaries()` JS function existed but had
  • **`templates/components/navbar.html`** — The `/debug/ipaws` IPAWS Poller Debug page
v2.71.13
2026-03-27
Fixed (7)
  • **`webapp/admin/coverage.py`** — `calculate_coverage_percentages`: Three separate bugs
  • **`webapp/admin/api.py`** — `alert_detail`: `is_actually_county_wide` now requires
  • **`templates/alert_detail.html`**:
  • "COUNTY-WIDE ALERT" banner no longer fires for SAME-estimated coverage.
  • "Exact Coverage" label changes to "Estimated Coverage" when `is_estimated=True`,
  • Square miles are now displayed next to the coverage percentage in both the
  • Coverage badge in the Alert Information header no longer shows the county-wide
v2.71.12
2026-03-27
Fixed (1)
  • **`webapp/admin/coverage.py`** — `calculate_coverage_percentages`: Added fallback
Changed (1)
  • **`webapp/admin/api.py`** — `get_boundaries`: When `/api/boundaries?type=county`
v2.71.11
2026-03-27
v2.71.10
2026-03-27
Fixed (2)
  • **`poller/cap_poller.py`** — `_update_existing_alert`: No longer clears
  • **`webapp/admin/coverage.py`** — `try_build_geometry_from_same_codes`: Added
v2.71.9
2026-03-27
Fixed (4)
  • **`templates/alert_detail.html`** — Replaced misleading "COVERAGE CALCULATING" /
  • **`templates/alert_detail.html`** — `triggerIntersectionFix()`: Added immediate
  • **`webapp/admin/intersections.py`** — `calculate_single_alert`: Always calls
  • **`webapp/admin/coverage.py`** — `calculate_coverage_percentages`: County coverage
v2.71.8
2026-03-26
v2.71.7
2026-03-26
Fixed (2)
  • **`templates/base.html`** — Python badge updated from `3.11` to `3.13` to
  • **`templates/partials/footer.html`** — Python badge updated from `3.11.14` to
v2.71.6
2026-03-26
Changed (14)
  • **`templates/base.html`** — Updated copyright year 2025 → 2026. Wrapped
  • **`templates/partials/footer.html`** — Updated both copyright year references
  • **`static/css/styles.css`** — Multiple visual improvements:
  • Added the previously missing `page-header-gradient` CSS class (referenced in
  • Added animated rainbow bottom accent line (`::after`) to `.navbar`.
  • Added `page-header::after` subtle bottom highlight line.
  • Enlarged `.footer-logo-mark` icon box (60 → 64 px) with a blue glow shadow.
  • Made `.footer-divider` an animated rainbow gradient stripe instead of a plain
  • Updated `.footer-column-title::after` underline to teal-to-blue gradient.
  • Added `.tech-stack-card` glass-morphism container for the badge row.
  • ...4 more
v2.71.5
2026-03-26
v2.71.4
2026-03-26
Fixed (1)
  • **`templates/admin/tts_pronunciation.html`** — The JavaScript block was declared as
v2.71.3
2026-03-26
Fixed (2)
  • **`app_utils/eas_decode.py`** (`_try_multiple_sample_rates`) — Audio file was read and
  • **`app_utils/eas_decode.py`** (`_decode_from_samples`) — Extracted the decode body
v2.71.2
2026-03-26
Fixed (2)
  • **`app_utils/ipaws_enrichment.py`** (`_canonicalize_signed_info`) — `with_comments=False`
  • **`poller/cap_poller.py`** (`_convert_cap_alert`) — Alert XML is now serialized using
v2.71.1
2026-03-26
Fixed (2)
  • **`templates/alert_detail.html`** (`loadCountiesFromSameCodes`) — SAME codes ending in
  • **`app_utils/eas.py`** (`_convert_audio_to_samples`) — Added direct `ffmpeg` subprocess
v2.71.0
2026-03-26
Added (6)
  • **`app_core/models.py`** — New `TTSPronunciationRule` model and `TTS_BUILTIN_PRONUNCIATIONS`
  • **`app_utils/eas.py`** — `_normalize_text_for_tts()` function: two-layer substitution
  • **`app_utils/eas.py`** — `_load_pronunciation_rules()` helper loads enabled rules ordered
  • **`webapp/admin/tts_pronunciation.py`** — Full CRUD admin routes under `/admin/tts/pronunciation`
  • **`app_core/migrations/versions/20260326_add_tts_pronunciation_rules.py`** — Alembic migration
  • **`docs/development/AGENTS.md`** — New "Alembic Migration Rules" section under Database
Fixed (1)
  • **`app_core/migrations/versions/20260326_add_tts_pronunciation_rules.py`** — `down_revision`
v2.70.3
2026-03-25
Fixed (6)
  • **`app_utils/eas.py`** (`EASBroadcaster.handle_alert`) — `inject_eas_audio()` was called
  • **`app_core/audio/eas_stream_injector.py`** (`inject_eas_audio`) — Before publishing EAS
  • **`app_core/audio/ingest.py`** (`AudioSourceAdapter`) — Added `_eas_inject_seq` integer
  • **`app_core/audio/icecast_output.py`** (`IcecastStreamer._feed_loop`) — Each streamer now
  • **`app_core/audio/eas_monitor.py`** (`_store_received_alert`) — If `db.session.commit()`
  • **`eas_monitoring_service.py`** (`_ensure_raw_audio_column`) — At startup the service now
v2.70.2
2026-03-25
Fixed (1)
  • **`app_core/audio/ingest.py`** (`AudioIngestController.inject_eas_test_signal`) — Test
v2.70.1
2026-03-25
Fixed (3)
  • **`app_core/audio/ingest.py`** (`AudioSourceAdapter`) — Added `_eas_injection_active`
  • **`app_core/audio/eas_stream_injector.py`** (`inject_eas_audio`) — Sets
  • **`app_core/audio/eas_monitor.py`** (`_store_received_alert`) — `full_alert_data=alert`
v2.70.0
2026-03-25
Added (6)
  • **`app_core/audio/ingest.py`** (`AudioSourceAdapter.schedule_inject`) — New public method
  • **`app_core/models.py`** (`ReceivedEASAlert.raw_audio_data`) — New `LargeBinary` column that
  • **`app_core/audio/eas_monitor_v3.py`** (`UnifiedEASMonitorService`) — Per-source audio ring
  • **`webapp/admin/audio/received.py`** — New `/audio/received/<id>/audio` route that streams
  • **`templates/audio_received_detail.html`** — Audio player card showing the raw received OTA
  • **`app_core/migrations/versions/20260325_add_raw_audio_to_received_alerts.py`** — Migration
Fixed (3)
  • **`eas_monitoring_service.py`** — `eas_stream_injector.set_controller()` was never called
  • **`app_core/audio/ingest.py`** (`inject_eas_test_signal`) — The test signal was injected
  • **`webapp/documentation.py`** — `/docs/DIAGRAMS` (and `/docs/CHANGELOG`, `/docs/ABOUT`)
v2.69.6
2026-03-24
Fixed (3)
  • **`app_core/audio/redis_commands.py`** (`_execute_command` / `source_start`) — The return
  • **`app_core/audio/sources.py`** (`StreamSourceAdapter._restart_ffmpeg_process`) — When
  • **`eas_service.py`** (`publish_eas_metrics_to_redis`) — When `eas_monitoring_service.py`
v2.69.5
2026-03-24
Fixed (5)
  • **`webapp/admin/audio_ingest.py`** (`api_delete_audio_source`) — Replace the
  • **`webapp/admin/audio_ingest.py`** (`api_delete_audio_source`) — Deleting a
  • **`app_core/audio/redis_commands.py`** (`delete_source`) — Added
  • **`eas_monitoring_service.py`** (`initialize_audio_controller`) — Wrapped
  • **`eas_monitoring_service.py`** (`main`) — Wrapped the
v2.69.4
2026-03-24
Fixed (4)
  • **`webapp/admin/audio_ingest.py`** (`api_delete_audio_source`) — Delete no
  • **`webapp/admin/audio_ingest.py`** (`api_get_audio_sources`) — Sources that
  • **`update.sh`** — Added `systemctl reset-failed` for all EAS Station service
  • **`systemd/eas-station-audio.service`** — Added `StartLimitBurst=0` to
v2.69.3
2026-03-24
Fixed (7)
  • **`eas_monitoring_service.py`** (`publish_metrics_to_redis`) — Replaced the
  • **`eas_monitoring_service.py`** (main loop) — Reduced metrics publish interval
  • **`eas_monitoring_service.py`** (source watchdog) — Watchdog now also
  • **`app_core/audio/worker_coordinator_redis.py`** (`read_shared_metrics`) —
  • **`app_core/audio/auto_streaming.py`** (`_get_eas_monitor_settings`) —
  • **`app_core/audio/auto_streaming.py`** (health-check step) — Dead streamers
  • **`app_core/websocket_push.py`** — Reduced the WebSocket push loop from
v2.69.2
2026-03-24
Fixed (4)
  • **`app_core/audio/auto_streaming.py`** — `_get_eas_monitor_settings()` now
  • **`app_core/audio/redis_commands.py`** — `inject_test_signal` handler now
  • **`eas_service.py`** — `initialize_eas_monitor()` now wraps the FIPS
  • **`eas_monitoring_service.py`** — Added `_redis_publisher_monitor_loop()`
v2.69.1
2026-03-24
Fixed (3)
  • **`eas_monitor_v3.py`** — `HealthTracker.update_no_audio()` no longer resets
  • **`redis_commands.py`** — Added `inject_test_signal` command to
  • **`eas_decoder_monitor.py`** — The `/api/admin/eas_decoder_monitor/test_signal`
v2.69.0
2026-03-23
Added (8)
  • `EASMonitor._streaming_decoder` alias, `_restart_count` tracker, `_restart_monitor_thread()`, and `_resample_if_needed()` to support watchdog restarts and stereo audio handling.
  • `EASMonitor.get_status()` now includes `restart_count` and computes runtime metrics even when the monitor is stopped.
  • `_SoapySDRReceiver._calculate_buffer_size()` dynamically sizes the IQ read buffer based on the configured sample rate.
  • Setup wizard now includes a **Core** section (SECRET_KEY and PostgreSQL credentials) that is validated on form submission.
  • `_is_valid_partition_code()` in `location_settings.py` — `sanitize_fips_codes()` now accepts SAME partition-digit codes (e.g. `627137`) whose whole-county equivalent is known.
  • `tools/download_nws_gis_data.py` — standalone CLI that downloads NWS Public Forecast Zones and NWR Political Subdivisions (partial-county) shapefiles from weather.gov into `assets/`.
  • NWS partial-county shapefile `assets/cs16ap26.dbf` (April 2026 vintage) bundled; `_load_county_subdivision_index` now auto-detects the newest `cs*.dbf` in `assets/` and logs a download hint when absent.
  • `install.sh` now runs `tools/download_nws_gis_data.py` after database setup to fetch the latest GIS data.
Fixed (4)
  • Removed redundant `import os` inside `_collect_smart_health` that caused `UnboundLocalError` in production.
  • `_restart_ffmpeg` in `icecast_output.py` now sleeps for `ICECAST_RESTART_DELAY` seconds before relaunching FFmpeg to prevent rapid restart loops.
  • `build_database_url()` now falls back to `POSTGRES_*` environment variables when `DATABASE_URL` is not set.
  • SOAPY_SDR error code −7 description now includes "not locked" so the PLL lock hint is surfaced correctly.
v2.68.0
2026-03-23
Changed (4)
  • **`broadcast_adapter.py`** — Replaced bare `except:` clause with `except queue.Empty:` so
  • **`radio/discovery.py`** — Silent `except Exception: pass` blocks in SoapySDR capability
  • **`routes_settings_radio.py`** — Replaced three generic `raise Exception(error)` calls with
  • **Migration scripts** — Replaced `print()` calls in five Alembic migration files with
v2.67.0
2026-03-23
Added (5)
  • **Per-source EAS ingest Icecast streams** — The auto-streaming service now creates a
  • **EAS decoder monitor respects database settings** — `AutoStreamingService` now reads
  • **Test signal injection** — New `POST /api/admin/eas_decoder_monitor/test_signal`
  • **Navbar link** — *EAS Decoder Monitor* is now listed under Monitor → Radio Monitoring
  • **Updated nginx proxy rule** — The single `/eas-ingest.mp3` location block is replaced
Changed (2)
  • `AutoStreamingService.__init__` accepts an optional `flask_app` parameter so the
  • `AudioIngestController` gains `inject_eas_test_signal(source_name)` method.
v2.66.2
2026-03-23
Fixed (1)
  • **TTS "No TTS provider configured" for every IPAWS/CAP alert** — `load_eas_config()` was
v2.66.1
2026-03-23
Fixed (1)
  • **Navbar Tools menu overflow** — The standalone "Tools" dropdown was too long to fit on
v2.66.0
2026-03-23
Added (3)
  • **EAS ingest Icecast stream** (`/eas-ingest.mp3`) — a 3rd Icecast mountpoint that
  • **Three working audio pipeline test files** — `tests/test_audio_playout_queue.py` (24
  • **Robust test-runner logging** — `routes_audio_tests.py` now scans output from the
Fixed (2)
  • **Listen button** — root cause was `audio.play()` being called inside an async
  • **Error messages now actionable** — the error alert distinguishes between "no audio
v2.65.9
2026-03-23
Added (5)
  • **Operator audit trail for manual EAS alerts** — `manual_eas_activations` now stores
  • **Application log entries** — `workflow_logger.info` now emits a line such as
  • **`generated_by` in SystemLog** — the `admin` code path also records the operator in the
  • **Alert self-test log** — `route_logger.info` for `run_alert_self_test` now includes the
  • **Database migration** `20260323_add_created_triggered_by_to_activations` adds the two
v2.65.8
2026-03-21
Fixed (4)
  • **OLED screen previews no longer blank** — the Custom Display Screens management page now
  • **Bar graphs visible in previews** — `bar` elements are drawn as filled progress bars on
  • **VFD element previews improved** — VFD screens that use the `elements` format now render
  • **Legacy `lines`-format OLED screens unaffected** — the previous text-based renderer is
v2.65.7
2026-03-21
Added (2)
  • **ENDEC hardware shown in Alert Verification** — the detected ENDEC type (`endec_mode`)
  • **`endec_mode` persisted in stored decode records** — `record_audio_decode_result()` now
Fixed (1)
  • `_deserialize_decode_result` in the alert-verification route now correctly restores
v2.65.6
2026-03-21
Added (10)
  • **ENDEC hardware detection via null/FF terminator bytes** — `detect_endec_mode()` now
  • NWS Legacy / EAS.js: 2 × 0x00 → `NWS`
  • NWS Broadcast Message Handler: 3 × 0x00 → `NWS_BMH`
  • NWS Console Replacement System: 3 × 0x00 with CRS scoring → `NWS_CRS`
  • SAGE ANALOG 1822: 1 × 0xFF → `SAGE_ANALOG_1822`
  • SAGE DIGITAL 3644: 3 × 0xFF → `SAGE_DIGITAL_3644`
  • SAGE DIGITAL 3644 (first burst leading byte): 0x00 before preamble → strong `SAGE_DIGITAL_3644` vote
  • DEFAULT / DASDEC / TRILITHIC: identified by inter-burst gap timing (existing logic retained)
  • **Post-message terminator capture in `SAMEDemodulatorCore`** — after a SAME message is
  • **Leading null byte detection** — a 0x00 byte decoded just before a burst's preamble
v2.65.5
2026-03-21
Fixed (3)
  • **32-bit PCM WAV files fail to decode** — `_read_audio_samples` only handled 16-bit
  • **Goertzel decoder overrides correct DLL result with garbled partial header** — for
  • **SAME headers generated with trailing spaces** — `build_same_header` padded the
v2.65.4
2026-03-20
Fixed (3)
  • **`/admin` returning fallback HTML** — `get_same_lookup()` returns a `MappingProxyType`
  • **`/admin/notifications` and `/admin/application` returning fallback HTML** — both pages
  • **Setup-mode first-run access** — `before_request` endpoint allowlist for setup mode only
v2.65.3
2026-03-20
Fixed (3)
  • **`/api/system_status` 500 error** — `_CPU_SAMPLE_INTERVAL_SECONDS` constant was
  • **`/logs` page (system_logs.html)** — template used `{% block head %}` which is not
  • **Test correctness** — updated `test_admin_dashboard_fixes.py` to reflect the active
v2.65.2
2026-03-20
Fixed (4)
  • **`admin/notifications/` 500 error** — error-handler in `notifications.py` referenced
  • **`admin/poller/` 500 error** — same `admin_page` typo in `poller.py`; corrected.
  • **`admin/application-settings/` 500 error** — same `admin_page` typo in
  • **`admin/hardware/`, `admin/icecast/`, `admin/tts/`, `admin/certbot/`,
v2.65.1
2026-03-20
Added (3)
  • **Application Settings**, **Alert Poller**, **Text-to-Speech**, **SSL Certificates**, and **Backups**
  • New **System** category in the Settings Hub for Backups.
  • Certbot (SSL) card added to the **Network** category.
Fixed (1)
  • Notifications card description in the Settings Hub now correctly reads
v2.65.0
2026-03-20
Added (5)
  • **SNMP v2c trap notifications** — EAS Station can now send SNMP traps to NMS targets
  • **`pysnmp` added to `requirements.txt`** — previously the SNMP library was an undocumented
  • **`test-snmp` endpoint** — `/admin/notifications/test-snmp` (POST) sends a test SNMP trap
  • **SNMP fields in `NotificationSettings` model** — `snmp_enabled`, `snmp_targets` (JSONB),
  • **Database migration `20260320_add_snmp_to_notifications`** — upgrades existing installs
Fixed (2)
  • **Compliance email alerts now use database SMTP settings** — `system_health.py` was still
  • **SNMP health monitor uses database targets** — `system_health.py` now reads SNMP targets
v2.64.0
2026-03-20
Added (8)
  • **Raw SAME Header Parser** on `/admin/alert-verification` — paste any `ZCZC-…` string and
  • **Skip baud-rate offset variants when DLL confidence ≥ 0.85** — the Goertzel bit-scan now
  • **Early-exit in multi-rate sample-rate selection** — `_try_multiple_sample_rates` stops
  • **Vectorized Goertzel filter for tone detection** — `_goertzel_power` in
  • **Eliminated double audio load in `detect_eas_from_file`** — tone and narration detection
  • **Polyphase audio resampler** — `_resample_with_scipy` now uses `scipy.signal.resample_poly`
  • **FIPS lookup singleton** — `get_same_lookup()` returns the module-level `US_FIPS_LOOKUP`
  • **DB indexes on alert analytics columns** — added `idx_cap_alerts_sent`,
v2.63.3
2026-03-20
Changed (8)
  • **`docs/hardware/ALPHA_*.md` renamed** — removed "Phase X" development numbering from
  • **`docs/troubleshooting/AUDIO_STREAMING_SETUP.md`** — rewrote from scratch. Previous
  • **`docs/guides/HELP.md`** — fixed Reference Commands table (all entries were Docker
  • **`docs/troubleshooting/TTS_TROUBLESHOOTING.md`** — replaced two references to the
  • **`docs/guides/MANUAL_EAS_EVENTS.md`** — replaced reference to `debug_tts.py` with
  • **`mkdocs.yml`** — removed all nav entries pointing to previously deleted files; updated
  • **`docs/INDEX.md`** — added Alpha LED Sign documentation to the Hardware section.
  • **`scripts/README.md`** — rewrote to reflect current bare-metal scripts inventory.
v2.63.2
2026-03-20
Fixed (1)
  • **Missing image beside maintainer bio on About page** – `ham-radio-icon.svg` was a PNG
v2.63.1
2026-03-20
Fixed (2)
  • **EAS monitor showing false "Disconnected/Unavailable" status** – The
  • **Audio System Logs tab always empty** – The `AudioAlert` database model existed and
v2.63.0
2026-03-19
Fixed (4)
  • **Coverage percentage calculation** – The denominator in `calculate_coverage_percentages`
  • **County-wide fallback producing wrong 100 % coverage** – The alert detail view had a
  • **"Calculate Coverage Percentage" button failing with missing geometry** – The
  • **XML digital signature verification** – Added `_canonicalize_signed_info()` helper in
v2.62.2
2026-03-19
Fixed (5)
  • **Unauthenticated access to VFD control** – All VFD routes (`/vfd_control`, `/vfd`, and all
  • **Unauthenticated access to Displays dashboard** – `/displays` now requires
  • **Unauthenticated access to Screen management** – All screen and rotation routes (`/screens`,
  • **Unauthenticated access to Alert Verification** – All alert verification routes
  • **Unauthenticated access to EAS Compliance dashboard** – All compliance routes
v2.62.1
2026-03-19
Fixed (4)
  • **Unauthenticated access to LED control** – All LED routes (`/led_control`, `/led`, and all
  • **Message history stuck on "Loading message history..."** – `loadMessageHistory()` now updates
  • **Live sign preview (canvas simulator) not working** – Fixed a JavaScript bug where a duplicate
  • **Search/filter history did nothing** – Implemented the previously empty `displayFilteredHistory()`
v2.62.0
2026-03-19
Added (12)
  • **WYSIWYG LED Sign Simulator** – Live CSS-animated sign panel in the Custom Message tab; all 20 M-Protocol display modes animate in real time (scroll, roll-left/right/up/down, wipe-*, flash, explode, compressed-rotate, auto, clock)
  • **Mixed-mode multi-line preview** – each of the 4 lines independently shows its selected effect/color/speed in the simulator panel
  • **Layout Preset buttons** – one-click configurations: Static 4, Header+Scroll, Alert, Ticker
  • **Per-line effect pills** – colour-coded badges on each line editor card showing the active display mode
  • **Speed modifier CSS classes** – speed-1 through speed-5 control animation playback rate
  • **Dots / Pixel-Art tab** – 20×7 (up to 160×16) interactive pixel-art canvas; click/drag to paint, shift/invert/fill tools, text-to-dots generator (5×7 bitmap font for A/E/S), five quick patterns (checkerboard, border, diagonal, heart, arrow), live canvas preview; sends via new M-Protocol Picture File (Type I) command
  • **RSS Feeds tab** – add/remove RSS feed sources with name, URL, interval, color, effect, max items; per-feed fetch/refresh button; item viewer with click-to-select (up to 4 lines); "Send Selected" and "Send All Enabled Feeds" buttons
  • **`send_dots_graphic()` method** on `Alpha9120CController` – encodes a 2-D pixel grid as an M-Protocol Type I (Picture File) frame
  • **`LEDRSSFeed` and `LEDRSSItem` database models** with full CRUD API (`/api/led/rss/feeds`, `/api/led/rss/feeds/<id>/fetch`, `/api/led/rss/feeds/<id>/items`, `/api/led/rss/send`)
  • **Dots API** (`POST /api/led/dots`) accepts a JSON dot-grid and sends it to the sign
  • ...2 more
v2.61.2
2026-03-18
Added (3)
  • **EAS decoding architecture diagram** in `docs/architecture/EAS_DECODING_SUMMARY.md` —
  • **Notification delivery flow diagram** in `docs/guides/notifications.md` — Sequence
  • **Updated `docs/reference/DIAGRAMS.md`** — Added index entries for 5 previously
Fixed (1)
  • **7 broken Mermaid diagrams** — Fixed parse and lexical errors in
v2.61.1
2026-03-18
Fixed (5)
  • **Dark theme: invisible text on cards and Bootstrap components** — Bootstrap 5.3
  • **`.card` missing explicit text color** — Added `color: var(--text-color)` directly
  • **`bg-*-subtle` / `text-*-emphasis` Bootstrap utilities** — Overrode
  • **`alert-light` / `alert-secondary` in dark themes** — These alerts previously
  • **Severity badge text contrast (`index.html`)** — `.severity-severe` used
v2.61.0
2026-03-18
Fixed (7)
  • **OTA broadcast silently skipped** — The EAS monitor daemon thread had no
  • **`handle_alert()` false-positive success on DB failure** — `same_triggered`
  • **EASSettings not loaded from database in CAP poller** — `load_eas_config()`
  • **Deprecated `datetime.utcnow()` in `alert_forwarding.py`** — Redis payload
  • **OTA auto-forward attempted broadcast for UNKNOWN event codes** — When the
  • **`build_files()` exceptions propagated uncaught from `handle_alert()`** —
  • **`test_eom_segment_duration_is_reasonable` used wrong lower bound** — The
v2.60.4
2026-03-18
Fixed (9)
  • **IPAWS alerts with embedded audio fall back to TTS instead of using the pre-recorded
  • **`save_ipaws_audio()` skips `derefUri` resources with missing `mimeType`** — The
  • **MPEG audio format detection too narrow** — `_convert_audio_to_samples()` checked
  • **EAS audio sources stuck in ERROR state after network disruption** — The
  • **No automatic recovery of failed audio sources** — Added a source error-recovery
  • **"Listen to EAS audio feed" button always fails when EAS monitor has no active
  • **Misleading "audio-service may be starting up" error message** — The EAS monitor
  • **EAS monitor badge showed no guidance when sources are stopped** — Added a
  • **Listen button error showed no actionable guidance** — When the decoder stream
v2.60.2
2026-03-17
Fixed (5)
  • **Edit Alert modal and Confirmation modal unclickable** — Both Bootstrap modals were
  • **"Delete Expired Alerts" button always failed** — The JavaScript `clearExpiredAlerts()`
  • **"View Alert" button on Audio Archive** — The button was incorrectly linking to the
  • **"Edit Alert" modal not opening on Admin Panel** — The Bootstrap Modal instance for
  • **Confirmation modal not opening on Admin Panel** — `window.confirmationModal` was
v2.59.0
2026-03-17
Added (2)
  • **NOAA vs IPAWS polling differentiation** — The CAP poller now writes a separate
  • **Per-source error attribution** — Fetch errors (SSL, timeout, request failures) are now
Fixed (3)
  • **`AudioAlert.cleared` AttributeError** — The `audio` log-viewer category referenced a
  • **`PollHistory.poll_time` AttributeError** — `websocket_push.py` referenced
  • **IPAWS-STAGING endpoints now grouped with IPAWS** — The FEMA TDL staging domain
v2.58.0
2026-03-14
Changed (12)
  • **Documentation cleanup** — Removed one-off development artifacts from the docs directory:
  • **CSS Variables Migration doc relocated** — Moved `CSS_VARIABLES_MIGRATION.md` from the
  • **mkdocs.yml copyright corrected** — Changed "MIT License" to the accurate dual-license
  • **mkdocs.yml navigation rebuilt** — Removed 29 navigation entries pointing to files that do
  • **Installation** section (7 guides, previously absent from nav)
  • **Troubleshooting** section (21 guides, previously entirely absent from nav)
  • **Security** section (3 guides, previously absent from nav)
  • **Architecture** section expanded from 3 to 11 entries
  • **Hardware** section expanded from 4 to 15 entries (including Alpha LED sign docs)
  • **Guides** section expanded with all orphaned user guides
  • ...2 more
v2.57.3
Fixed (2)
  • **RBDS unreliable for stations broadcasting Group 2B (C' blocks)** — When the presync state
  • **RBDS polarity not updated at sync achievement** — After presync achieved sync, `_rbds_inverted_polarity`
v2.57.2
Fixed (7)
  • **Audio monitor shows "No metrics available from audio-service"** — `_sanitize_value()` in
  • **`broadcast_queue` stats never populated** — `collect_metrics()` stored broadcast queue data
  • **EAS monitor status stored as string `"None"` in Redis** — when `_eas_monitor.get_status()`
  • **`routes_eas_monitor_status.py` "invalid type" error** — the non-dict check now returns
  • **Audio monitor VU meter warning hides when sources are running but silent** — the warning
  • **EAS Continuous Monitor badge stays "Loading…" on error** — the status badge is now updated
  • **Source cards show "STOPPED" for unknown status** — when the audio-service is not running,
v2.57.1
Fixed (2)
  • **RBDS crystal-locked carrier phase drift** — `RBDSWorker._pilot_sample_counter` only
  • **Stale RBDS unit tests** — Updated `tests/test_rbds_demodulation.py` to test the current
v2.57.0
Added (5)
  • **Received EAS Alerts log tab** — New "Received EAS" tab on the Logs page shows EAS alerts
  • **EAS activity stat cards** — The Statistics dashboard now shows four new metric cards:
  • **Urgency and Certainty distribution charts** — New "By Urgency" and "By Certainty" bar/doughnut
  • **Received EAS stats in backend** — Stats route now queries `ReceivedEASAlert` and
  • **Received EAS category in All Logs** — The "All Logs" view now includes a "Received EAS"
Fixed (1)
  • **Duration chart `avg_hours` field mismatch** — `createDurationChart()` was reading `i.avg_hours`
v2.56.2
Fixed (3)
  • **504 Gateway Timeout / Gunicorn worker hung in I2C on Raspberry Pi** — Three
  • **Session key inconsistency across Gunicorn workers** (`app.py`). Without
  • **Gunicorn workers crashing on startup when PostgreSQL is not yet ready**
v2.56.1
Fixed (2)
  • **Web stream stall after extended runtime** (`icecast_output.py`) — The source-timeout restart check was gated on the internal buffer being non-empty (`and buffer`). When the audio source stopped supplying data the buffer drained to zero, causing the check to silently skip and leaving a stalled FFmpeg process running indefinitely. The erroneous guard has been removed so the timeout fires correctly regardless of buffer state.
  • **RBDS decoding never locking** (`demodulation.py`) — Two related bugs prevented reliable RBDS carrier lock:
v2.56.0
Changed (7)
  • **Ambient background gradient** — All pages now display a subtle two-orb radial-gradient overlay fixed to the viewport. The gradient is derived from the active theme's `--primary-color` and `--secondary-color` variables, so it automatically adapts across all 20 built-in themes.
  • **Admin card headers** — Replaced the flat `var(--bg-color)` fill with a theme-aware gradient tint (`color-mix` at low opacity against `--surface-color`), giving every section card a subtle accent without obscuring form content.
  • **Admin header banner** — Replaced hardcoded `#667eea / #764ba2` hex values with `var(--primary-color)` / `var(--secondary-color)` so the banner matches the chosen theme. Added a shimmer highlight overlay and a stronger box-shadow for depth.
  • **Admin stat cards** — Replaced hardcoded indigo/purple gradient with theme-aware `var(--primary-color)` → `var(--secondary-color)` gradient. Hover shadow also now uses `color-mix` on the theme primary rather than a hardcoded RGBA.
  • **Admin modal headers** — Replaced the hardcoded red gradient with the theme primary→secondary gradient to align with the rest of the UI.
  • **Manage-card headers** — Applied the same subtle gradient tint treatment as the main card headers for visual consistency.
  • **Form focus glow** — Replaced hardcoded `rgba(102, 126, 234, 0.2)` focus ring with `color-mix(in srgb, var(--primary-color) 20%, transparent)` so the focus state reflects the active theme color.
v2.55.0
Added (1)
  • **Unified Settings hub page** (`/settings`) — All settings sections (Configuration, Network, Hardware, Security & Access) are now presented as a single card-based overview page, making it much easier to discover and navigate to any setting without hunting through nested dropdown menus.
Changed (1)
  • **Settings navbar entry simplified** — The Settings dropdown (which previously contained 15+ nested links across four sections) is replaced by a single "Settings" link that navigates directly to the new unified `/settings` hub page, reducing navbar visual complexity.
v2.54.1
Changed (3)
  • **Merged Hardware dropdown into Settings** - The Hardware navigation item has been removed as a standalone top-level dropdown. All hardware-related links (SDR Receivers, Audio Streams, Audio Archives, Hardware Settings, GPIO & Relays, Zigbee) are now organized under a new "Hardware" section within the Settings dropdown, reducing top-level navigation from 7 to 6 items.
  • **Moved Audio Health to Monitor** - Audio Health dashboard link moved from Tools > Observability to Monitor > Radio Monitoring, where it logically belongs alongside other audio/radio monitoring links.
  • **Removed duplicate Alert Statistics from Tools** - The `/stats` link in Tools > Analytics & Reporting has been removed since Statistics is already accessible from the Monitor dropdown.
v2.54.0
Added (10)
  • **`POST /api/led/set_time_format` endpoint** (v2.54.0)
  • Accepts `time_format` ("TIME_12H" or "TIME_24H"), `color`, and `font` parameters.
  • Calls the LED sign controller to apply the selected 12-hour or 24-hour time format, then sends the current time as a two-line message ("CURRENT TIME" / formatted time string) to the sign.
  • Records the sent message in the `led_messages` database table.
  • Files: `webapp/routes_led.py`
  • **`POST /api/led/set_date_format` endpoint** (v2.54.0)
  • Accepts `date_format` (one of MMDDYY, DDMMYY, MMDDYYYY, DDMMYYYY, YYMMDD, YYYYMMDD), `color`, and `font` parameters.
  • Formats the current date using the requested layout and sends it as a two-line message ("TODAY'S DATE" / formatted date string) to the sign.
  • Records the sent message in the `led_messages` database table.
  • Files: `webapp/routes_led.py`
Changed (4)
  • **LED control frontend buttons now fully functional** (v2.54.0)
  • Removed the "Time/date display feature coming soon" stub and disabled early-returns from `sendTimeDisplay()` and `sendDateDisplay()` in `templates/led_control.html`.
  • `sendDateDisplay()` corrected to call `/api/led/set_date_format` with the `date_format` key instead of the old copy-paste bug that called `/api/led/set_time_format` with `time_format`.
  • Files: `templates/led_control.html`
v2.53.2
Added (21)
  • **CTIA-required opt-out footer in all outgoing EAS alert SMS messages** (v2.53.2)
  • `app_core/notifications/sms.py` now appends `Reply STOP to stop msgs` to every alert message body, satisfying CTIA messaging guidelines that Twilio enforces during toll-free number verification. This footer is required for carrier delivery.
  • Test SMS messages also include `Reply STOP to stop msgs, HELP for help` so test submissions to Twilio reviewers demonstrate compliance.
  • Files: `app_core/notifications/sms.py`
  • **Expanded `/sms-compliance` opt-in disclosure page** (v2.53.2)
  • Added "Sample Message Format" section with an exact mock-up of what EAS alert messages look like (including the new STOP footer), satisfying Twilio's requirement to show a representative message sample on the opt-in page.
  • Added verbatim "Consent Disclosure Language" block (the exact text shown to recipients at opt-in) so Twilio reviewers can verify the opt-in flow.
  • Expanded opt-out keyword table to include all Twilio-standard keywords: STOP, STOP ALL, CANCEL, END, QUIT, UNSUBSCRIBE.
  • Removed Sprint (now T-Mobile) from the carrier list; list now reflects current major carriers.
  • Files: `templates/sms_compliance.html`
  • ...11 more
v2.53.1
Added (83)
  • **AMPR 44.0.0.0/8 Non-Commercial Network Disclaimer** (v2.53.1)
  • Added a prominent non-commercial network notice to `templates/about.html` and `templates/terms.html` for deployments accessible via the AMPRNet (44.0.0.0/8) address block.
  • Added the same notice as Section 13 to `docs/policies/TERMS_OF_USE.md`.
  • Explains FCC Part 97 non-commercial requirements, ARDC allocation policy, and that this service is operated strictly for non-commercial amateur radio research and emergency communications training.
  • Files: `templates/about.html`, `templates/terms.html`, `docs/policies/TERMS_OF_USE.md`
  • **Consistent visual theming across all pages** (v2.52.0)
  • Added the standard `admin-page-header` gradient banner to all 22 admin pages that previously lacked a consistent page header (application_settings, backups, county_boundaries, eas_decoder_monitor, mail_server, notifications, poller, zones, sessions, audio_archives, audio_sdr_fix, audio_sources, radio, radio_diagnostics, certbot, icecast, tailscale, tts, alert_feeds, environment, network, zigbee). Old ad-hoc h1/h2 heading rows removed.
  • Migrated `hardware_settings.html` from the non-admin `.page-header` to `.admin-page-header` for consistent admin section styling.
  • Fixed `index.html` (dashboard): removed the large inline `<style>` block that overrode the global `.page-header` CSS with conflicting padding, border-radius, and child element structure. Updated dashboard page-header HTML to use the canonical standard pattern (matching alerts.html, etc.).
  • Replaced hardcoded hex colors (`#6610f2`, `#6f42c1`) in `.admin-page-header.header-purple` in `static/css/admin.css` with theme-aware CSS variables (`var(--vibrant-indigo)`, `var(--secondary-color)`) so the purple header variant respects the active theme.
  • ...73 more
Fixed (405)
  • **Created missing `docs/javascripts/mermaid-init.js`** (v2.53.1)
  • `mkdocs.yml` referenced `javascripts/mermaid-init.js` as an extra JavaScript file, but the file and its parent directory did not exist, causing a 404 error when building the MkDocs documentation site.
  • Created `docs/javascripts/mermaid-init.js` with proper Mermaid initialization configuration (startOnLoad, theme variables, flowchart and ER diagram options).
  • Files: `docs/javascripts/mermaid-init.js`
  • **Fixed `.bg-light` text readability in dark and coffee themes** (v2.53.1)
  • The `.bg-light` CSS rule hard-coded `color: #212121` (near-black text), which became illegible when the `--light-color` variable resolves to a dark background colour (`#455169` in the dark theme, `#5b4333` in the coffee theme). Added theme-scoped overrides to use `var(--text-color)` and `var(--text-secondary)` for those two dark themes.
  • Files: `static/css/styles.css`
  • **Updated SMS Messaging Policy date** (v2.53.1)
  • Updated the "Last updated" field in `docs/policies/SMS_MESSAGING.md` from a placeholder to the current revision date.
  • Files: `docs/policies/SMS_MESSAGING.md`
  • ...395 more
Changed (44)
  • **Display preview styling with type-specific themes** (PR #1670)
  • Applied type-specific visual themes to display preview and screens templates
  • Files: `templates/displays_preview.html`, `templates/screens.html`
  • **Compact SAME codes and geocodes in multi-column grid layout** (PR #1668)
  • Alert detail page compresses SAME codes and geocodes into a readable multi-column grid
  • Files: `templates/alert_detail.html`
  • **Refactored alert detail layout** (PR #1667)
  • Moved timing and technical information cards from sidebar into main content flow
  • Files: `templates/alert_detail.html`
  • **GPIO configuration UI aligned with Hardware Settings** (PR #1653)
  • ...34 more
Security (16)
  • **CRITICAL: Fix path traversal vulnerability in IPAWS audio serving** (v2.46.4)
  • Added filename sanitization using `os.path.basename()` to prevent directory traversal
  • Added path validation to ensure resolved path is within output directory
  • Changed to use Flask's `send_file()` instead of reading entire file into memory
  • File: `webapp/admin/api.py` - `ipaws_original_audio()` endpoint
  • **CRITICAL: Fix XSS vulnerability in IPAWS web resource URLs** (v2.46.4)
  • Added URL scheme validation to only allow http:// and https:// protocols
  • Prevents javascript: URIs and other malicious schemes from being rendered
  • File: `webapp/admin/api.py` - `_extract_ipaws_display_data()` function
  • **MAJOR: Fix DoS vulnerability in IPAWS audio handling** (v2.46.4)
  • Added configurable size limit (10MB default) via `IPAWS_AUDIO_MAX_BYTES` env var
  • Validates size hint from resource metadata before decoding
  • Estimates decoded size before base64 decode to prevent memory exhaustion
  • Uses strict base64 validation to catch malformed payloads
  • Verifies actual decoded size before writing to disk
  • File: `app_utils/ipaws_enrichment.py` - `save_ipaws_audio()` function
v2.43.4
2024-12-21
Fixed (38)
  • **CRITICAL: RBDS Buffer Management Fixed** - Changed from buffer-draining to index-based bit processing
  • Root cause: `_decode_rbds_groups()` was using `pop(0)` in a `while` loop, consuming ALL bits even during failed presync
  • When presync found valid blocks but spacing verification failed, bits were already consumed and lost
  • This caused constant `buffer=0` in logs and prevented synchronization from ever being achieved
  • Changed to index-based processing (like python-radio reference) that preserves unprocessed bits
  • Bits are only removed from buffer after successful processing or when buffer exceeds 6000 bit limit
  • Failed presync attempts now preserve bits for retry instead of discarding them
  • Added `_rbds_buffer_index` to track position in buffer without destroying data
  • Improved logging: spacing mismatches now show which block types caused the mismatch
  • Reference: https://github.com/ChrisDev8/python-radio/blob/main/decoder.py (lines 235-280)
  • ...28 more
v2.43.0
2024-12-20
Added (63)
  • **Icecast Source Limit Configuration** - Made maximum concurrent sources configurable
  • Added `max_sources` field to `IcecastSettings` database model
  • Web UI field at `/admin/icecast` to configure max concurrent audio sources
  • Supports 0 for unlimited sources, or positive integer for specific limit
  • Updates `/etc/icecast2/icecast.xml` `<sources>` limit automatically
  • Default behavior: If not set (null), Icecast uses its default of 2 sources
  • File: `app_core/models.py`, `webapp/admin/icecast.py`, `templates/admin/icecast.html`
  • **RBDS and Stereo Path Verification** - Comprehensive verification tools and documentation
  • Added `tools/analyze_rbds_stereo_code.py` - Static code analyzer for RBDS/stereo paths
  • Added `tools/trace_rbds_stereo_path.py` - Runtime tracer for signal flow (requires numpy)
  • ...53 more
Fixed (237)
  • **CRITICAL: SDR Audio Source Startup Failure** - Fixed `ModuleNotFoundError: No module named 'app_core.radio.rbds'`
  • Root cause: `FMDemodulator._init_rbds_state()` was trying to import `RBDSDecoder` from non-existent `.rbds` module
  • `RBDSDecoder` class is defined in the same file (`app_core/radio/demodulation.py` line 1662)
  • Removed incorrect import statement on line 297
  • SDR audio sources now start correctly without module import errors
  • Fixes "Audio source is error" message preventing audio monitoring
  • File: `app_core/radio/demodulation.py`
  • **CRITICAL: Hardware Module Import Errors Fixed** - Fixed `ImportError` crashes in VFD and LED modules
  • **VFD**: Removed `VFD_PORT` and `VFD_BAUDRATE` from `app_core/vfd.py` `__all__` exports (not defined as module-level constants)
  • **VFD Routes**: Updated `webapp/routes_vfd.py` to use `get_vfd_settings()` from `app_core.hardware_settings` instead of importing constants
  • ...227 more
Changed (73)
  • **EAS Monitor Architecture** - Major architectural improvement: resample BEFORE queueing
  • Audio now resampled from source rate (48kHz) to 16kHz BEFORE entering EAS queue
  • EAS monitor receives pre-resampled 16kHz audio directly (no conversion needed)
  • Eliminates resampling bottleneck that caused packet drops
  • Reduces queue memory usage by 3x (16kHz vs 48kHz samples)
  • 10000 chunk queue provides ~14 minutes of buffering (same duration at all rates due to resampling)
  • At 48kHz: 10000 chunks × 4096 samples = 40.96M samples / 48kHz = 853 seconds
  • At 16kHz: 10000 chunks × 1365 samples = 13.65M samples / 16kHz = 853 seconds
  • Removed ResamplingBroadcastAdapter dependency - no longer needed
  • Each audio source now has two queues: native rate for streaming, 16kHz for EAS
  • ...63 more
v2.39.0
Added (77)
  • **Poller Settings Admin Page** - New database-based poller configuration interface
  • Created `/admin/poller` page for managing alert poller settings
  • Added `enabled` and `poll_interval_sec` fields to `PollerSettings` model
  • Poller now reads configuration from database instead of environment variables
  • Dynamic interval updates without service restart (checked each poll cycle)
  • Poller can be enabled/disabled via admin UI
  • Links to existing `/logs?type=polling&limit=100` for viewing polling logs
  • Added navigation link in Settings dropdown menu
  • Database migration: `20251218_add_poller_settings.py`
  • Replaces `POLL_INTERVAL_SEC` environment variable with database setting
  • ...67 more
Fixed (258)
  • **Update Script Password Prompts** - Fixed update.sh asking for eas-station user password
  • Added `root ALL=(eas-station) NOPASSWD: ALL` to sudoers configuration
  • Allows root to run commands as eas-station user without password prompt
  • Update.sh now installs/updates sudoers file early in update process
  • Fixed pre-existing sudoers syntax errors (escaped colons in chown commands)
  • Addresses: "The update script is asking for eas-stations password"
  • **Install/Update Scripts Webroot Directory Ownership** - Fixed webroot directory permissions in install.sh and update.sh
  • Changed ownership from www-data:www-data to root:root in both scripts
  • Ensures certbot (runs as root) can write challenge files during initial setup
  • Previously would fail on first webroot certificate attempt after fresh install
  • ...248 more
Changed (26)
  • **Admin Page Refactoring Phase 2 Complete** - Completed modularization of admin.html JavaScript
  • Moved final inline function `sanitizeBoundaryTypeInput` to core.js module
  • Removed outdated comments about remaining inline functions
  • admin.html reduced from original 7,461 lines to 2,043 lines (73% reduction, exceeding 30% target)
  • All JavaScript now modularized into 9 separate files (132KB total) for better maintainability
  • Improved browser caching with external modules
  • Cleaner separation of concerns between template variables and business logic
  • Version bump to 2.38.0 marks completion of Phase 2 refactoring
  • **Admin Page Refactoring - Phase 2 (Major Progress)** - Modular JavaScript extraction
  • ✅ Moved 449 lines of inline CSS to `/static/css/admin.css`
  • ...16 more
v2.36.0
Added (20)
  • **LED Sign IP Address Configuration** - Added IP address and port fields to admin Hardware tab
  • Added `led_ip_address` and `led_port` input fields in admin.html Hardware Integrations tab
  • Updated `/api/led/serial_config` endpoint to save IP address and port to both LEDSignStatus and HardwareSettings tables
  • JavaScript now loads and saves LED IP/port configuration along with serial settings
  • Eliminates confusion about where to configure serial-to-ethernet converter network settings
  • Users can now configure all LED sign settings (IP, port, serial mode, baud rate) in one location
  • **Admin Role Assignment Fix Script** - Added utility script to fix users without roles
  • Created `scripts/fix_admin_roles.py` to assign admin role to users created before roles were initialized
  • Script ensures roles/permissions are initialized and assigns admin role to any user without a role
  • Run with: `python3 scripts/fix_admin_roles.py`
  • ...10 more
Fixed (14)
  • **Hardware Settings Permission Issue** - Fixed "permission denied" error accessing advanced hardware settings
  • Changed `/admin/hardware` permission from `'admin'` (superuser only) to `'system.configure'` (regular admins)
  • Updated navbar to show Hardware Settings link only to users with `system.configure` permission
  • Separated hardware navigation: GPIO/Zigbee for `gpio.view`, Hardware Settings for `system.configure`
  • Eliminated confusion caused by two hardware configuration locations
  • **Zone Catalog Permission Errors** - Fixed 403 permission_denied on Zone Catalog page
  • Changed all zone routes from non-existent `'admin.settings'` to `'system.configure'`
  • Zone catalog now accessible to users with system.configure permission
  • Fixed: Zone info endpoint, zone management page, zone search, zone upload, zone reload
  • **Admin Users Created Without Roles** - Fixed critical issue where admin users show "No Role"
  • ...4 more
v2.34.2
Fixed (4)
  • **Screen Renderer Connection Error Logging** - Reduced log spam from expected connection failures
  • Changed screen_renderer.py to log connection errors at DEBUG level instead of ERROR
  • Connection refused errors are expected when web service isn't running (hardware-only mode)
  • Prevents log spam while still showing unexpected errors
v2.34.1
Fixed (7)
  • **Audio/Icecast Error Logging Fixes** - Resolved excessive error logging and JSON parsing issues
  • Fixed JSON parsing error in websocket audio_monitoring_update caused by improper bytes decoding from Redis
  • Added proper UTF-8 decoding for Redis hgetall() values (redis-py 7.x returns bytes)
  • Added validation to skip empty strings before JSON parsing to prevent "Expecting value" errors
  • Reduced Icecast connection error spam by suppressing repetitive "Connection refused" logs during backoff
  • Improved audio underrun warning frequency with exponential backoff (10, 50, 100, 200, 500, etc.)
  • Added better error handling for invalid heartbeat values in Redis metrics
v2.34.0
Added (29)
  • **Full Web UI for Certbot Operations** - Complete SSL certificate management through web interface
  • Added `/api/certbot/obtain-certificate-execute` endpoint to directly obtain SSL certificates
  • Added `/api/certbot/renew-certificate-execute` endpoint to directly renew certificates
  • Added `/api/certbot/enable-auto-renewal` endpoint to manage systemd timer
  • Users can now obtain, renew, and manage SSL certificates entirely through the web UI
  • Supports standalone, nginx plugin, and webroot certificate acquisition methods
  • Supports dry-run testing, normal renewal, and forced renewal
  • Real-time feedback with certbot output displayed in the UI
  • Enable/disable automatic renewal with one click
  • Added SSL Certificates link to Settings dropdown in navigation menu
  • ...19 more
Fixed (7)
  • **Removed Duplicate Icecast Settings** - Consolidated all Icecast configuration to single location
  • Removed entire Icecast settings section from `/settings/audio` page (lines 131-252 HTML)
  • Removed all Icecast JavaScript functions from audio.html (300+ lines)
  • **All Icecast settings now managed exclusively at `/admin/icecast`**
  • Eliminates confusion from having same settings in multiple locations
  • Cleaner UI with single source of truth for Icecast configuration
  • Addresses new requirement to consolidate settings to one spot
v2.33.1
Added (107)
  • **Icecast Password Management Improvements** - Transformed password handling to read-only display with regenerate option
  • Password fields now read-only to prevent user errors and mismatches with Icecast server
  • Added password masking with show/hide toggle buttons for security
  • Added copy-to-clipboard functionality for easy password access
  • Added informational text explaining passwords are auto-generated during installation
  • Added regenerate password functionality that updates database, .env file, AND Icecast server config
  • New endpoint `/admin/api/icecast/regenerate-passwords` for secure password regeneration
  • **CRITICAL: Now updates Icecast server configuration file** (`/etc/icecast2/icecast.xml`)
  • Automatically restarts Icecast service after password regeneration
  • Handles default passwords (changeme_admin) by updating server config
  • ...97 more
Fixed (350)
  • **Certbot/SSL Certificate Management Security Fix** - Removed sudo calls from web interface
  • Removed all `sudo certbot` subprocess calls from web application for security compliance
  • Web interface now provides copy-paste commands instead of executing privileged operations
  • Added systemd timer status checking for automatic certificate renewal
  • Updated UI to display certificate acquisition instructions with multiple methods (standalone, nginx, webroot)
  • Added copy-to-clipboard functionality for certificate management commands
  • Provides clear guidance on manual certificate operations via command line
  • Fixes "no new privileges" flag error when attempting sudo from web app
  • Maintains certificate status checking functionality (read-only operations)
  • Addresses security concern of web application having elevated privileges
  • ...340 more
Changed (66)
  • **Environment Variables Cleanup** - Removed redundant settings that are now managed via dedicated admin pages
  • Removed 'gpio' category from environment variables (now managed via `/admin/hardware`)
  • Removed 'icecast' category from environment variables (now managed via `/admin/icecast`)
  • Removed duplicate 'notifications' category that contained SDR/audio settings
  • GPIO, OLED, LED, VFD, and Icecast settings exclusively managed through database-backed admin UIs
  • Cleaner environment configuration focused on core application settings
  • VERSION bumped to 2.31.0 (feature enhancement)
  • **Documentation Update** - Comprehensive review and updates across all documentation
  • Updated all main architecture documents with current timestamps (2025-12-16)
  • Updated INDEX.md statistics: 92 total files (was 47), 12 guides (was 6), 18 architecture docs (was 10), 19 troubleshooting guides (was 10)
  • ...56 more
v2.21.0
2025-12-12
Fixed (8)
  • Copy button label on logs page changed from "Copy Logs" to "Copy" for clarity
  • CSV export button relabeled to "Excel" to match user terminology
  • CSV export icon changed from `fa-file-csv` to `fa-file-excel`
  • Update script (`update.sh`) now properly displays VERSION file contents instead of showing "unknown"
  • Update script now prioritizes VERSION file over git commit hash for version display
  • Updated POLLER_CONFIG_MIGRATION.md to clarify unified poller architecture
  • Removed outdated references to separate `ipaws.env` and `noaa.env` files (no longer used in 2.20+)
  • Added troubleshooting section for "IPAWS.env not found" error
Changed (8)
  • **Environment variable consolidation** - Reduced from 93 to 73 variables by consolidating related settings
  • `MAIL_URL` replaces 5 mail variables (MAIL_SERVER, MAIL_PORT, MAIL_USERNAME, MAIL_PASSWORD, MAIL_USE_TLS)
  • `LOCATION_CONFIG` (JSON) replaces 9 location variables (DEFAULT_TIMEZONE, DEFAULT_COUNTY_NAME, DEFAULT_STATE_CODE, DEFAULT_ZONE_CODES, DEFAULT_FIPS_CODES, DEFAULT_STORAGE_ZONE_CODES, DEFAULT_MAP_CENTER_LAT, DEFAULT_MAP_CENTER_LNG, DEFAULT_MAP_ZOOM)
  • `ICECAST_CONFIG` (JSON) replaces 5 Icecast auth variables (ICECAST_SOURCE_PASSWORD, ICECAST_RELAY_PASSWORD, ICECAST_ADMIN_USER, ICECAST_ADMIN_PASSWORD, ICECAST_ADMIN)
  • `ICECAST_INTERNAL_URL` and `ICECAST_PUBLIC_URL` replace 4 connection variables (ICECAST_SERVER, ICECAST_PORT, ICECAST_EXTERNAL_PORT, ICECAST_PUBLIC_HOSTNAME)
  • `AZURE_OPENAI_CONFIG` (JSON) replaces 5 Azure OpenAI variables (AZURE_OPENAI_ENDPOINT, AZURE_OPENAI_KEY, AZURE_OPENAI_MODEL, AZURE_OPENAI_VOICE, AZURE_OPENAI_SPEED)
  • VERSION bumped to 2.21.0
  • VERSION bumped to 2.20.2
v2.20.1
2025-12-11
Changed (22)
  • **Enhanced PyCharm integration documentation** - Added comprehensive field-by-field setup instructions in `docs/guides/PYCHARM_DEBUGGING.md`
  • Added detailed tables for every configuration dialog with all fields explained
  • Added example values for each field with explanations
  • Added step-by-step Database Tools (DataGrip) configuration
  • Added step-by-step Debug Configuration setup for AI coding assistants
  • Added validation checklist for complete PyCharm setup
  • Added "Quick Start" section with essential settings table for rapid configuration
  • **Added comprehensive GitHub Copilot integration section** - Detailed comparison with zencoder.ai
  • Added GitHub Copilot setup instructions for PyCharm and VS Code
  • Added capability comparison table (Copilot vs zencoder.ai)
  • ...12 more
v2.20.0
2025-12-11
Added (7)
  • **Complete whiptail-based setup** - All installation inputs now use professional TUI interface
  • **FIPS code checklist interface** - Select multiple counties at once instead of typing
  • **Radio button menus** - EAS Originator code selection with predefined options (WXR, EAS, PEP, etc.)
  • **Consistent branding** - Copyright and license info on all whiptail dialogs throughout install.sh
  • **FIPS management in eas-config** - Configure FIPS codes post-installation with same checklist UI
  • Branding footer function for consistent copyright/license display
  • Improved Python environment detection for FIPS lookup during installation
Fixed (3)
  • FIPS lookup now gracefully handles case where Python dependencies aren't installed yet
  • Better validation for all user inputs with helpful error messages
  • Consistent dialog widths and heights for better readability
Changed (5)
  • **FIPS lookup workflow** - Now shows full county list with checkboxes instead of search-based approach
  • EAS Originator input changed from text entry to radio button selection for better validation
  • All whiptail dialogs now include branding footer with copyright and license information
  • Improved error messaging when Python environment isn't available during installation
  • Enhanced user experience with clearer instructions and better dialog sizing
v2.19.12
2025-12-11
Added (7)
  • Added "All Logs" tab as the default view with organized category sections
  • Added collapsible accordion sections for each log category (System, Polling, Audio, GPIO, EAS Messages, etc.)
  • Added category badges showing log count per category
  • Logs now organized by category instead of mixed together chronologically
  • Added automatic firewall configuration for Icecast port 8000 during installation
  • Added firewall configuration summary in installation completion message
  • Added instructions for optionally opening PostgreSQL port with security warnings
Fixed (4)
  • Fixed logs page to display ALL logs instead of only categorized logs
  • Fixed Bootstrap modal aria-hidden accessibility warnings when adding/editing audio sources
  • Fixed potential focus trap issues preventing interaction with audio source modals
  • Fixed missing firewall rules for Icecast streaming (port 8000)
Changed (6)
  • Default logs view changed from "System" to "All Logs" for better visibility
  • "All Logs" view now uses accordion with category grouping for better organization
  • Modal elements now properly blur focus before hiding to prevent accessibility issues
  • Improved log readability by separating logs into logical categories
  • Installation now automatically opens port 8000 for Icecast if enabled
  • Firewall status display now shows configured ports
v2.19.11
2025-12-10
Added (9)
  • **PostgreSQL password now displayed during installation** for easy IDE/pgAdmin access
  • Added comprehensive database credentials section in installation completion message
  • Shows full PostgreSQL connection details (host, port, database, username, password)
  • Added instructions for viewing password later: `sudo grep POSTGRES_PASSWORD /opt/eas-station/.env`
  • Enhanced installation progress messages with detailed package lists
  • Added informative descriptions of what each installation step does
  • More aesthetic progress indicators showing estimated time and package counts
  • pgAdmin access instructions (if successfully installed) in completion message
  • Separate database credentials section with security warnings
Fixed (3)
  • Fixed pgAdmin 4 installation failures by adding better error handling and --allow-downgrades flag
  • Fixed pgAdmin installation to gracefully skip if it fails, allowing installation to continue
  • Added error detection and informative messages for pgAdmin installation issues
Changed (6)
  • Installation completion message now includes full database credentials for IDE access
  • Made install.sh significantly more informative and user-friendly
  • Enhanced progress messages to show what packages are being installed
  • Improved visual hierarchy in completion message sections
  • pgAdmin configuration skips gracefully if installation failed
  • Database password warning emphasizes saving credentials (only shown once)
v2.19.10
2025-12-10
Added (4)
  • Systemd service monitoring for all EAS Station services (web, sdr, audio, eas, hardware, noaa-poller, ipaws-poller)
  • Dependency service monitoring (nginx, postgresql, redis-server, icecast2)
  • Service status categorization (active, inactive, failed) with visual indicators
  • Separate display sections for EAS Station services vs. system dependencies
Fixed (3)
  • Removed Docker/container monitoring from system health in favor of systemd service monitoring
  • System health now queries systemd services directly using systemctl for accurate bare metal deployment status
  • Updated system health template to display systemd services instead of Docker containers
Changed (4)
  • Replaced _collect_container_statuses() with _collect_systemd_services() in system.py
  • System health data structure now uses "systemd" key instead of "containers"
  • Service monitoring now uses native systemctl commands instead of Docker API
  • Health dashboard shows systemd service status with active/inactive/failed states
v2.19.9
2025-12-10
Fixed (10)
  • Reduced excessive whitespace between navbar and page content by decreasing --layout-padding-top from 1.5rem to 0.5rem
  • Fixed NOAA_USER_AGENT validation error by adding default value in environment.py configuration
  • Fixed environment validation to check default values before reporting "required but not set" errors
  • Updated setup wizard configuration persistence notice to remove Docker/container-specific references
  • Changed setup wizard text to reflect bare metal deployment with /app-config/.env persistent volume
  • Removed Docker-specific terminology from about.html (changed "containers" to "services")
  • Removed Docker-specific terminology from admin.html (container references, --network=host flag)
  • Updated admin panel text to be deployment-agnostic (removed "inside the app container" references)
  • Removed hardcoded version number from NOAA_USER_AGENT default value to prevent version drift
  • Changed "System Reinstall" to "Fresh Installation" in setup wizard for clarity
Changed (5)
  • Updated setup wizard to show accurate configuration persistence behavior for bare metal deployments
  • Environment validation now respects default values defined in ENV_CATEGORIES when checking required fields
  • About page now uses deployment-agnostic terminology for service architecture
  • Admin panel now uses terminology appropriate for both Docker and bare metal deployments
  • NOAA_USER_AGENT default value no longer includes version number (simplified to "EAS Station")
v2.19.8
2025-12-10
Changed (14)
  • Completely rewrote PyCharm/VS Code debugging guide for bare metal deployment
  • Removed all Docker/container references, replaced with systemd service instructions
  • Updated all file paths from /home/pi/eas-station to /opt/eas-station
  • Added comprehensive section on debugging individual systemd services with debugpy
  • Added detailed instructions for using AI coding agents (ZenCoder) with real-time code access
  • Updated database configuration section for bare metal PostgreSQL (not containerized)
  • Added multiple methods for enabling debugpy: temporary, persistent, and code modification
  • Documented debug port assignments for all services (5678-5684)
  • Added SSH port forwarding instructions for secure remote debugging
  • Updated troubleshooting section with systemd-specific solutions
  • ...4 more
Security (5)
  • Added security warnings for exposing debugpy ports on all network interfaces
  • Documented SSH port forwarding as secure alternative to opening firewall ports
  • Improved PostgreSQL remote access documentation with security best practices
  • Restricted sudoers examples to specific services and journalctl units only
  • Clarified user permissions for AI agent integration with minimal necessary access
v2.19.7
2025-12-10
Fixed (7)
  • Fixed pgAdmin4 installation to prevent apache2 from being installed as a dependency
  • Added python3-typer package installation to resolve "ModuleNotFoundError: No module named 'typer'" in pgAdmin setup
  • Added apt preferences to block apache2 packages during pgadmin4 installation
  • Added automatic apache2 masking and removal if already installed
  • Fixed remote access by configuring UFW firewall to allow ports 80 (HTTP) and 443 (HTTPS)
  • Added firewall configuration section in install.sh with proper UFW setup
  • Improved installation reliability with better dependency management
v2.19.6
2025-12-10
Changed (8)
  • Enhanced install.sh with improved visual design and user experience
  • Added colorful banner, progress indicators, and step counters
  • Enhanced completion message with detailed component access instructions
  • Added comprehensive post-installation checklist with actionable items
  • Improved readability with emoji icons, better spacing, and color-coded sections
  • Added detailed connection instructions for all components (web UI, pgAdmin, PostgreSQL, Redis)
  • Included useful commands for backup, restore, SSL setup, and troubleshooting
  • Suppressed verbose output from package installations for cleaner display
v2.19.5
2025-12-10
Fixed (4)
  • Fixed PostgreSQL authentication configuration in `install.sh` to allow password-based connections
  • Added `pg_hba.conf` configuration to enable `scram-sha-256` authentication for `eas_station` user
  • Updated `scripts/database/fix_database_permissions.sh` to also configure PostgreSQL authentication
  • Resolves "password authentication failed for user eas_station" errors during installation
v2.19.4
2025-12-10
Changed (7)
  • Updated architecture documentation to reflect bare-metal systemd deployment
  • Replaced "container" terminology with "service" or "process" in architecture docs
  • Replaced "Docker" references with "systemd service" or "bare-metal" as appropriate
  • Updated mermaid chart labels in `SYSTEM_ARCHITECTURE.md` from container to service
  • Updated `HARDWARE_ISOLATION.md` with systemd service terminology and journalctl commands
  • Updated `DATA_FLOW_SEQUENCES.md` to reflect systemd service architecture
  • Aligned all documentation with ISO_BUILD_READY.md bare-metal migration status
v2.19.3
2025-12-10
Added (3)
  • Added `samples/README.md` documenting EAS test audio files and their purpose
  • Added comprehensive `legacy/README.md` explaining Docker-era scripts and their bare-metal replacements
  • Added `tests/bug_reproductions/README.md` explaining one-off test files
Changed (3)
  • Updated `install.sh` to exclude development directories: `bugs/`, `legacy/`, `bare-metal/`, `tests/bug_reproductions/`
  • Updated `.gitignore` to exclude `bugs/` and `tests/bug_reproductions/` from version control
  • Cleaned samples directory to ~6.2MB (only EAS audio test files remain)
v2.19.2
2025-12-10
Added (2)
  • Added Redis server health check to `/health/dependencies` endpoint
  • Created new bare-metal version of `scripts/collect_sdr_diagnostics.sh` using systemd and native tools
Changed (3)
  • Updated `webapp/routes_monitoring.py` to check Redis instead of Docker daemon
  • Updated comment in `webapp/routes_settings_radio.py` to remove Docker architecture reference
  • SDR diagnostics now use systemd service status and journalctl for logs instead of Docker commands
v2.19.1
2025-12-10
Added (3)
  • Added **Frontend-First Philosophy** to AI agent guidelines: All system management must be web-accessible
  • Added **CLI-Free Operations** requirement: Users should never need SSH or command-line access
  • Documented existing web UI features for logs, configuration, services, and troubleshooting
Changed (5)
  • Updated `docs/installation/INSTALLATION_DETAILS.md` to remove Docker references
  • Updated `docs/troubleshooting/AUDIO_SQUEAL_FIX.md` to note it's for legacy Docker deployments
  • Updated `scripts/README.md` to remove references to deleted SQL files
  • Updated `webapp/routes_ipaws.py` to use systemd commands for service restarts instead of Docker
  • Updated `webapp/routes_monitoring.py` to remove docker-compose.yml from configuration checks
v2.19.0
2025-12-10
Changed (3)
  • Updated troubleshooting guides to use systemd commands exclusively
  • Updated architecture documentation to reflect bare-metal deployment
  • Simplified migration guides to focus on bare-metal setup
v2.18.0
2025-12-10
Fixed (3)
  • Maintenance API uses standard filesystem paths instead of container paths
  • Complete installation guide available in `bare-metal/README.md`
  • Quick start guide available in `bare-metal/QUICKSTART.md`
Changed (3)
  • Updated README.md to focus on bare metal deployment via systemd services
  • Configuration now uses `/opt/eas-station/.env` as standard location
  • Services managed via systemd: `sudo systemctl [start|stop|restart] eas-station.target`
v2.17.2
2025-12-09
Fixed (10)
  • **EAS Monitor Display Issues**: Fixed decoding rates showing >100% and display bouncing between states
  • Root cause 1: Rate calculation `samples_per_second` was sensitive to timing variations and could spike >100%
  • Root cause 2: During startup (first 2 seconds), rate calculation reported 0, triggering "no audio" warnings
  • Root cause 3: Frontend hysteresis (2 consecutive readings) wasn't enough to prevent flicker at 100ms WebSocket rate
  • Fix 1: Added exponential moving average (EMA) smoothing with alpha=0.3 to filter timing noise
  • Fix 2: Implemented 2-second minimum sample threshold - report expected rate during warmup instead of 0
  • Fix 3: Health percentage grows linearly 0-95% during warmup for smooth visual feedback
  • Fix 4: Increased frontend hysteresis from 2 to 5 consecutive readings (500ms stability required)
  • Fix 5: Properly clamp health_percentage to [0, 1] range in all code paths
  • Result: Rates never exceed 100%, smooth warmup transition, no state bouncing
Changed (6)
  • **Code Quality**: Extracted magic numbers to named class constants for easier configuration
  • `WARMUP_DURATION_SECONDS = 2` - Duration of warmup period
  • `WARMUP_MAX_HEALTH_PERCENTAGE = 0.95` - Maximum health shown during warmup
  • `RATE_SMOOTHING_ALPHA = 0.3` - EMA smoothing factor (lower=smoother, higher=more responsive)
  • `AUDIO_FLOWING_STABILITY_THRESHOLD = 5` - Frontend consecutive readings before state change
  • Improves maintainability and makes performance tuning easier
v2.17.1
2025-12-09
Fixed (14)
  • **CRITICAL: WebSocket Support Broken**: Fixed Flask-SocketIO async_mode mismatch that prevented WebSockets from working
  • Root cause: `app.py` used `async_mode='threading'` but gunicorn uses `--worker-class gevent`
  • This mismatch caused WebSockets to FAIL SILENTLY and fall back to long-polling
  • Fix: Changed `async_mode='threading'` to `async_mode='gevent'` to match gunicorn worker class
  • Impact: Enables real-time WebSocket updates at 10Hz (100ms) instead of 1-2 second polling intervals
  • This fixes why the entire site was polling despite WebSocket infrastructure being present
  • **UI White Space**: Fixed excessive white space at top of pages caused by `flex: 1` on `.page-shell`
  • Root cause: Flexbox layout with `flex: 1` caused content to expand and fill all vertical space
  • Fix: Removed `flex: 1` from `.page-shell` - footer's `margin-top: auto` handles sticky footer
  • Result: Pages now start content immediately after navbar without huge gaps
  • ...4 more
Changed (8)
  • **WebSocket Infrastructure**: Audio monitoring page already uses WebSockets when available
  • VU meters, EAS monitor, and broadcast stats all receive real-time updates via WebSocket
  • System automatically falls back to polling only if WebSocket connection fails
  • With this fix, WebSockets should now work properly and polling fallback won't be needed
  • This fixes the root cause of why 10+ previous agent sessions couldn't solve the white space issue
  • The white space issue was subtle - `flex: 1` is a common flexbox pattern but caused unwanted expansion
  • The WebSocket issue explains why 32 setInterval() polling calls exist throughout the codebase
  • Future work: Extend WebSocket push service to broadcast all data types (alerts, system health, etc.) to eliminate remaining polling
v2.16.5
2025-12-09
Fixed (4)
  • **Application Startup Failure**: Fixed unterminated triple-quoted string literal in `webapp/admin/audio_ingest.py` at line 2237
  • Root cause: Docstring for legacy `generate_wav_stream()` function was never closed
  • This prevented database migrations from running and caused gunicorn workers to crash on startup
  • Fix: Properly closed the docstring and commented out the legacy code inside the function
v2.16.3
2025-12-09
Fixed (11)
  • **EAS Monitor Runtime Display**: Fixed runtime timer showing "0s" and buffer bar not filling on Audio Monitoring page
  • Root cause: API endpoint was not passing `wall_clock_runtime_seconds` from the audio-service metrics
  • Fix: Added `wall_clock_runtime_seconds` to the API response in `routes_eas_monitor_status.py`
  • **Audio Detail Page Error**: Fixed "Unable to load audio detail at this time" error when viewing IPAWS-generated alerts
  • Root cause: Template used `url_for('alert_detail', ...)` but the route is on the `api` blueprint
  • Fix: Changed to `url_for('api.alert_detail', ...)` in `audio_detail.html`
  • **Layout Spacing**: Reduced global `--layout-padding-top` from `1.5rem` to `0.5rem` to minimize gap between navbar and content
  • **Audit Logs UI**: Fixed stat-card styling conflict where global vibrant gradient styles were overriding the audit logs page local styles
  • Added more specific CSS selectors (`.stats-row .stat-card`) to ensure local styles take precedence
  • Used `!important` flags to override global pseudo-elements that added shimmer/glow effects
  • ...1 more
v2.16.2
2025-12-09
Fixed (9)
  • **Code Quality**: Fixed bare `except:` clauses in multiple files for PEP 8 compliance:
  • `scripts/run_radio_manager.py`: Added proper exception logging during cleanup
  • `debug_airspy.py`: Changed bare `except:` to `except Exception:` with comments
  • **Defensive Coding**: Added None checks for `fetchone()` calls in migration and utility scripts:
  • `scripts/apply_source_type_migration.py`: Safe handling when column check returns no result
  • `app_core/migrations/versions/20251105_add_rbac_and_mfa.py`: Safe handling when INSERT RETURNING fails
  • `app_core/migrations/versions/20251116_populate_oled_example_screens.py`: Safe handling for screen insert
  • **Architecture Review**: Reviewed all 17 bugs from ARCHITECTURE_REVIEW_BUGS.md - most critical bugs (1-14) were already fixed in codebase
  • Remaining bugs are low-priority design issues or already addressed
v2.16.1
2025-12-09
Fixed (4)
  • **Dashboard Layout**: Removed duplicate `page-shell` class from dashboard container that caused large gap at top of page
  • Root cause: `page-shell` was applied to both `<main>` in base.html and inner container in index.html
  • This resulted in double top padding (from both elements)
  • Fix: Removed redundant `page-shell` class from inner `<div class="container-fluid">` in index.html
v2.16.0
2025-12-08
Changed (9)
  • **BREAKING: Service Renaming - Clean Architecture**
  • Renamed `audio_service.py` → `eas_monitoring_service.py` (reflects actual purpose)
  • Renamed `sdr_service.py` → `sdr_hardware_service.py` (clarifies exclusive hardware access)
  • **Why**: Old names were confusing and led to architectural mistakes
  • **No backward compatibility wrappers** - clean break for clarity
  • `eas_monitoring_service.py`: New name for EAS monitoring + audio processing service
  • `sdr_hardware_service.py`: New name for SDR hardware access service
  • `RENAME_SERVICES.md`: Updated to reflect completed rename
  • Old files (`audio_service.py`, `sdr_service.py`) removed completely
v2.15.5
2025-12-08
Fixed (12)
  • **CRITICAL: Complete SDR Hardware Separation**: Removed ALL SDR hardware access from audio-service.py
  • **Root Cause**: Both audio-service and sdr-service were fighting for USB access to SDR hardware
  • Removed `initialize_radio_receivers()` functionality from audio-service (kept stub for backward compat)
  • Removed RadioManager initialization and all `_radio_manager` references
  • Removed process_commands() SDR hardware operations (restart, get_spectrum, discover_devices)
  • Removed collect_metrics() radio_manager stats collection
  • Removed spectrum publishing loop with direct IQ sample access
  • **Result**: audio-service.py now ONLY subscribes to Redis channels from sdr-service
  • **Impact**: SDR hardware access is now exclusive to sdr-service.py container
  • **Why SDR Never Worked**: Both containers tried to open same USB devices → conflict
  • ...2 more
v2.15.4
2025-12-08
Fixed (8)
  • **Code Quality: Removed Bare Except Statements**: Fixed 4 bare `except:` statements that could mask errors
  • `app_core/audio/eas_monitor.py`: Database rollback and SAME header parsing now log errors
  • `app_core/audio/streaming_same_decoder.py`: Message validation errors now logged at debug level
  • `app_core/audio/worker_coordinator_redis.py`: Redis connection close errors now logged
  • All exceptions now specify expected types (IndexError, AttributeError, Exception)
  • Improves debugging by making error paths visible in logs
  • Follows Python best practices for exception handling
  • **Impact**: Better error visibility and easier troubleshooting
v2.15.3
2025-12-08
Fixed (15)
  • **CRITICAL: Multi-Stream EAS Monitoring (LP1, LP2, SP1)**: Implemented per-source EAS monitoring
  • **Root Cause**: EAS monitor only listened to ONE audio source at a time (highest priority)
  • AudioIngestController.broadcast_pump selected only the highest priority running source
  • Main broadcast queue received audio from only ONE source, others were ignored
  • Result: LP1, LP2, SP1 web streams ran successfully but only ONE was monitored for EAS
  • **Fix**: Changed from single EAS monitor to per-source monitors (one for each stream)
  • Each audio source now has its own dedicated EAS monitor instance
  • All sources monitored simultaneously for SAME/EAS alerts
  • Alerts include source name in metadata for proper attribution
  • **Why IPAWS worked**: IPAWS uses internet polling (cap_poller.py), not audio monitoring
  • ...5 more
v2.15.2
2025-12-08
Added (4)
  • **Diagnostic Tools**: Created comprehensive audio chain diagnostic utilities
  • `diagnose_audio_chain.py` - Full audio chain health check from SDR to EAS monitor
  • `fix_audio_source_sync.py` - Manual audio source sync tool with dry-run support
  • Both tools check receivers, audio sources, Redis connectivity, and IQ sample flow
Fixed (10)
  • **CRITICAL: Audio Chain for SDR Sources (LP1, LP2, SP1)**: Fixed missing audio pipeline for SDR-based EAS monitoring
  • Added automatic audio source synchronization on audio-service startup
  • Previously, audio sources for radio receivers weren't created automatically, breaking the audio chain
  • In separated architecture, sdr-service publishes IQ samples to Redis, but audio-service needs AudioSourceConfigDB entries
  • Without these entries, RedisSDRSourceAdapter instances weren't created, preventing audio from reaching EAS monitor
  • New `sync_radio_receiver_audio_sources()` function ensures audio sources exist for all enabled receivers
  • Sets critical `managed_by='radio'` flag to trigger Redis adapter creation
  • Enhanced logging shows receiver details, subscription channels, and startup status
  • Affects LP1, LP2, SP1 and any other SDR receivers with audio_output=True
  • **Impact**: Fixes complete loss of EAS monitoring from local/state primary SDR sources
v2.15.1
2025-12-08
Fixed (4)
  • **Template Consistency**: Fixed deprecated block usage in zigbee.html template, resolving CI failures
  • Changed `templates/settings/zigbee.html` from deprecated `{% block extra_js %}` to standard `{% block scripts %}`
  • Ensures all templates consistently use the `scripts` block for page-specific JavaScript
  • Fixes template consistency check CI workflow that was failing
v2.15.0
2025-12-08
Changed (5)
  • Network error displays now show hint and technical details
  • Password input now includes real-time validation
  • Confirmation dialogs provide more context for destructive actions
  • Netmask dropdown now shows common use cases
  • DNS server input includes popular server recommendations
v2.14.0
2025-12-08
v2.13.5
2025-12-08
Fixed (16)
  • **CRITICAL WiFi BUG**: Fixed WiFi scanning returning no networks even when networks available
  • Added nmcli availability check - prevents silent failures when NetworkManager not installed
  • Added WiFi interface auto-detection - finds wlan0/wlp* interfaces dynamically instead of hardcoded assumptions
  • Fixed network status endpoint - now returns correct data structure with wifi.ssid that frontend expects
  • Fixed WiFi scan race condition - replaced arbitrary 2-second sleep with proper completion detection
  • Fixed disconnect functionality - backend now auto-detects active connection name instead of requiring frontend to send it
  • Fixed empty scan results handling - now properly detects and reports when no networks found vs. scan failure
  • Enhanced error handling and logging throughout WiFi operations
  • Frontend now properly parses backend network status response structure
  • Frontend disconnect sends empty body (backend auto-detects connection)
  • ...6 more
v2.13.4
2025-12-07
Fixed (7)
  • **CRITICAL SEPARATION MISMATCH**: Fixed audio-service startup failing to load SDR sources from database
  • audio-service was trying to create SDRSourceAdapter for `source_type='sdr'` but had no radio manager (separated architecture)
  • Added detection: if source is radio-managed (`managed_by='radio'`), create RedisSDRSourceAdapter instead
  • Now audio-service properly loads SDR sources on startup and subscribes to IQ samples from sdr-service
  • ✅ Audio sources persist across audio-service restarts
  • ✅ No more "SDR source not available - radio manager missing" errors
  • ✅ Separated architecture fully functional at startup
v2.13.3
2025-12-07
Fixed (7)
  • **CRITICAL AUDIO BUG**: Fixed source_type mismatch preventing audio from playing and Icecast mounts from appearing
  • `ensure_sdr_audio_monitor_source` was sending `source_type: 'sdr'` but audio-service expected `'redis_sdr'` for separated architecture
  • Result: RedisSDRSourceAdapter was never created, no audio demodulation happened, no Icecast mount appeared
  • Changed to `source_type: 'redis_sdr'` so audio-service properly creates Redis IQ subscriber and Icecast output
  • ✅ Audio now plays from SDR receivers
  • ✅ Icecast mounts now appear (e.g., /receiver.mp3)
  • ✅ Complete end-to-end audio pipeline working
v2.13.2
2025-12-07
Fixed (9)
  • **CRITICAL END-TO-END**: Complete signal chain from detection to audio now works
  • **Device Discovery**: Added `discover_devices` command handler in sdr-service
  • **Receiver Creation**: Added `reload_receivers` command to sync database changes to sdr-service
  • **Auto-Start**: New/updated receivers now automatically loaded by sdr-service
  • Webapp now properly communicates with sdr-service for device discovery and receiver management
  • _sync_radio_manager_state now tells sdr-service to reload configuration
  • Fallback to app-side radio manager if sdr-service unavailable
  • Better error handling and logging throughout signal chain
  • Device enumeration works in separated architecture
v2.13.1
2025-12-07
Fixed (9)
  • **CRITICAL AIRSPY BUG**: AirspyReceiver class was completely empty with NO Airspy-specific configuration
  • **Airspy Never Worked**: Device would never get warm because no samples were being processed correctly
  • Implemented proper `_open_handle()` override with Airspy R2 sample rate validation (2.5 MHz or 10 MHz only)
  • Configured linearity gain mode for optimal strong signal handling (FM/NOAA)
  • Added Bias-T safety (disabled by default to prevent equipment damage)
  • Airspy R2 TCXO provides accurate frequency - no PPM correction needed
  • Comprehensive Airspy R2 configuration logging
  • Sample rate validation with clear error messages
  • Better exception handling for Airspy-specific settings
v2.13.0
2025-12-07
Added (4)
  • **MAJOR FEATURE**: PPM (Parts Per Million) frequency correction support for compensating crystal oscillator drift in SDRs
  • Added `frequency_correction_ppm` field to RadioReceiver model and database schema
  • Hardware frequency readback verification with mismatch warnings
  • Comprehensive frequency tuning diagnostics and logging
Fixed (6)
  • **Frequency Accuracy**: RTL-SDR and other low-cost SDRs now properly compensate for clock drift (typically ±50 PPM)
  • **Tuning Verification**: Actual tuned frequency is now logged and verified against requested frequency
  • **Diagnostic Logging**: Frequency settings, PPM correction, and readback values now logged for troubleshooting
  • Frequency accuracy can now be calibrated using PPM correction (e.g., calibrate with GSM cell tower or known station)
  • Mismatch warnings help identify hardware tuning issues (> 1 kHz error triggers warning)
  • Better separation: PPM correction in `ReceiverConfig` dataclass, not just database
v2.12.27
2025-12-07
Fixed (2)
  • **CRITICAL Demodulation Bug**: Added missing `process()` method to FMDemodulator and AMDemodulator classes that was being called by RedisSDRSourceAdapter but didn't exist, causing audio demodulation to fail completely
  • Fixed method signature mismatch where redis_sdr_adapter.py called `demodulator.process()` but only `demodulate()` existed, preventing any audio from being generated from IQ samples
v2.12.26
2025-12-07
Fixed (9)
  • **SDR Core**: Implemented missing `get_ring_buffer_stats()` method in `_SoapySDRReceiver` that was being called by sdr_service.py but didn't exist, causing silent failures in buffer health monitoring
  • **SDR Core**: Integrated SDRRingBuffer initialization in receiver startup to enable proper USB jitter absorption and backpressure handling
  • **SDR Core**: Ring buffer now properly instantiated when device opens, providing robust sample buffering for reliable 24/7 SDR operation
  • **SDR Core**: Capture loop now writes samples to ring buffer for overflow detection and backpressure monitoring
  • **SDR Core**: Ring buffer properly shut down when receiver stops, preventing resource leaks
  • Enhanced ring buffer statistics reporting with fallback to simple buffer stats when SDRRingBuffer unavailable
  • Added comprehensive buffer health metrics (overflow/underflow counts, fill percentage, total samples) to Redis
  • Improved separation between app.py and SDR service - all SDR operations completely independent of Flask application
  • Ring buffer overflow detection now logs dropped samples when processing can't keep up with USB data rate
v2.12.25
2025-12-05
Fixed (3)
  • **CRITICAL**: Fixed audio sources not starting when clicking start button - source name mismatch between webapp and audio-service (webapp sends "WIMT", audio-service expected "redis-WIMT")
  • Fixed race condition in metrics publishing where audio-service was deleting eas_monitor metrics from Redis causing "No metrics available from audio-service" error
  • Audio-service now uses original source names (not prefixed with "redis-") for separated architecture compatibility
v2.12.24
2025-12-05
Fixed (1)
  • Fixed audio-service container running Flask app.py during migrations by skipping database migrations in standalone service containers (audio-service, sdr-service, eas-service, hardware-service) that should not load the main Flask application
v2.12.23
2025-12-05
v2.12.22
2025-12-05
Fixed (2)
  • Fixed AirspyReceiver method override bug where `_open_device()` was defined but parent class uses `_open_handle()`, preventing Airspy-specific configuration (sample rate validation, linearity mode, bias-T settings) from ever executing
  • Added `get_ring_buffer_stats()` method to SDR receivers to fix method-not-found errors when SDR service attempts to publish ring buffer statistics to Redis
v2.12.21
2025-11-27
Added (5)
  • Made SDR++ Server the default and recommended SDR option in the Radio Receiver settings UI
  • Added prominent "SDR++ Server" quick-add button in the Quick Setup panel
  • SDR++ Server now appears as the first option in the device selection dropdown
  • Updated documentation (SDR Setup Guide) with comprehensive SDR++ Server setup instructions
  • Added SDR++ Server to the hardware comparison table and configuration examples
Changed (3)
  • Reordered SDR presets to prioritize SDR++ Server (network SDR) over direct USB connections
  • Updated capture workflow description to mention SDR++ Server as the recommended approach
  • Renamed "Discover Devices" button to "Discover USB Devices" for clarity
v2.12.21
2025-11-27
Fixed (1)
  • Let OLED alert scrolls run across the full padded buffer before wrapping so alert text cleanly exits and re-enters the screen instead of freezing or overlaying fragments.
v2.12.20
2025-11-27
Fixed (1)
  • Restored OLED alert scrolling by advancing the seamless scroll window based on elapsed frame time and speed settings so high-priority messages animate smoothly instead of freezing on a single frame.
v2.12.19
2025-11-26
Fixed (1)
  • Added IPv6 connectivity troubleshooting documentation (`docs/troubleshooting/FIX_IPV6_CONNECTIVITY.md`) so operators can diagnose SSL Labs IPv6 test failures and nginx upstream connection errors.
v2.12.18
2025-11-26
Fixed (1)
  • Redirected the policy docs URLs to the canonical `/terms` and `/privacy` routes and updated the documentation index to point to those pages so users no longer see divergent copies of the legal notices.
v2.12.17
2025-11-25
Fixed (1)
  • Redirect permission-denied responses to the dashboard blueprint's admin route so settings pages (including `/settings/alert-feeds`) return a proper 403 flow instead of a 500 BuildError when the non-namespaced endpoint is unavailable.
v2.12.15
2025-11-22
Changed (2)
  • Downsampled the continuous EAS monitor to 8 kHz (with automatic resampling from higher-rate sources) so SAME FSK decoding runs at an efficient rate without wasting CPU on unnecessary bandwidth.
  • Surfaced both the source and decoder sample rates in the monitor status API so operators can verify the tap is resampling correctly instead of assuming 22.05 kHz.
v2.12.14
2025-11-22
Fixed (2)
  • Matched the streaming decoder sample rate to the active ingest source so SAME correlation and preamble detection run at the correct frequency instead of drifting off-sync when sources run at 44.1 kHz.
  • Exposed the ingest-driven sample rate in the broadcast adapter stats returned with the EAS monitor status so operators can confirm the tap is aligned with the source.
v2.12.13
2025-12-05
Fixed (3)
  • Added broadcast subscription health (queue depth, underruns, last audio time) to the continuous monitor API so the dashboard shows when audio is actually flowing and operators can see the tap is healthy instead of guessing through empty fields.
  • Throttled repetitive buffer underrun warnings from the monitor's broadcast adapter while still counting them for visibility, preventing log spam when sources are temporarily quiet.
  • Exposed broadcast queue stats and the currently active source in `/api/audio/metrics` so VU meters can distinguish "no signal" from transport failures and display accurate runtime state.
v2.12.12
2025-12-05
Fixed (2)
  • Filled the continuous monitor status API with the streaming decoder's health, rate, and sync metrics so every dashboard field renders and operators can confirm the monitor is actively processing audio.
  • Tagged live audio metrics with each source's runtime status so the VU meters reflect whether inputs are running instead of dimming as if they were offline.
v2.12.10
2025-12-04
Changed (1)
  • Added a selectable streaming mode on the audio monitor that prefers the built-in HTTPS stream by default and only opts into Icecast when operators explicitly choose it, reducing stalls when external ports are blocked.
v2.12.9
2025-12-04
Fixed (1)
  • Filter placeholder artwork metadata values (e.g., `null`, `undefined`, root-only paths) in the audio monitor so browsers stop
v2.12.8
2025-12-03
Fixed (1)
  • Corrected the default Icecast external port variable so Icecast URLs use the configured `ICECAST_EXTERNAL_PORT` rather than
v2.12.7
2025-12-02
Fixed (1)
  • Hardened the SDR audio monitoring stack by adding an auto-healing ingest controller that restarts stalled/error sources,
v2.12.6
2025-12-01
Fixed (2)
  • Added a differential RBDS symbol slicer so FM demodulation correctly reconstructs PI/PS/RadioText metadata and keeps the latest
  • Hardened the SoapySDR receiver implementation by mapping stream error codes (including SOAPY_SDR_NOT_LOCKED) to descriptive
v2.12.5
2025-11-30
Changed (1)
  • Disabled the CAP poller's optional SDR capture orchestration by default so its RadioManager hooks stay idle unless the poller
v2.12.4
2025-11-29
Fixed (1)
  • Forced OLED templates with manually positioned lines to default to no-wrapping in the renderer so preview cards and physical
v2.12.3
2025-11-29
Fixed (1)
  • Updated the OLED layout migration to use uniquely named bind parameters so Alembic can compile the update statement without colliding with column names, preventing the `bindparam() name 'name' is reserved` failure during upgrades.
v2.12.2
2025-11-29
Fixed (2)
  • Added an automatic SoapySDR fallback that retries opening receivers without the serial filter when the initial connection fails, letting Airspy radios initialize even if the driver rejects the serialized arguments.
  • Updated the OLED layout migration to JSON-serialize `template_data` before persisting it to PostgreSQL so upgrades no longer crash with `can't adapt type 'dict'` errors.
v2.12.1
2025-11-27
Changed (2)
  • Rebuilt the EAS Station wordmark as an inline SVG partial that inherits theme colors for its accent bars and lettering, so the logo automatically matches whichever palette operators choose without filters or manual assets.
  • Updated the navigation bar and hero sections on the Help, About, Privacy, Terms, and Version pages to consume the new partial, eliminating duplicate markup and keeping the refreshed layout consistent in every mode.
v2.12.0
2025-11-27
Added (2)
  • Introduced two new UI themes, **Midnight** and **Tide**, complete with theme-switcher entries and CSS variable palettes so operators can choose between a deep slate dark mode and a crisp coastal light mode.
  • Published NOAA, FEMA IPAWS, and ARRL resource badges plus a curated "Trusted Field Resources" section on the Help page so the most requested links are visual, organized, and no longer broken.
Changed (2)
  • Modernized the Help & Operations Guide layout with hero quick links, an operations flow mini-timeline, refreshed typography, and a reorganized assistance section for a more professional flow.
  • Added dedicated Help-page utility styles that sharpen quick-link tiles, timeline steps, and resource cards, ensuring the guide matches the rest of the dashboard polish.
v2.11.7
2025-11-18
Changed (3)
  • Added a refresh-status meta block on the dashboard map card that now shows the last update time, refresh source, and a live
  • Replaced the fixed interval timer with a scheduler that pauses during manual refreshes, resumes after success or failure, and
  • Updated the dashboard refresh action so manual, automatic, keyboard, and debug triggers all share the same code path,
v2.11.6
2025-11-23
Changed (1)
  • Default location snapshots now seed `area_terms` with an empty list rather than mirroring the removed environment variable,
v2.11.5
2025-11-23
Fixed (1)
  • Removed the CAP poller's area-term fallback so alerts only appear on `/alerts` when their SAME or UGC codes match the
v2.11.4
2025-11-22
Fixed (1)
  • Fixed duplicate DOM element declarations on the Weekly Test Automation page that threw JavaScript errors and prevented saved
v2.11.3
2025-11-21
Fixed (1)
  • Ensured the RWT scheduler always opens a Flask application context before touching the
v2.11.2
2025-11-20
Added (2)
  • Added an offline alert self-test harness plus `scripts/run_alert_self_test.py` so operators can replay bundled RWT captures,
  • Folded the alert self-test harness into the **Tools → Alert Verification** dashboard so operators can replay bundled or custom
Changed (1)
  • Consolidated the alert self-test workflow into the Alert Verification dashboard so operators validate decoding, analytics,
v2.10.0
2025-11-18
Added (8)
  • Added comprehensive `utilities.css` with gradient, card, badge, spacing, layout, typography, shadow, border, visibility, and animation utilities
  • Created reusable template component partials in `templates/components/` for metric cards, stat cards, page headers, status badges, and data lists
  • Built new professional version page (`/help/version`) with tabbed interface featuring Overview, Changelog, Features, System Info, and JSON API tabs
  • Added `changelog_parser.py` utility to parse CHANGELOG.md files and extract structured version history
  • Integrated git commit information display (hash, branch, date, message) on version page
  • Added visual timeline visualization for changelog with animated current version marker
  • Added comprehensive feature matrix showing all installed system components and their availability status
  • Added copy-to-clipboard functionality for JSON API output
Fixed (3)
  • Fixed inconsistent gradient implementations across templates by centralizing in utilities.css
  • Fixed missing CSS files (design-system.css, components.css) not being loaded in base template
  • Improved dark theme compatibility for version page components
Changed (5)
  • Updated `base.html` template to include all CSS files in proper order: design-system, base, components, utilities, layout, and enhancements
  • Replaced basic version page with comprehensive tabbed interface showing full release history from parsed CHANGELOG.md
  • Enhanced version route in `routes_monitoring.py` to include git metadata and parsed changelog data
  • Standardized gradient usage across all templates with new utility classes (.gradient-primary, .gradient-success, etc.)
  • Improved version page accessibility with URL hash-based tab navigation
v2.71.40 Current
Added (42)
  • Clarified the commercial license offer notes pricing covers software only and excludes any hardware costs.
  • Extended `/api/system_status` and `/api/system_health` with hostname, primary IPv4, uptime, and primary-interface metadata
  • Surfaced the Weekly Test Automation console with a county management side panel, Broadcast navigation entry, and in-product callouts so operators can edit RWT schedules and default SAME codes entirely from the UI.
  • Added a curated OLED showcase rotation (system overview, alerts, network beacon, IPAWS poll watch, audio health, and audio
  • Enforced Argon Industria OLED reservations by blocking BCM pins 2, 3, 4, and 14 (physical header block 1-8) from GPIO configuration, greying them out in the GPIO Pin Map, and surfacing guidance in setup, environment, and hardware docs.
  • Provisioned default OLED status screens with system, alert, and audio telemetry plus on-device button shortcuts (short press to advance rotation, long press for a live snapshot).
  • Added Argon Industria SSD1306 OLED module support with full configuration tooling and display workflows
  • Introduced `app_core/oled.py` with luma.oled-based controller, new `OLED_*` environment variables, and runtime initialization hooks
  • Extended screen renderer, manager, and `/api/screens` endpoints with an `oled` display type alongside LED and VFD rotations
  • Updated admin Environment editor, setup wizard, and hardware reference docs for OLED installation and configuration guidance
  • ...32 more
Fixed (96)
  • Removed caching from `/api/audio/metrics` and set explicit no-store headers so VU meters and live audio telemetry refresh in
  • Hardened backup API endpoints by validating backup names to block path traversal before
  • Removed the CAP poller's area-term fallback so `/alerts` only surfaces entries that explicitly name the configured SAME or
  • Ensured the continuous EAS monitor auto-initializes on demand so the audio monitoring page no longer stalls when the monitor
  • Added comprehensive audio ingest pipeline for unified capture from SDR, ALSA, and file sources
  • Implemented `app_core/audio/ingest.py` with pluggable source adapters and PCM normalization
  • Added peak/RMS metering and silence detection with PostgreSQL storage
  • Built web UI at `/settings/audio-sources` for source management with real-time metering
  • Exposed configuration for capture priority and failover in environment variables
  • Documented the Weekly Test Automation county list regression addressed in 2.11.4 so QA can trace the scheduler fix through the
  • ...86 more
Changed (13)
  • Refined the theming system with higher-contrast logo treatments and added Aurora, Nebula, and Sunset presets to expand the built-in palette while keeping the wordmark legible across gradients.
  • Renamed the "EAS Workflow" console to **Broadcast Builder** and linked the Weekly Test Automation page throughout the Broadcast menu and workflow hero banner so automation tooling is obvious to operators.
  • **Consolidated stream support in Audio Sources system** - Removed stream support from RadioReceiver model and UI, centralizing all HTTP/M3U stream configuration through the Audio Sources page where StreamSourceAdapter already provided full functionality
  • Removed `source_type` and `stream_url` fields from RadioReceiver database model
  • RadioReceiver now exclusively handles SDR hardware (RTL-SDR, Airspy)
  • Added Stream (HTTP/M3U) option to Audio Sources UI dropdown
  • Added stream configuration fields (URL, format) to Audio Sources modal
  • Updated navigation to point to `/settings/audio` instead of deprecated `/audio/sources` route
  • Clear separation of concerns: Radio = RF hardware, Audio = all audio ingestion sources
  • Enhanced AGENTS.md with bug screenshot workflow, documentation update requirements, and semantic versioning conventions
  • ...3 more
v2.9.0
2025-11-15
Added (2)
  • OLED alert rotations now preempt normal playlists when `skip_on_alert` is enabled, prioritizing the most severe alert and
  • `/api/alerts` now returns each alert's source and (when available) the cached EAS narration text, allowing custom OLED/LED
v2.8.0
2025-02-15
Fixed (42)
  • Prevented the `20251113_add_serial_mode_to_led_sign_status` Alembic migration from
  • Added an offline pyttsx3 text-to-speech provider so narration can be generated without
  • Authored dedicated `docs/reference/ABOUT.md` and `docs/guides/HELP.md` documentation describing the system mission, software stack, and operational playbooks, with cross-links from the README for quick discovery.
  • Exposed in-app About and Help pages so operators can read the mission overview and operations guide directly from the dashboard navigation.
  • Documented open-source dependency attributions in the docs and surfaced
  • Inserted the mandatory display-position byte in LED sign mode fields so M-Protocol
  • Surface offline pyttsx3 narration failures in the Manual Broadcast Builder with
  • Detect missing libespeak dependencies when pyttsx3 fails and surface
  • Detect missing ffmpeg dependencies and empty audio output from pyttsx3 so the
  • Surface actionable pyttsx3 dependency hints when audio decoding fails so
  • ...32 more
Changed (11)
  • Documented why the platform remains on Python 3.12 instead of the new Python 3.13 release across the README and About surfaces,
  • Documented Debian 14 (Trixie) 64-bit as the validated Raspberry Pi host OS while clarifying that the container image continues to ship on Debian Bookworm via the `python:3.12-slim-bookworm` base.
  • Documented the release governance workflow across the README, ABOUT page, Terms of Use, master roadmap, and site footer so version numbering, changelog discipline, and regression verification remain mandatory for every contribution.
  • Suppressed automatic EAS generation for Special Weather Statements and Dense Fog Advisories to align with standard activation practices.
  • Clarified in the README and dependency notes that PostgreSQL with PostGIS must run in a dedicated container separate from the application services.
  • Clarified the update instructions to explicitly pull the Experimental branch when refreshing deployments.
  • Documented the expectation that deployments supply their own PostgreSQL/PostGIS host and simplified Compose instructions to run only the application services.
  • Reworked the EAS Output tab with an interactive Manual Broadcast Builder and refreshed the README/HELP documentation to cover the browser-based workflow.
  • Enhanced the Manual Broadcast Builder with a hierarchical state→county SAME picker, a deduplicated PSSCCC list manager, a live `ZCZC-ORG-EEE-PSSCCC+TTTT-JJJHHMM-LLLLLLLL-` preview with field-by-field guidance, and refreshed docs that align with commercial encoder terminology.
  • Added a one-touch **Quick Weekly Test** preset to the Manual Broadcast Builder so operators can load the configured SAME counties, test status, and sample script before generating audio.
  • ...1 more
v2.7.5
2025-11-15
Fixed (1)
  • Allow first-time deployments to create the initial administrator from a dedicated
v2.7.2
2025-11-15
Fixed (1)
  • Restore SDR audio monitor adapters on-demand for all audio ingest APIs, eliminating the recurring 503 responses and broken
v2.7.1
2025-11-15
Fixed (1)
  • Backfill SDR squelch columns automatically when legacy deployments haven't run the
v2.7.0
2025-11-14
Added (1)
  • Added an audio-monitor provisioning API and UI workflow that auto-starts SDR Icecast streams, surfaces RBDS programme data, and exposes squelch/carrier telemetry directly from the radio settings page for immediate listening checks.
Changed (1)
  • Enabled configurable squelch thresholds, timing, and carrier-loss alarms for SDR receivers with service-specific defaults tuned for Raspberry Pi deployments, reducing false positives while keeping CPU usage low.
v2.4.16
2025-11-10
Fixed (1)
  • Removed the `APP_BUILD_VERSION` environment override so persistent `.env` files can no longer pin stale release numbers; the UI now always reflects the repository `VERSION` manifest.
v2.4.15
2025-11-10
Fixed (2)
  • Ensured the version resolver invalidates its cache when `APP_BUILD_VERSION` or the `VERSION` file changes so dashboards display
  • Disabled caching on the built-in documentation viewer routes to prevent browsers and reverse proxies from serving outdated
v2.4.14
2025-11-10
Fixed (1)
  • Added automatic cache-busting query parameters to all Flask-served static asset URLs so envoy/nginx layers fetch freshly deployed bundles instead of stale copies (Screenshot_7-11-2025_75931_easstation.com.jpeg).
v2.4.11
2025-11-09
Fixed (2)
  • Corrected the documentation viewer's Mermaid block detection to support Windows-style line endings so diagrams render instead of showing raw code.
  • Refreshed system version metadata on each request so the footer and monitoring endpoints display the latest release after version bumps.
v2.4.1
2025-11-09
Fixed (3)
  • **Resolved production nginx image regressions** - Ensured HTTPS container bundles required tooling and static assets
  • Copied repository `static/` directory into the image to stop 404 errors for CSS, JS, and image assets
  • Updated nginx configuration to use the modern `http2 on;` directive and silence deprecation warnings during startup
v2.3.12
2025-11-15
Fixed (1)
  • Hardened admin location validation so statewide SAME/FIPS codes are always accepted and labelled consistently when saving.
v2.3.11
2025-11-14
Fixed (1)
  • Fixed admin location settings so statewide SAME/FIPS codes remain saved when operators select entire states.
v2.3.10
2025-11-03
Changed (1)
  • Reformatted SAME plain-language summaries to omit appended FIPS and state code
v2.3.9
2025-11-03
Changed (1)
  • Display the per-location FIPS identifiers and state codes on the Audio Archive
v2.3.8
2025-11-02
Fixed (1)
  • Backfilled missing plain-language SAME header summaries when loading existing
v2.3.7
2025-11-02
Changed (1)
  • Linked the admin location reference summary and API responses to the bundled
v2.3.6
2025-11-02
Added (1)
  • Added an admin location reference API and dashboard card that surfaces the saved
v2.3.5
2025-11-01
Fixed (1)
  • Prevented the public forecast zone catalog synchronizer from inserting duplicate
v2.3.3
2025-11-13
Changed (1)
  • Documented Raspberry Pi 5 (4 GB RAM) as the reference platform across the README, policy documents, and in-app help/about pages while noting continued Raspberry Pi 4 compatibility.
v2.3.2
2025-11-02
Changed (1)
  • The web server now falls back to a guarded setup mode when critical
v2.3.1
2025-11-01
Added (1)
  • Added one-click backup and upgrade controls to the Admin System Operations panel, wrapping the existing CLI helpers in background tasks with status reporting.
v2.1.9
2025-10-31
Added (1)
  • Delivered a WYSIWYG LED message designer with content-editable line cards, live colour/effect previews,
Changed (2)
  • Refactored the LED controller to accept structured line payloads, allowing nested colours, display modes,
  • Enhanced the LED send API to normalise structured payloads, summarise mixed-format messages for history
v2.1.8
2025-10-30
Fixed (1)
  • Inserted the mandatory display-position byte in LED sign mode fields so M-Protocol
v2.1.7
2025-10-29
Changed (1)
  • Updated ignore rules and documentation so generated EAS artifacts and runtime logs remain outside
v2.1.6
2025-10-28
Changed (2)
  • Aligned build metadata across environment defaults, the diagnostics endpoints, and the
  • Refreshed the README to highlight core features, deployment steps, and configuration
v2.1.5
2025-10-27
Added (5)
  • Added database-backed administrator authentication with PBKDF2 hashed passwords,
  • Expanded the admin console with a user management tab, dedicated login page, and APIs
  • Introduced `.env.example` alongside README instructions covering environment setup and
  • Implemented the EAS broadcaster pipeline that generates SAME headers, synthesizes WAV
  • Published `/admin/eas_messages` for browsing generated transmissions and downloading
Changed (2)
  • Switched administrator password handling to Werkzeug's PBKDF2 helpers while migrating
  • Extended the database seed script to provision `admin_users`, `eas_messages`, and
v2.1.4
2025-10-26
Added (4)
  • Persisted configurable location settings with admin APIs and UI controls for managing
  • Delivered a manual NOAA alert import workflow with backend validation, a reusable CLI
  • Enabled editing and deletion of stored alerts from the admin console, including audit
  • Broadened boundary metadata with new hydrography groupings and preset labels for water
Changed (1)
  • Hardened manual import queries to enforce supported NOAA parameters and improved error
v2.1.0
2025-10-25
Added (3)
  • Established the NOAA CAP alert monitoring stack with Flask, PostGIS persistence,
  • Delivered the interactive Bootstrap-powered dashboard with alert history, statistics,
  • Integrated optional LED sign controls with configurable presets, message scheduling,
v2.2.0
2025-10-29
Added (2)
  • Recorded the originating feed for each CAP alert and poll cycle, exposing the source in the
  • Normalised IPAWS XML payloads with explicit source tagging and circle-to-polygon conversion
Changed (2)
  • Automatically migrate existing databases to include `cap_alerts.source` and
  • Surfaced poll provenance in the statistics dashboard, including the observed feed sources
v2.3.4
Added (1)
  • Documented the public forecast zone catalog synchronisation workflow and
v2.3.0
2025-10-30
Changed (3)
  • Normalized every database URL builder to require `POSTGRES_PASSWORD`, apply safe
  • Trimmed duplicate database connection variables from the default `.env` file and
  • Bumped the default `APP_BUILD_VERSION` to 2.3.0 across the application and sample
v2.4.9
2025-11-09
Fixed (2)
  • Switch certbot issuance to standalone HTTP-01 mode so the container itself binds to port 80 during startup,
  • Log the standalone challenge server activation so operators can confirm ACME connectivity when debugging
v2.4.8
2025-11-09
Fixed (2)
  • Verify existing certificates against the system trust store and expiration before skipping issuance, so stale self-signed chains are purged and a new ACME request runs on startup.
  • Log detailed reasons when certificate validation fails and remove the associated material, making it obvious when fallback artifacts block public issuance.
v2.4.7
2025-11-09
Fixed (2)
  • Detect existing certificates issued by anything other than Let's Encrypt (including legacy self-signed chains)
  • Extend the certificate cleanup routine to treat unknown issuers as invalid, guaranteeing that deployments replace
v2.4.6
2025-11-09
Fixed (2)
  • Remove any lingering self-signed certificate directories (including suffixed variants) on
  • Extend the certificate purge routine to clean historical self-signed material before certbot
v2.4.5
2025-11-09
Fixed (2)
  • Purge the domain's existing `/etc/letsencrypt` material whenever a self-signed
  • Force certbot to request a fresh certificate for self-signed domains by
v2.4.4
2025-11-09
Fixed (2)
  • Detect legacy self-signed fallback certificates by inspecting the existing fullchain.pem and
  • Remove invalid certificate files prior to issuing new ones so nginx never launches with the
v2.4.3
2025-11-09
Fixed (2)
  • Detect previously generated self-signed certificates and automatically retry Let's Encrypt
  • Tag self-signed fallbacks with a marker file and clear it after successful issuance to avoid
v2.4.2
2025-11-09
Fixed (2)
  • Provision certbot in the nginx container via Python's package manager so Let's Encrypt
  • Replaced bash-specific `[[ ... ]]` usage in the nginx initialization script with

Installed Features

CAP Alert Monitoring
Core feature
EAS Broadcasting
Core feature
LED Signs
Not configured
VFD Display
v2.1.0+
OLED Support
v2.8.0+
SDR/Radio
v2.1.0+
RBAC Security
v2.3.0+
Audio Subsystem
v2.7.0+
Analytics
v2.0.0+
PostGIS Spatial
Core feature
GPIO Control
v2.1.0+
Bare Metal Deployment
Core feature
Feature Status

This EAS Station installation includes all core features and professional-grade components for 24/7 emergency alert monitoring and broadcasting. Visit the documentation for detailed feature guides.

System Information

Version Details
System Name
NOAA CAP Alerts System
Version
2.71.40
Author
KR8MER Amateur Radio Emergency Communications
Description
Emergency alert system for Putnam County, OH
Git Information
Commit Hash
af7d0e9d
Branch
main
Commit Date
2026-04-03T12:41:54Z
Message
Update repository statistics [skip ci]
Time Information
Timezone
America/New_York
Local Time
2026-04-03T23:22:10.601335-04:00
UTC Time
2026-04-04T03:22:10.601110+00:00
Features
LED Signs
Not Available

JSON API Response

This data is also available in JSON format at /version for programmatic access.

JSON Output
{
  "version": "2.71.40",
  "name": "NOAA CAP Alerts System",
  "author": "KR8MER Amateur Radio Emergency Communications",
  "description": "Emergency alert system for Putnam County, OH",
  "timezone": "America/New_York",
  "led_available": false,
  "timestamp": "2026-04-04T03:22:10.601110+00:00",
  "local_timestamp": "2026-04-03T23:22:10.601335-04:00"
}