From df32c263bcfbb0048e235c4a025f414087fb1371 Mon Sep 17 00:00:00 2001 From: jonathan Date: Tue, 2 Jun 2026 22:29:42 +0200 Subject: [PATCH] chore: remove NTFY notification roadmap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not being pursued — the planning doc just adds noise. Co-Authored-By: Claude Sonnet 4.6 --- ROADMAP.md | 154 ----------------------------------------------------- 1 file changed, 154 deletions(-) delete mode 100644 ROADMAP.md diff --git a/ROADMAP.md b/ROADMAP.md deleted file mode 100644 index 57c09a2..0000000 --- a/ROADMAP.md +++ /dev/null @@ -1,154 +0,0 @@ -# ISR Roadmap - -## notify.py — NTFY Loudness Notifications - -### Context - -Street ambience recorder. Goal: detect notable audio events (speech, thunder, -sustained unusual sounds) in hourly recording files and push a notification via -a self-hosted NTFY server. Generic short events (car horn, passing vehicle) -should be filtered out by a minimum section duration. - -### Design decisions - -| Topic | Decision | -|---|---| -| Detection | RMS + minimum section duration filter (KISS — no FFT for now) | -| Timing | Configurable: `immediate` / `daily` / `both` | -| Config | `[notify]` section in existing `config.ini` | -| Code structure | `notify.py` imports `analyze_wav` / `analyze_flac` from `web.py` (DRY) | -| Source name | Included in notification body; configurable display name per source | - ---- - -### Config additions (`config.example.ini`) - -Add a `[notify]` section to `config.ini`: - -```ini -[notify] -enabled = true -ntfy_url = https://ntfy.example.com/mytopic ; full URL incl. topic -mode = immediate ; immediate | daily | both -daily_time = 08:00 ; HH:MM — used in daily and both modes -debounce_minutes = 60 ; immediate mode: suppress repeat notifications within this window -min_section_duration = 2.0 ; seconds — sections shorter than this are ignored (filters car horns etc.) -min_sections = 1 ; number of qualifying sections required to trigger a notification -loudness_threshold = 0.05 ; RMS 0–1, same scale as web.py analysis threshold -``` - -Per recording source, add an optional `display_name`: - -```ini -[radio1] -type = stream -url = http://icecast.example.com:8000/live -display_name = Street mic north ; shown in notification; defaults to section name [radio1] -``` - ---- - -### Notification format - -``` -Title: ISR — Notable audio · Street mic north -Body: radio1_20260427_0300.wav - 3 notable sections (≥ 2.0 s each) - → 00:12 – 00:18 - → 01:45 – 01:52 - → 47:03 – 47:11 - Peak RMS: 0.312 -``` - -Daily digest example: - -``` -Title: ISR Daily Digest · 2026-04-27 -Body: Street mic north — 4 files with notable events - 03:00 file · 3 sections (peak 0.312) - 07:00 file · 1 section (peak 0.091) - 14:00 file · 2 sections (peak 0.204) - 21:00 file · 1 section (peak 0.178) -``` - ---- - -### Implementation plan - -#### Phase 1 — Core - -1. **`config.example.ini`** — add `[notify]` section and `display_name` key to - source section examples (as shown above). - -2. **`notify.py` — file watcher** - - Polls `recordings/status.json` every 30 s. - - Tracks which files were in `active` on the previous poll. - - When a file disappears from `active` it was just closed → queues it for - analysis. - - Skips files with extensions that cannot be analysed (anything other than - `.wav` / `.flac`). - -3. **`notify.py` — analysis + filter** - - Imports `analyze_wav` / `analyze_flac` from `web.py`. - - Applies `loudness_threshold` from `[notify]` config. - - Filters resulting sections to those with duration ≥ `min_section_duration`. - - Counts filtered sections against `min_sections` threshold. - -4. **`notify.py` — NTFY HTTP POST** - - Plain `urllib` POST to `ntfy_url` (no extra dependencies). - - Sets `Title` and message body as described above. - - Logs success / failure to stdout. - -#### Phase 2 — Cadence modes - -5. **Immediate mode with debounce** - - Fires right after the file closes and analysis passes. - - Persists last-notification timestamp per source to a small - `notify_state.json` in the recordings directory. - - Suppresses sending if last notification for that source was within - `debounce_minutes`. - -6. **Daily digest mode** - - Appends qualifying events to `notify_log.jsonl` in the recordings - directory (one JSON line per event: timestamp, source, filename, sections, - peak RMS). - - On each poll checks whether `daily_time` has passed today and no digest - has been sent yet (tracked in `notify_state.json`). - - Reads all undigested entries from `notify_log.jsonl`, groups by - `display_name`, sends one notification per source with notable activity. - - Marks entries as digested. - -7. **Both mode** - - Immediate path: only fires when peak RMS exceeds a second, higher - threshold (`alarm_threshold`, default `0.3`; add to `[notify]` config). - - Daily digest path: fires for everything that passes `min_sections`. - -#### Phase 3 — Integration - -8. **Docker** — optional `notify` service in `docker-compose.yml`: - ```yaml - notify: - build: . - command: python notify.py - volumes: - - ./recordings:/app/recordings - - ./config.ini:/app/config.ini:ro - restart: unless-stopped - ``` - -9. **README** — new section documenting `notify.py` usage, config keys, and - Docker setup. - ---- - -### Open questions (decide before implementing) - -- **Log rotation**: `notify_log.jsonl` grows indefinitely. Options: cap at N - days (configurable), cap at N MB, or leave cleanup to the user. No decision - made yet. -- **Multiple NTFY topics per source**: current design uses one global topic. - If per-source topics are ever needed, `ntfy_url` could be moved to the source - section and override the global one. -- **FFT / frequency analysis** (future): distinguishing thunder (low rumble, - 50–200 Hz) from speech (300–3000 Hz) from vehicles would reduce false - positives further. Deferred — requires `numpy` and adds meaningful complexity.