From bb1e08786750943e8e7e70a23d15d5842e15d1a8 Mon Sep 17 00:00:00 2001 From: Jens Ahrensfeld Date: Tue, 26 May 2026 13:59:58 +0200 Subject: [PATCH] collect: add --dry flag to run push server without WeConnect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When --dry is set, WeConnect login and data collection are skipped. The push server still starts and serves preloaded 24 h history to connecting clients — useful for GUI testing without a live vehicle. Credentials are not required in dry-run mode. Co-Authored-By: Claude Sonnet 4.6 --- collect.py | 81 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 48 insertions(+), 33 deletions(-) diff --git a/collect.py b/collect.py index b2534f0..ea3573c 100644 --- a/collect.py +++ b/collect.py @@ -71,15 +71,20 @@ def run(args: argparse.Namespace) -> None: log.error("Unknown domain(s): %s. Available: %s", unknown, list(ALL_DOMAINS)) sys.exit(1) - log.info("Connecting to WeConnect…") - wc = we_connect.connect(args.username, args.password) + if args.dry: + log.info("Dry-run mode — skipping WeConnect login") + wc = None + vehicle = None + vin = args.vin or "UNKNOWN" + else: + log.info("Connecting to WeConnect…") + wc = we_connect.connect(args.username, args.password) + vehicle, err = we_connect.select_vehicle(wc, args.vin) + if err: + log.error(err) + sys.exit(1) + vin = vehicle.vin.value - vehicle, err = we_connect.select_vehicle(wc, args.vin) - if err: - log.error(err) - sys.exit(1) - - vin = vehicle.vin.value log.info("Vehicle: %s", vin) logs_dir = Path(args.log_dir) @@ -94,34 +99,39 @@ def run(args: argparse.Namespace) -> None: current_day = datetime.now(timezone.utc).date() store = load_store(out, vin, args.interval) push_store_ref["current"] = store - log.info( - "Collecting [%s] every %ds → %s (Ctrl-C to stop)", - ", ".join(domains), - args.interval, - out, - ) + + if args.dry: + log.info("Push server running on %s:%d — no live collection (Ctrl-C to stop)", args.host, args.port) + else: + log.info( + "Collecting [%s] every %ds → %s (Ctrl-C to stop)", + ", ".join(domains), + args.interval, + out, + ) try: while True: - today = datetime.now(timezone.utc).date() - if today != current_day: - out = auto_out_path(logs_dir, vin) - store = load_store(out, vin, args.interval) - push_store_ref["current"] = store - current_day = today - log.info("Midnight UTC rotation → %s", out) + if not args.dry: + today = datetime.now(timezone.utc).date() + if today != current_day: + out = auto_out_path(logs_dir, vin) + store = load_store(out, vin, args.interval) + push_store_ref["current"] = store + current_day = today + log.info("Midnight UTC rotation → %s", out) - try: - wc.update() - snapshot = collect_snapshot(vehicle, domains) - store["records"].append(snapshot) - save_store(out, store, args.max_records) - network.broadcast(snapshot, push_clients, push_lock) - log.info("Record #%d saved at %s", len(store["records"]), snapshot["ts"]) - except KeyboardInterrupt: - raise - except Exception: - log.exception("Collection failed — will retry at next interval") + try: + wc.update() + snapshot = collect_snapshot(vehicle, domains) + store["records"].append(snapshot) + save_store(out, store, args.max_records) + network.broadcast(snapshot, push_clients, push_lock) + log.info("Record #%d saved at %s", len(store["records"]), snapshot["ts"]) + except KeyboardInterrupt: + raise + except Exception: + log.exception("Collection failed — will retry at next interval") time.sleep(args.interval) @@ -174,6 +184,11 @@ def main() -> None: help="Keep only the last N records per file (default: unlimited)", ) p.add_argument("-v", "--verbose", action="store_true", help="Enable debug logging") + p.add_argument( + "--dry", + action="store_true", + help="Skip WeConnect login and data collection; run push server only (for GUI testing)", + ) p.add_argument( "--list-domains", action="store_true", @@ -217,7 +232,7 @@ def main() -> None: args.port = int(creds_data.get("port", 9999)) args.log_dir = creds_data.get("log_dir", "./logs") - if not args.username or not args.password: + if not args.dry and (not args.username or not args.password): p.error( "Username and password are required. " "Provide them in the credentials file or via -u/-p / WC_USER / WC_PASS."