Files
series3-watcher/CHANGELOG.md
T
serversdown 770336e09f fix(forward): pair BW ACH ASCII reports using the _ASCII.TXT convention (v1.5.4)
Blastware's official Auto Call Home server writes per-event ASCII
reports as <stem>_<ext>_ASCII.TXT (e.g. N844L20G_630H_ASCII.TXT),
not <binary>.TXT (e.g. N844L20G.630H.TXT).  Versions v1.5.0–v1.5.3
only looked for the latter and silently shipped every binary alone,
so the SFM database lost the per-event Peak Acceleration / Peak
Displacement / ZC Freq / Time of Peak / Peak Vector Sum + time /
sensor self-check fields on every forwarded event.

Fix: pair-finding logic now tries the ACH-convention filename first
and falls back to <binary>.TXT for compatibility with operator-saved
manual exports and existing test fixtures.

  ach_report_name("M529LK44.AB0")    → "M529LK44_AB0_ASCII.TXT"
  legacy_report_name("M529LK44.AB0") → "M529LK44.AB0.TXT"

When both files exist (operator manually saved + ACH auto-exported),
ACH wins because that's the canonical name on modern BW deployments.
Both candidates checked case-insensitively against the cached
directory listing — no extra stat() calls.

6 new unit tests cover the new pairing logic, helper-function
correctness, and the precedence rule.  Total now 31 tests, all green.

Field-deploy note: re-running v1.5.4 on a folder where v1.5.0–v1.5.3
already ran will NOT re-forward historical events — the
sfm_forwarded.json state file remembers them by sha256.  To re-forward
historical events to populate SFM with the now-correctly-paired
reports, delete the state file before starting v1.5.4.
2026-05-10 20:10:38 +00:00

218 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Changelog
All notable changes to **Series 3 Watcher** will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
---
## [1.5.4] - 2026-05-10
### Fixed
- **CRITICAL: Pair BW ACH ASCII reports using the `_ASCII.TXT` convention.** Blastware's official Auto Call Home server writes per-event ASCII reports as `<stem>_<ext>_ASCII.TXT` (e.g. `N844L20G_630H_ASCII.TXT`), not `<binary>.TXT` (e.g. `N844L20G.630H.TXT`). Versions v1.5.0v1.5.3 only looked for the latter and silently shipped every binary alone, so the SFM database lost the per-event Peak Acceleration / Peak Displacement / ZC Freq / Time of Peak / Peak Vector Sum + time / sensor self-check fields on every forwarded event. After this fix the watcher tries the ACH-convention filename first and falls back to the manual-export `<binary>.TXT` for compatibility with operator-saved exports + existing test fixtures.
### Changed
- New helper functions `ach_report_name()` and `legacy_report_name()` make the two filename conventions explicit and testable.
- 6 new unit tests covering both pairing conventions, the precedence-when-both-present rule (ACH wins), and helper-function correctness.
### Field-deploy note
Re-running v1.5.4 on a folder where v1.5.0v1.5.3 already ran will NOT re-forward historical events to pick up the rich metadata — the `sfm_forwarded.json` state file remembers them by sha256 and still considers them forwarded. If you want to re-forward to populate the SFM database with the now-correctly-paired reports for the historical archive, delete the state file before starting v1.5.4. Otherwise the fix only affects events appearing from v1.5.4 onward.
## [1.5.3] - 2026-05-10
### Changed
- **Forward log lines now distinguish histogram events from waveform-without-report.** Previously every event without a paired `.TXT` report logged "no report", which on machines running histogram-mode units (extensions ending in `H`, e.g. `H907L1R7.PG0H`) generated alarming-looking lines on every single event when the lack of report was actually completely normal — Blastware doesn't auto-export ASCII reports for histograms. Three log states now:
- **Waveform + paired TXT**: `+ <txt> attached`
- **Waveform without TXT**: `no report ⚠` (suggests checking BW's "Save Event Report" setting)
- **Histogram (any flavour)**: `(histogram, no report expected)`
- New `is_histogram_event(filename)` helper classifies BW filenames by extension (4-char ext ending in `H` = histogram; old-firmware 3-char extensions remain unclassifiable and default to non-histogram for safe defaults).
- 1 new unit test for histogram classification.
## [1.5.2] - 2026-05-10
### Added
- **`SFM_MAX_FORWARDS_PER_PASS` rate cap.** Default 500 events per scan tick (60-second interval = ~30K events/hour). Drips first-deploy backfill instead of hammering the SFM server with one giant burst on machines that have hundreds of thousands of historical events in the BW ACH folder. `0` = unlimited (preserves the 1.5.0 behaviour for ops who want it).
- **`event_forwarder.py --seed-state` CLI mode.** Walks the watch folder once, sha256s every in-window event, and marks them all as already-forwarded *without* POSTing anything. The recommended pre-deploy workflow on machines with a large historical archive — flip `SFM_FORWARD_ENABLED=true` after seeding and only events that appear *from then on* get forwarded.
- New "Max Events Per Pass" spinbox in the Settings dialog's SFM Forward tab.
- README "First-time deployment" section documenting both options.
- 7 new unit tests covering the cap (oldest-first ordering, cap=0 unlimited, cap=N enforcement) and the seed-state mode (skips out-of-window files, idempotent across re-runs, end-to-end skip-after-seed).
### Behaviour change
The scan loop now sorts entries by mtime ascending before walking, so backfill always advances chronologically (oldest qualifying event first). Without the cap the visible behaviour is identical; with the cap it means each scan reliably advances and we never get stuck re-considering the same N newest files.
## [1.5.1] - 2026-05-10
### Added
- **SFM Forward tab in the Settings dialog.** v1.5.0 shipped the `event_forwarder.py` module + INI keys but missed the GUI; operators had to edit `config.ini` by hand to enable forwarding. The settings dialog now exposes:
- **Forward events to SFM** checkbox
- **SFM Server URL** entry with a **Test** button (mirrors the Connection tab — GETs `/health` and shows the result)
- **Forward Interval / Quiescence / Missing-Report Grace / HTTP Timeout** spinboxes
- **State File** entry with a Browse... button (defaults to `<log dir>/sfm_forwarded.json` when blank)
- Save-time guard: enabling SFM Forward without filling in the URL shows a validation error rather than silently saving a non-functional config.
## [1.5.0] - 2026-05-09
### Added
- **SFM event forwarder.** When `SFM_FORWARD_ENABLED=true` and `SFM_URL` is set, every Blastware event binary is forwarded to an SFM server's `/db/import/blastware_file` endpoint as a multipart POST. The corresponding `<binary>.TXT` ASCII report (which Blastware's ACH writes alongside each event) is paired by filename and shipped in the same request, letting the SFM server index the full per-channel stats (PPV, ZC Freq, Time of Peak, Peak Acceleration / Displacement, Peak Vector Sum + time, sensor self-check Pass/Fail, monitor-log timestamps) without depending on the still-undecoded Blastware waveform body codec.
- **Idempotent forwarding.** Forwarded files are tracked by sha256 in a JSON state file (default `<log dir>/sfm_forwarded.json`, override via `SFM_STATE_FILE`). Re-scans don't re-POST and the state survives restarts / auto-updates.
- **Quiescence + grace-period guards.** Files modified within `SFM_QUIESCENCE_SECONDS` (default 5s) are skipped to avoid forwarding mid-write. If a binary's `.TXT` partner hasn't appeared after `SFM_MISSING_REPORT_GRACE_SECONDS` (default 60s), the binary is forwarded alone rather than blocking forever.
- New `event_forwarder.py` module + 17 unit tests in `test_event_forwarder.py` covering filename matching, state idempotency, scan logic, multipart encoding, and a fake-server end-to-end POST.
### Configuration
New `[agent]` keys (all default-off — existing 1.4.x deployments don't change behaviour on auto-update):
- `SFM_FORWARD_ENABLED` (default `false`)
- `SFM_URL` (e.g. `http://10.0.0.44:8200`)
- `SFM_FORWARD_INTERVAL_SECONDS` (default `60`)
- `SFM_QUIESCENCE_SECONDS` (default `5`)
- `SFM_MISSING_REPORT_GRACE_SECONDS` (default `60`)
- `SFM_HTTP_TIMEOUT` (default `60`)
- `SFM_STATE_FILE` (default: `<log dir>/sfm_forwarded.json`)
### Compatibility
- Requires SFM server v0.16+ (the `/db/import/blastware_file` endpoint that accepts paired `.TXT` reports — released alongside this watcher version on the seismo-relay side).
## [1.4.4] - 2026-03-17
### Removed
- `OK_HOURS` and `MISSING_HOURS` config keys and Settings dialog fields removed — unit status thresholds are calculated by terra-view from raw `age_minutes`, not by the watcher. These fields had no effect since v1.4.2.
## [1.4.3] - 2026-03-17
### Added
- Auto-updater now logs all activity to the watcher log file (`[updater]` prefix) — silent failures are now visible.
- Configurable update source: `UPDATE_SOURCE = gitea` (default), `url`, or `disabled`. In `url` mode the watcher fetches `version.txt` and the `.exe` from a custom base URL (e.g. terra-view) instead of the Gitea API — enables updates on isolated networks that cannot reach Gitea. `disabled` turns off automatic checks while keeping the remote push path (from terra-view) functional.
- New **Updates** tab in the Settings dialog to configure `UPDATE_SOURCE` and `UPDATE_URL`.
### Fixed
- Downloaded `.exe` is now validated before applying: absolute size floor (100 KB), relative size floor (50% of current exe), and MZ magic bytes check. A corrupt or truncated download is now rejected and logged rather than silently overwriting the live exe.
- Swap `.bat` now backs up the current exe as `<exe>.old` before overwriting, providing a manual rollback copy if needed.
- Swap `.bat` retry loop is now capped at 5 attempts — was previously infinite if the file remained locked.
- Swap `.bat` now cleans up the temp download file on both success and failure.
## [1.4.2] - 2026-03-17
### Changed
- Tray icon color now reflects watcher + API health rather than unit ages — green=API OK, amber=API disabled, red=API failing, purple=watcher error.
- Status menu text updated to show `Running — API OK | N unit(s) | scan Xm ago`.
- Units submenu removed from tray — status tracking for individual units is handled by terra-view, not the watcher.
- Unit list still logged to console and log file for debugging, but no OK/Pending/Missing judgement applied.
- `watcher_status` field added to heartbeat payload so terra-view receives accurate watcher health data.
## [1.4.1] - 2026-03-17
### Fixed
- `config.ini` now saves to `AppData\Local\Series3Watcher\` instead of `Program Files` — fixes permission denied error on first-run wizard save.
- Config path resolution in both `series3_tray.py` and `series3_watcher.py` updated to use `sys.frozen` + `LOCALAPPDATA` when running as a PyInstaller `.exe`.
- Status menu item now uses a callable so it updates every time the menu opens — was showing stale "Starting..." while tooltip correctly showed current status.
- Settings dialog now opens in its own thread — fixes unresponsive tabs and text fields while the watcher loop is running.
- Tray icon reverted to plain colored dot — custom icon graphic was unreadable at 16px tray size. `.ico` file is still used for the `.exe` file icon.
### Changed
- Terra-View URL field in settings wizard now accepts base URL only (e.g. `http://192.168.x.x:8000`) — `/api/series3/heartbeat` endpoint appended automatically.
- Test Connection button now hits `/health` endpoint instead of posting a fake heartbeat — no database side effects.
- "terra-view URL" label capitalized to "Terra-View URL".
- Default log path updated to `AppData\Local\Series3Watcher\agent_logs\series3_watcher.log`.
- Installer now creates `agent_logs\` folder on install.
- `BUILDING.md` added — step-by-step guide for building, releasing, and updating.
## [1.4.0] - 2026-03-12
### Added
- `series3_tray.py` — system tray launcher using `pystray` + `Pillow`. Color-coded icon (green=OK, amber=Pending, red=Missing, purple=Error, grey=Starting). Right-click menu shows live status, unit count, last scan age, Open Log Folder, and Exit.
- `run_watcher(state, stop_event)` in `series3_watcher.py` for background thread use by the tray. Shared `state` dict updated on every scan cycle with status, unit list, last scan time, and last error.
- Interruptible sleep in watcher loop — tray exit is immediate, no waiting out the full scan interval.
### Changed
- `main()` now calls `run_watcher()` — standalone behavior unchanged.
- `requirements.txt` updated to document tray dependencies (`pystray`, `Pillow`); watcher itself remains stdlib-only.
---
## [1.3.0] - 2026-03-12
### Changed
- Renamed program to "series3-watcher" and main script to `series3_watcher.py` — better reflects what it does (watches for activity) rather than implying active data emission.
- Default `SOURCE_TYPE` updated to `series3_watcher`.
- Default log filename updated to `series3_watcher.log`.
---
## [1.2.1] - 2026-03-03
### Changed
- Changed the name of the program to "series3-agent", this was done to align with the s4/thor agent and because it represents the program's functionality better.
- All instances of "emitter" changed to agent.
- config.ini added to .gitignore, replaced with a template example file.
- README.md updated to reflect changes.
---
## [1.2.0] - 2025-12-04
### Changed
- Removed roster CSV dependency and all Dropbox refresh/hot-reload logic; heartbeat now only enumerates `.MLG` files.
- Added `MAX_EVENT_AGE_DAYS` filter to ignore stale events and log when no recent activity exists.
- Simplified heartbeat output/logging to show detected units only; logging hardened to never crash the agent.
---
## [1.1.1] - 2025-12-02
### Added
- Example `config.ini` now ships with API heartbeat settings enabled (`API_ENABLED`, `API_URL`, `API_INTERVAL_SECONDS`, `SOURCE_ID`, `SOURCE_TYPE`).
---
## [1.1.0] - 2025-12-01
### Added
- Standardized SFM telemetry payload builder and periodic HTTP heartbeat POST via `urllib`.
- Config support for API heartbeat (`API_ENABLED`, `API_URL`, `API_INTERVAL_SECONDS`, `SOURCE_ID`, `SOURCE_TYPE`); payload includes file path/size metadata.
### Changed
- Refactored scanner to retain file paths and header sniff cache; reformatted logging/ANSI handling.
---
## [1.0.1] - 2025-11-20
### Added
- `API_URL` config key and `report_to_server` per-unit POST hook (adds `requests` dependency).
### Changed
- Example `config.ini` roster URL updated; merged into `main`.
---
## [1.0.0] - 2025-11-17
### Added
- **Automatic roster refresh** from Dropbox at a configurable interval (`ROSTER_REFRESH_MIN_SECONDS`).
- **Hot-reload** of roster file without restarting the script.
- **Failsafe reload:** if the new roster is missing or invalid, the previous good roster is retained.
- **Atomic roster downloads** (temp file in-place replace) to avoid partial/corrupted CSVs.
- **Startup config echo** printing WATCH_PATH, ROSTER_FILE, and ROSTER_URL visibility.
- **Active / Bench / Ignored** unit categories for clearer fleet status mapping.
### Fixed
- Removed stray `note=note_suffix` bug in the Unexpected Units section.
- Removed duplicate `import time`.
- Removed duplicate roster load during startup (roster now loads once).
- Cleaned indentation for Python 3.8 compatibility.
### Changed
- Reset versioning from legacy `v5.9 beta` to **v1.0.0** (clean semver baseline).
- Main script normalized as `series3_emitter.py` (later renamed to `series3_agent.py` in v1.2.1).
---
[Unreleased]: https://example.com/compare/v1.2.0...HEAD
[1.2.0]: https://example.com/releases/v1.2.0
[1.1.1]: https://example.com/releases/v1.1.1
[1.1.0]: https://example.com/releases/v1.1.0
[1.0.1]: https://example.com/releases/v1.0.1
[1.0.0]: https://example.com/releases/v1.0.0