feat: add option to restart monitoring after event download in AchSession
This commit is contained in:
@@ -139,6 +139,7 @@ class AchSession:
|
|||||||
state_path: Path,
|
state_path: Path,
|
||||||
db: "SeismoDb",
|
db: "SeismoDb",
|
||||||
clear_after_download: bool = False,
|
clear_after_download: bool = False,
|
||||||
|
restart_monitoring: bool = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.sock = sock
|
self.sock = sock
|
||||||
self.peer = peer
|
self.peer = peer
|
||||||
@@ -149,6 +150,7 @@ class AchSession:
|
|||||||
self.state_path = state_path
|
self.state_path = state_path
|
||||||
self.db = db
|
self.db = db
|
||||||
self.clear_after_download = clear_after_download
|
self.clear_after_download = clear_after_download
|
||||||
|
self.restart_monitoring = restart_monitoring
|
||||||
|
|
||||||
def run(self) -> None:
|
def run(self) -> None:
|
||||||
ts = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
ts = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||||
@@ -319,6 +321,38 @@ class AchSession:
|
|||||||
"peer": self.peer,
|
"peer": self.peer,
|
||||||
}
|
}
|
||||||
_save_state(self.state_path, state)
|
_save_state(self.state_path, state)
|
||||||
|
|
||||||
|
# ── Erase even when no new events (if requested) ──────────
|
||||||
|
# Blastware ACH always erases after every session — even when
|
||||||
|
# nothing new was downloaded. Without the erase the device
|
||||||
|
# still sees stored events in its memory and immediately
|
||||||
|
# retries the call-home, causing the looping we observed.
|
||||||
|
# Only erase when device actually has events stored; skip
|
||||||
|
# the erase if device_keys is empty (nothing to erase).
|
||||||
|
if self.clear_after_download and device_keys:
|
||||||
|
log.info(
|
||||||
|
" Clearing device memory (--clear-after-download, "
|
||||||
|
"no new events but device has %d stored)...",
|
||||||
|
len(device_keys),
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
client.delete_all_events()
|
||||||
|
log.info(" [OK] Device memory cleared")
|
||||||
|
# Reset state so the next session starts fresh.
|
||||||
|
state[unit_key] = {
|
||||||
|
"downloaded_keys": [],
|
||||||
|
"max_downloaded_key": "00000000",
|
||||||
|
"last_seen": datetime.datetime.now().isoformat(),
|
||||||
|
"serial": serial,
|
||||||
|
"peer": self.peer,
|
||||||
|
}
|
||||||
|
_save_state(self.state_path, state)
|
||||||
|
except Exception as exc:
|
||||||
|
log.error(
|
||||||
|
" [WARN] Event deletion failed: %s -- events NOT cleared",
|
||||||
|
exc,
|
||||||
|
)
|
||||||
|
|
||||||
log.info("Session complete (no new events) -> %s", session_dir)
|
log.info("Session complete (no new events) -> %s", session_dir)
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
@@ -489,6 +523,15 @@ class AchSession:
|
|||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
log.error(" [FAIL] Event download failed: %s", exc, exc_info=True)
|
log.error(" [FAIL] Event download failed: %s", exc, exc_info=True)
|
||||||
|
|
||||||
|
# ── Optional: restart monitoring after successful download ─────────
|
||||||
|
if self.restart_monitoring:
|
||||||
|
log.info(" Restarting monitoring on device (--restart-monitoring)...")
|
||||||
|
try:
|
||||||
|
client.start_monitoring()
|
||||||
|
log.info(" [OK] Monitoring restarted")
|
||||||
|
except Exception as exc:
|
||||||
|
log.warning(" [WARN] Failed to restart monitoring: %s", exc)
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
raw_fh.close()
|
raw_fh.close()
|
||||||
client.close() # closes transport / socket cleanly
|
client.close() # closes transport / socket cleanly
|
||||||
@@ -593,6 +636,7 @@ def serve(args: argparse.Namespace) -> None:
|
|||||||
print(f" State file: {state_path}")
|
print(f" State file: {state_path}")
|
||||||
print(f" Max events per session: {max_ev if max_ev else 'unlimited'}")
|
print(f" Max events per session: {max_ev if max_ev else 'unlimited'}")
|
||||||
print(f" Clear device after download: {'YES' if args.clear_after_download else 'no'}")
|
print(f" Clear device after download: {'YES' if args.clear_after_download else 'no'}")
|
||||||
|
print(f" Restart monitoring after download: {'YES' if args.restart_monitoring else 'no'}")
|
||||||
print(f"{'='*60}")
|
print(f"{'='*60}")
|
||||||
print(f"\n Point your test unit's ACEmanager call-home settings to:")
|
print(f"\n Point your test unit's ACEmanager call-home settings to:")
|
||||||
print(f" Remote Host: <this machine's LAN IP>")
|
print(f" Remote Host: <this machine's LAN IP>")
|
||||||
@@ -631,6 +675,7 @@ def serve(args: argparse.Namespace) -> None:
|
|||||||
state_path=state_path,
|
state_path=state_path,
|
||||||
db=db,
|
db=db,
|
||||||
clear_after_download=args.clear_after_download,
|
clear_after_download=args.clear_after_download,
|
||||||
|
restart_monitoring=args.restart_monitoring,
|
||||||
)
|
)
|
||||||
t = threading.Thread(target=session.run, daemon=True, name=f"ach-{peer}")
|
t = threading.Thread(target=session.run, daemon=True, name=f"ach-{peer}")
|
||||||
t.start()
|
t.start()
|
||||||
@@ -694,6 +739,16 @@ def parse_args() -> argparse.Namespace:
|
|||||||
"If not specified, all IPs are accepted (not recommended for public servers)."
|
"If not specified, all IPs are accepted (not recommended for public servers)."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
p.add_argument(
|
||||||
|
"--restart-monitoring",
|
||||||
|
action="store_true",
|
||||||
|
default=False,
|
||||||
|
help=(
|
||||||
|
"After downloading events, send SUB 0x96 (start monitoring) before "
|
||||||
|
"disconnecting. Required for RV55 units whose firmware does not assert "
|
||||||
|
"DCD on disconnect — without this the unit stays idle after a call-home."
|
||||||
|
),
|
||||||
|
)
|
||||||
p.add_argument(
|
p.add_argument(
|
||||||
"--clear-after-download",
|
"--clear-after-download",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
|
|||||||
Reference in New Issue
Block a user