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

14 KiB
Raw Blame History

Changelog

All notable changes to Series 3 Watcher will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.


[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).