feat: add device family to separate s3 and s4 events.
This commit is contained in:
+56
-3
@@ -85,6 +85,7 @@ CREATE TABLE IF NOT EXISTS events (
|
||||
blastware_filesize INTEGER, -- bytes; NULL if no event file saved
|
||||
a5_pickle_filename TEXT, -- "<filename>.a5.pkl" sidecar
|
||||
sidecar_filename TEXT, -- "<filename>.sfm.json" review/metadata sidecar
|
||||
device_family TEXT, -- "series3" (MiniMate Plus / BW) | "series4" (Micromate / Thor) — drives per-family UI rendering (units, labels)
|
||||
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
|
||||
UNIQUE(serial, timestamp)
|
||||
);
|
||||
@@ -198,11 +199,53 @@ class SeismoDb:
|
||||
("blastware_filesize", "INTEGER"),
|
||||
("a5_pickle_filename", "TEXT"),
|
||||
("sidecar_filename", "TEXT"),
|
||||
("device_family", "TEXT"),
|
||||
):
|
||||
if col not in existing_cols:
|
||||
log.info("_migrate: events ADD COLUMN %s %s", col, ddl)
|
||||
conn.execute(f"ALTER TABLE events ADD COLUMN {col} {ddl}")
|
||||
|
||||
# Migration 1c: backfill device_family for existing rows by sniffing
|
||||
# the device-native binary filename's extension. Thor (Micromate
|
||||
# Series IV) writes `.IDFH` / `.IDFW`; MiniMate Plus (Series III)
|
||||
# writes `.AB0*` / `.N00` / `.<base36>` Blastware extensions. We do
|
||||
# this here rather than from sidecars so the migration is fully
|
||||
# self-contained (doesn't need the waveform-store root) and runs at
|
||||
# DB-init time. Only fills NULL device_family so re-runs are no-ops.
|
||||
rebackfill = conn.execute(
|
||||
"SELECT COUNT(*) FROM events WHERE device_family IS NULL"
|
||||
).fetchone()
|
||||
if rebackfill and rebackfill[0] > 0:
|
||||
log.info("_migrate: backfilling device_family for %d events", rebackfill[0])
|
||||
# Series IV (Thor IDF) — extension is exactly .IDFH or .IDFW
|
||||
conn.execute(
|
||||
"""
|
||||
UPDATE events
|
||||
SET device_family = 'series4'
|
||||
WHERE device_family IS NULL
|
||||
AND (
|
||||
UPPER(blastware_filename) LIKE '%.IDFH'
|
||||
OR UPPER(blastware_filename) LIKE '%.IDFW'
|
||||
)
|
||||
"""
|
||||
)
|
||||
# Everything else with a filename → Series III (Blastware family)
|
||||
conn.execute(
|
||||
"""
|
||||
UPDATE events
|
||||
SET device_family = 'series3'
|
||||
WHERE device_family IS NULL
|
||||
AND blastware_filename IS NOT NULL
|
||||
"""
|
||||
)
|
||||
# Rows with no filename (e.g. older monitor_log-derived events)
|
||||
# stay NULL — UI handles NULL as "unknown family".
|
||||
remaining = conn.execute(
|
||||
"SELECT COUNT(*) FROM events WHERE device_family IS NULL"
|
||||
).fetchone()[0]
|
||||
log.info("_migrate: device_family backfill complete (remaining NULL=%d)",
|
||||
remaining)
|
||||
|
||||
# Migration 2: change monitor_log UNIQUE from (serial, waveform_key) to
|
||||
# (serial, start_time) — same reasoning as events.
|
||||
row = conn.execute(
|
||||
@@ -302,6 +345,7 @@ class SeismoDb:
|
||||
serial: str,
|
||||
session_id: Optional[str] = None,
|
||||
waveform_records: Optional[dict[str, dict]] = None,
|
||||
device_family: Optional[str] = None,
|
||||
) -> tuple[int, int]:
|
||||
"""
|
||||
Insert triggered events. Silently skips duplicates (serial+timestamp).
|
||||
@@ -316,6 +360,11 @@ class SeismoDb:
|
||||
(dedup hit), the matching waveform record is upserted onto the
|
||||
existing row so a re-download via the live endpoint refreshes the
|
||||
file metadata.
|
||||
|
||||
``device_family`` (optional): "series3" (MiniMate Plus / Blastware) or
|
||||
"series4" (Micromate / Thor). Drives per-family UI rendering — most
|
||||
importantly the mic-unit convention (psi vs dB(L)). Set on every
|
||||
insert and overwritten on every UPSERT so the latest writer wins.
|
||||
"""
|
||||
inserted = skipped = 0
|
||||
wave_recs = waveform_records or {}
|
||||
@@ -349,8 +398,9 @@ class SeismoDb:
|
||||
project, client, operator, sensor_location,
|
||||
sample_rate, record_type,
|
||||
blastware_filename, blastware_filesize,
|
||||
a5_pickle_filename, sidecar_filename)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
a5_pickle_filename, sidecar_filename,
|
||||
device_family)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
self._new_id(), serial, key, session_id, ts,
|
||||
@@ -369,6 +419,7 @@ class SeismoDb:
|
||||
rec.get("filesize"),
|
||||
rec.get("a5_pickle_filename"),
|
||||
rec.get("sidecar_filename"),
|
||||
device_family,
|
||||
),
|
||||
)
|
||||
inserted += 1
|
||||
@@ -409,7 +460,8 @@ class SeismoDb:
|
||||
blastware_filename = ?,
|
||||
blastware_filesize = ?,
|
||||
a5_pickle_filename = ?,
|
||||
sidecar_filename = ?
|
||||
sidecar_filename = ?,
|
||||
device_family = COALESCE(?, device_family)
|
||||
WHERE serial = ? AND timestamp = ?
|
||||
""",
|
||||
(
|
||||
@@ -428,6 +480,7 @@ class SeismoDb:
|
||||
rec.get("filesize") if rec else None,
|
||||
rec.get("a5_pickle_filename") if rec else None,
|
||||
rec.get("sidecar_filename") if rec else None,
|
||||
device_family,
|
||||
serial,
|
||||
ts,
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user