Flatten the snapshot structure so each domain maps directly to its
fields rather than mirroring the old WeConnect status-object nesting.
New domains: electric_drive (range, battery/SOC/temps, odometer),
connectivity, vehicle, position, doors — replacing the old readiness,
parking, access, and measurements domains. Update apply_procedural
paths and collect.py defaults accordingly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the weconnect library with carconnectivity and
carconnectivity-connector-volkswagen. The connector is configured via
a dict passed to CarConnectivity(); startup()/fetch_all() replace
login()/update(). All domain extractors in data_model.py are rewritten
for the new object model (vehicle.charging.*, vehicle.get_electric_drive(),
vehicle.climatization.*, etc.). Remaining time fields are now derived
from estimated_date_reached DateAttributes. Battery temperatures are
read directly in °C (no Kelvin conversion). Auth error handling drops
the manual re-login since the connector manages token refresh internally.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
server/data_model.py:
- apply_procedural(record) — stub function; add computed fields to the
proc dict inside and they appear under record['procedural'] in every
record stored and broadcast.
- _get(data, *keys) — safe nested dict accessor for use inside
apply_procedural.
collect.py:
- New snapshots: apply_procedural() called after collect_snapshot(),
before appending to the store and broadcasting.
- Preloaded 24-h history: guarded apply (skip if 'procedural' already
present) applied after load_last_24h_records().
- Current-day store loaded from disk: same guarded apply after
load_store(), so legacy records sent to clients are enriched on the fly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Server (network.py): send every record in diff mode starting from
prev={}, including the first — fixes history drop on new client connect.
Collect (collect.py): remove payload["_diff"] = True from live broadcast.
GUI client (gui_client.py): always call jay_merge_full in diff mode;
drop the _diff key check that gated reconstruction.
CLI client (client.py): fix `args.diff or True` guard that made --diff
irrelevant.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Change --diff from store_true to default=None so CLI presence is
distinguishable from the JSON default. If not given on CLI, reads
creds_data.get("diff", False). Updated install.sh template and README.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
-i/--interval, --host, --port, --log-dir can now be passed on the
command line; each overrides the corresponding credentials file value
when given. Defaults remain unchanged (300 s, 0.0.0.0, 9999, ./logs).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Server (collect.py --diff):
- History burst: first record sent full, subsequent as jay_diff_full diffs
- Live broadcast: each snapshot diffed against the previous one
- Diff payloads tagged with "_diff": true
Client (client.py --diff):
- Reconstructs full state via jay_merge_full before printing
GUI (Connector tab "Diff mode" checkbox):
- TcpReader.connect_to() accepts diff_mode; maintains _state dict
- Merges incoming diffs before emitting to Dashboard/Plot
- Checkbox state persisted to plot_settings.json
Both sides default to off; must be enabled consistently on server and client.
utils/__init__.py added so utils.jay_diff is importable as a package.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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 <noreply@anthropic.com>
Remove --vin, --interval/-i, --output/-o, --host, --port from argparse.
All are now read from the credentials JSON (interval_s, host, port,
log_dir with sensible defaults). CLI flags -u/-p/-d still override the
file; log_dir replaces the old --output/auto-logs logic — logs_dir is
always used, no fixed output path option.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace load_today_records with load_last_24h_records which computes a
rolling 24 h cutoff, globs log files for both the current and previous
calendar day, and filters records by timestamp — so clients always
receive a full 24 h window regardless of when midnight falls.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously load_today() was only called if in-memory records were empty,
which was never true once the first WeConnect poll had completed.
Now disk records are loaded unconditionally at startup and merged with
live in-memory records (dedup by ts) when a client connects.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
storage_helpers: load_today_records() scans logs/ for all files
matching today's UTC date and VIN, merges and sorts their records.
network: _accept_loop receives an optional load_today callable;
if store_ref["current"] has no records it calls load_today() to
replay the day's history from disk before adding the client.
collect: passes a load_today lambda (None when -o is used).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
data_model, log_config, network, storage_helpers, we_connect are now
under server/. collect.py stays in the project root and imports via
the server package.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The server keeps the most recent snapshot in memory (under the same
lock as the client list). When a client connects it receives that
snapshot right away, then continues to receive live updates on each
collection cycle.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
auto_out_path, load_store, save_store moved out of data_model.py into
their own module. data_model.py now contains only value helpers and
domain extractors.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
we_connect.py now only handles WeConnect login and vehicle selection.
All extract_*() functions, ALL_DOMAINS, and collect_snapshot() live
in data_model.py alongside the store and value helpers.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each connected TCP client receives every snapshot as a newline-
delimited JSON line the moment it is collected (no polling needed).
The server binds on --host/--port (default 0.0.0.0:9999).
Client connections are accepted in a daemon thread; dead connections
are pruned on the next broadcast.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When -o is not set, the collector detects a UTC date change at the
top of each collection cycle and opens a fresh timestamped file under
logs/. Explicit -o paths are never rotated.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When -o is omitted, the output file is auto-named from the run's
start timestamp and the vehicle VIN and placed under ./logs/,
which is created on demand. logs/ is gitignored.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All fields with a physical unit are now emitted as
{"value": <number>, "unit": "<unit>"} instead of encoding the unit
in the field name. Field names are renamed accordingly (e.g.
chargePower_kW → chargePower). Battery temperature field names are
also fixed to reflect the already-applied K→°C conversion.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>