Commit Graph

49 Commits

Author SHA1 Message Date
serversdown 9b3ae6d548 Merge pull request 'feat(forward): SFM event forwarder (v1.5.0)' (#9) from dev into main
Reviewed-on: #9
2026-05-11 12:29:21 -04:00
serversdown 65b3af90ae feat(forward): re-pair late-arriving TXTs on subsequent scans
When a binary is forwarded WITHOUT its paired _ASCII.TXT (because
the TXT wasn't quiescent within the grace period — BW slow to
write, AV scanning, etc.), the old behaviour was to permanently
mark the binary as "done" in the state file, even though the TXT
might land seconds later.  Result: that event lived in SFM forever
with broken-codec peak values and no project info.

Fix: state entries now carry a had_report flag.  Forwards without
a TXT set had_report=False.  On subsequent scans, the watcher
treats had_report=False entries as re-pair candidates — they get
re-forwarded once the TXT appears, and the SFM server's upsert
path (in seismo-relay's insert_events IntegrityError handler)
refreshes the DB row with the report's authoritative values.

Three status states in ForwardState.status(sha256):
  None  — never forwarded.  First-forward path.
  True  — forwarded successfully WITH report (or legacy entry
          without the had_report field).  Permanently done.
  False — forwarded WITHOUT report.  Re-pair if TXT now exists.

Backward compat: legacy state-file entries (no had_report key)
default to True so existing deployments don't unexpectedly
re-forward every entry on upgrade.

Tests cover:
  - re-pair when TXT appears after a had_report=False forward
  - had_report=True entries stay skipped permanently
  - legacy entries (missing field) treated as fully forwarded
  - state.status() returns None for unknown sha
  - re-marking had_report=False then True promotes to fully-done

36 watcher tests pass (was 31, +5 new).
2026-05-11 16:22:53 +00:00
serversdown e6c25ab941 Merge pull request 'feat(forward): SFM event forwarder (v1.5.0)' (#8) from sfm-event-forwarder into dev
Reviewed-on: #8
2026-05-11 12:10:44 -04:00
serversdown c81f4ee61f docs(README): add Roadmap (Future) section
Captures the watcher-side deferred work from the v1.5.0 development
thread:

  - File archive manager (90-day events into year/month subfolders)
  - MLG forwarding (currently excluded from is_event_binary())
  - Pre-deploy seed-state UX in the Settings dialog

Points operators to seismo-relay's parallel Roadmap for the
server-side counterparts (MLG ingest endpoint, etc.).
2026-05-11 16:08:15 +00:00
serversdown 19548466ad chore(release): consolidate v1.5.1–v1.5.4 into single v1.5.0 Unreleased entry
None of v1.5.1 / v1.5.2 / v1.5.3 / v1.5.4 ever shipped — they only
existed as separate CHANGELOG entries on this unmerged feature
branch.  SemVer ties version numbers to releases, not commits.
From a field machine's perspective, the world skips straight from
v1.4.4 to whatever the next built-and-pushed installer is tagged.

Revert VERSION / AppVersion / module-docstring version comments
to v1.5.0 across:
  - series3_watcher.py     (VERSION = "1.5.0")
  - installer.iss          (AppVersion=1.5.0)
  - series3_tray.py        (docstring)
  - settings_dialog.py     (docstring)
  - README.md              (banner + footer)

Consolidate the four split CHANGELOG sections into a single
"## [Unreleased] — v1.5.0" entry covering all the work in one
release.  Configuration key table consolidated into one place.
No commit history rewriting — the per-commit code changes still
make sense as logical units for code review; only the surface-
level version metadata + CHANGELOG narrative was misleading.

Going forward: accumulate work-in-progress under an "[Unreleased]"
heading, bump VERSION only at actual release time.
2026-05-10 22:24:35 +00:00
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
serversdown a166918a9d fix(forward-log): distinguish histograms from missing-report (v1.5.3)
On machines running histogram-mode units (extensions ending in H,
e.g. H907L1R7.PG0H), every forwarded event was logging "no report"
even though histograms never get auto-exported ASCII reports from
Blastware — making the log look like every forward was misconfigured
when in fact things were working correctly.

Three log states now:

  - Waveform + paired TXT
      → "+ <txt> attached"
  - Waveform without TXT (likely BW config issue)
      → "no report ⚠"
  - Histogram (any flavour)
      → "(histogram, no report expected)"

New is_histogram_event() helper classifies by BW filename extension:
4-char ext ending in H = histogram; old-firmware 3-char extensions
default to non-histogram (safe default — we'd rather flag a missing
report than silently suppress the warning on a real waveform event).

Forwarding logic itself is unchanged — this is purely log clarity.
2026-05-10 01:39:22 +00:00
serversdown 815c643fb2 feat(forward): rate cap + seed-state mode for safe backfill (v1.5.2)
Two safety nets for first-deploy on Blastware ACH machines that
have accumulated tens or hundreds of thousands of historical events
in the watch folder.

1. SFM_MAX_FORWARDS_PER_PASS (default 500, 0=unlimited)
   ---------------------------------------------------
   Cap on the number of events forwarded per scan tick.  At the
   60-second default interval that's ~30K events/hour throughput —
   the SFM server gets a steady drip instead of one giant burst.
   Scan now sorts by mtime ascending so backfill advances
   chronologically (oldest first) and successive scans always
   make progress instead of re-considering the same N newest files.

   Wired into:
     - event_forwarder.find_pending_events / forward_pending
     - series3_watcher.run_watcher loop
     - config-template.ini
     - settings_dialog SFM Forward tab (new "Max Events Per Pass"
       spinbox, validated in _on_save)

2. event_forwarder.py --seed-state CLI
   -----------------------------------
   One-shot mode that walks the watch folder, sha256s every in-window
   event binary, and marks them all as already-forwarded WITHOUT
   POSTing anything.  Run before flipping SFM_FORWARD_ENABLED=true
   to skip the historical backfill entirely — the watcher then only
   forwards events that appear AFTER the seed.

   Usage:
       python event_forwarder.py --seed-state \
           --watch "C:\Blastware 10\Event\autocall home" \
           --state "C:\...\sfm_forwarded.json" \
           [--max-age-days 365]

7 new unit tests:
  - max_per_pass cap enforcement (=N, =0 unlimited, oldest-first
    ordering)
  - seed-state mode (in-window seeding, max-age skip,
    end-to-end skip-after-seed, idempotent re-runs)

README adds a "First-time deployment" section walking through both
options.  Bumps to v1.5.2.
2026-05-10 00:20:10 +00:00
serversdown 3ee0cae31e fix(settings): add SFM Forward tab to settings dialog (v1.5.1)
v1.5.0 shipped the forwarder module + INI keys but the settings
dialog wasn't extended, so the only way operators could enable
forwarding was hand-editing config.ini.  This adds a sixth tab
("SFM Forward") with:

  - Forward events to SFM    checkbox
  - SFM Server URL           entry + Test button (GETs /health)
  - Forward Interval (sec)   spinbox
  - Quiescence (sec)         spinbox
  - Missing-Report Grace     spinbox
  - HTTP Timeout             spinbox
  - State File               entry + Browse...

Save-time guard: enabling the forwarder without a URL raises a
validation error rather than silently saving a non-functional
config.

Patch release — same on-disk INI schema, no config migration.
2026-05-10 00:01:25 +00:00
serversdown f4ec6ef945 feat(forward): SFM event forwarder (v1.5.0)
When SFM_FORWARD_ENABLED=true and SFM_URL is set, every Blastware
event binary in the ACH watch folder is forwarded to an SFM server's
/db/import/blastware_file endpoint as a multipart POST.  The paired
<binary>.TXT ASCII report (which Blastware's ACH writes alongside
each event) is 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 per channel, and monitor-log timestamps —
without depending on the still-undecoded BW waveform body codec.

New module event_forwarder.py:
  - is_event_binary() filename matcher (BW's <P><serial3><stem>.<ext>
    scheme; rejects .MLG, .TXT, .log, .ini, .h5, etc.)
  - ForwardState (.json file keyed by sha256 — idempotent across
    restarts and auto-updates)
  - find_pending_events() with quiescence + grace-period guards
  - Hand-rolled multipart encoder (stdlib-only)
  - forward_event_pair() / forward_pending() — POST loop with
    structured per-event outcomes

Wired into series3_watcher.run_watcher() on its own cadence
(SFM_FORWARD_INTERVAL_SECONDS, default 60s) so it doesn't slow the
existing 5-min heartbeat scan.

Default-off: existing 1.4.x deployments keep their old behaviour
after auto-updating until an operator sets SFM_URL +
SFM_FORWARD_ENABLED=true and restarts.

17 unit tests in test_event_forwarder.py cover filename matching,
state idempotency, scan logic (quiescence, grace, max age,
already-forwarded, .TXT pairing), multipart byte shape, and an
end-to-end POST against a tiny stdlib http.server fake.

Bumps version 1.4.4 → 1.5.0 (minor — additive feature, no API break).
Requires SFM server v0.16+ for the paired-.TXT import endpoint.
2026-05-09 00:03:31 +00:00
serversdown 1abdc13645 Merge pull request 'bump to 1.4.4 (the nonupdate update)' (#6) from dev into main
Reviewed-on: #6
v1.4.4
2026-03-17 21:54:59 -04:00
claude 010016d515 bump to 1.4.4 (the nonupdate update)
chore: clean up code, deprecate status config.
2026-03-17 21:54:15 -04:00
serversdown f790b21808 Merge pull request 'merge v1.4.3' (#5) from dev into main
Reviewed-on: #5
v1.4.3
2026-03-17 21:11:41 -04:00
claude 439feb9942 Feat: Update settings tab implemented.
Auto-updates now configurable (URL, source (gitea or private server), log activity for auto updates.
fix: Update now hardened to prevent installation of corrupt or incorrect .exe files. (security to be hardened in the future)
2026-03-17 21:08:37 -04:00
serversdown 0bea6ca4ea Merge pull request 'v1.4.2' (#3) from dev into main
Reviewed-on: #3
v1.4.2
2026-03-17 16:15:22 -04:00
claude d2a8c2d928 Update to v1.4.2
Feat: tray icon now shows API/watcher health rather than unit ages. unit submenu removed, now handled by recieving software.

Chore: remove old unneeded code from deprecated features (console colorization, Missing/pending age limits)
2026-03-17 16:02:24 -04:00
claude 3303e22843 fix: update version to v1.4.2 and improve status reporting in tray
feat: now sends watcher_status via payload to terra-view
2026-03-17 15:23:55 -04:00
serversdown 2456fd0ee8 Merge pull request 'Merge v1.4.1 from dev' (#2) from dev into main
## [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.
v1.4.1
2026-03-17 14:31:50 -04:00
claude d2fd3b7182 docs: v1.4.1 changelog entry 2026-03-17 14:29:46 -04:00
claude 1d94c5dd04 docs: delete deprecated client specific readme 2026-03-17 14:26:59 -04:00
claude 814b6f915e fix: settings dialog now runs in its own thread, increasing responsiveness. 2026-03-17 13:36:35 -04:00
claude 9cfdebe553 fix: watcher correctly uses AppData directory, not program files. 2026-03-17 03:40:04 -04:00
claude f773e1dac9 fix: tray icon more legible 2026-03-17 03:27:53 -04:00
claude 326658ed26 doc: readme bummped to 1.4.1 2026-03-17 01:23:01 -04:00
claude 504ee1d470 bugfix: log directory now writes to appdata folder, avoiding permissions issues. log folder accessible from tray icon.
doc: deployment/build doc added
2026-03-17 01:10:40 -04:00
claude e67b6eb89f Feat: v1.4.1 - Windows installer updated. 2026-03-16 20:00:42 -04:00
claude 1b8c63025f doc: update readme v1.4 2026-03-13 17:52:59 -04:00
claude 0807e09047 feat: windows installer with remote updates and remote management added. 2026-03-13 17:40:28 -04:00
claude 00956c022a Rename to series 3 watcher 2026-03-12 19:14:30 -04:00
claude 9b20d93f4c chore: cleanup gitignore 2026-03-05 23:10:44 -05:00
serversdown c133932b29 Merge pull request 'Merge: dev to main, refactor rename' (#1) from dev into main
Reviewed-on: serversdown/series3-agent#1
2026-03-03 17:12:58 -05:00
claude d404bf6542 refactor: Rename emitter to agent, update related files and logging paths 2026-03-03 17:10:47 -05:00
claude 0d5fa7677f chore: Config-template.ini added to repo. .gitignore updated. 2026-03-03 16:13:01 -05:00
claude 44476248c3 chore: config.ini now added to git ignore. See config template for schema 2026-03-03 16:09:39 -05:00
claude fa56b93c8f Merge branch 'main' into dev 2025-12-04 17:25:36 -05:00
claude 58ba506f54 docs updated 2025-12-04 17:24:20 -05:00
claude 62a4ca2b1c Update README header formatting 2025-12-04 17:22:30 -05:00
claude f29943f8e4 Add version information to README 2025-12-04 17:16:59 -05:00
claude 35e3292f01 Merge pull request #4 from serversdwn/dev
Roster deprecated, v1.2
2025-12-04 17:16:23 -05:00
claude 73204ee92e Roster deprecated 2025-12-04 16:22:31 -05:00
claude 47718e7cad Merge pull request #3 from serversdwn/dev
Update to 1.1.0
2025-12-02 01:33:29 -05:00
claude 9074277ff3 config update 2025-12-02 01:31:37 -05:00
claude 551fdae106 v1.1 w/ api funtion added 2025-12-01 16:30:08 -05:00
claude a03d4a1f05 Add API_URL support + POST reporting logic 2025-11-20 18:24:57 -05:00
claude 142998251c Merge pull request #2 from serversdwn/dev
Merge pull request #1 from serversdwn/main
2025-11-20 18:03:59 -05:00
claude de3b46a09e Merge pull request #1 from serversdwn/main
Update ROSTER_URL in config.ini
2025-11-20 17:09:12 -05:00
claude 08c54f992c Update ROSTER_URL in config.ini
example config
2025-11-18 02:57:14 -05:00
claude 1cf10f0023 added README.md file 2025-11-17 12:15:04 -05:00
claude 5dc78096cd v1.0.0 – stable baseline emitter 2025-11-17 12:12:10 -05:00