README covers installation, collector CLI reference, push server protocol,
GUI client usage, and output format. conversation_recap documents the full
development history: features, bugs fixed, and design decisions.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Color palette taken directly from nmea_client/gui/plot_widget.py:
- Background #1a1a2e / #12121e, borders #2a2a4a/#3a3a5e,
text #aaaacc/#ddddee, connected #4CAF50, error #F44336
- Trace colors: Material palette (blue, red, green, orange, …)
- Plot widget background overridden from "white" to #12121e
- pyqtgraph foreground set to #aaaacc
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Trace selection combos show short labels (_trace_label) with full key
stored as item data; width auto-adjusts to content (min 120 px)
- Extended plot grid from 4 to 8 (4×2) wrapped in QScrollArea
- Removed reset-zoom toolbar and cursor readout area
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
InfiniteLine was included in auto-range calculations, causing the view
to rescale on every cursor move. Add it with ignoreBounds=True in both
the initial setup and after each redraw.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace static combo grid with a control bar above each plot:
add-trace dropdown + "+" button; active traces shown as colored chips with
"×" to remove (max 4 per plot)
- Save trace selection to ~/.config/we_monitor/plot_settings.json on every
change; restore automatically once matching signals arrive from the server
- Remove tiny tick-font overrides so axis labels are readable at default size
- Show received record count in the status bar
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>
Removed the QScrollArea wrapper and fixed figure-height calculation.
FigureCanvasQTAgg now fills the tab with an Expanding size policy so
all 8 subplots fit in the visible area at 1920x1200 without scrolling.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
create_connection(timeout=5) left a 5-second read timeout on the
socket. Any collection interval longer than 5 s caused recv() to
raise socket.timeout, which was caught as OSError and reported as
a lost connection. Switch to blocking mode with settimeout(None)
immediately after the connect handshake.
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>
- Connector tab: host/port fields, connect/disconnect button, status
- Dashboard tab: live QTreeWidget of the full snapshot hierarchy;
physical values show value and unit in separate columns;
expand state preserved across refreshes
- Plot tab: matplotlib time-series subplots (2 columns) for every
physical {value, unit} field, scrollable, auto-layout on new keys
- TcpReader runs in a daemon thread and delivers messages via
Qt signals so the UI never blocks
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>
Connects to collect.py's push server and prints each incoming
snapshot as pretty-printed JSON, separated by a dashed line.
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>