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>
we_monitor
Periodically polls a VW WeConnect vehicle via the weconnect library, stores
timestamped records as JSON, and pushes live data to connected TCP clients.
A PyQt5 GUI client visualises the data in real time.
Repository layout
collect.py — collector daemon (entry point)
gui_client.py — PyQt5 GUI client
client.py — minimal CLI test client
server/
data_model.py — domain extractors, collect_snapshot()
network.py — TCP push server (accept loop + broadcast)
storage_helpers.py— load / save JSON store, midnight rotation helpers
we_connect.py — WeConnect login and vehicle selection
log_config.py — logging setup
requirements.txt
Requirements
pip install weconnect PyQt5 pyqtgraph
Collector (collect.py)
Connects to WeConnect, polls selected domains at a configurable interval, and appends records to a JSON file. Simultaneously runs a TCP push server so clients receive every new snapshot the moment it is collected.
Quick start
# Credentials via environment variables, all defaults
export WC_USER=me@example.com
export WC_PASS=secret
python collect.py
# Credentials from a JSON file, 10-minute interval
python collect.py -c credentials/my_car.json -i 600
Credentials file (-c FILE)
{
"username": "me@example.com",
"password": "secret",
"vin": "WVWZZZE1ZMP000000",
"domains": ["charging", "measurements", "readiness"]
}
All keys are optional; explicit CLI flags and WC_USER / WC_PASS
environment variables take precedence.
CLI reference
| Flag | Default | Description |
|---|---|---|
-c FILE |
— | JSON credentials file |
-u / -p |
WC_USER / WC_PASS |
Username / password |
--vin |
first vehicle | Target VIN |
-d DOMAINS |
charging,measurements,readiness |
Comma-separated domains or all |
-i SECONDS |
300 |
Collection interval |
-o FILE |
logs/YYYY_MM_DD_HH_MM_SS_<VIN>.json |
Output file |
--max-records N |
unlimited | Keep only last N records |
--host |
0.0.0.0 |
Push server bind address |
--port |
9999 |
Push server TCP port |
-v |
— | Verbose / debug logging |
--list-domains |
— | Print available domains and exit |
Available domains: charging, climatisation, measurements,
readiness, parking, access
Log rotation
When using the default logs/ directory the collector automatically starts a
new file after midnight UTC, keeping all previous files intact. On startup the
full day's records are pre-loaded from disk so newly connected clients receive
the complete history.
Output format
Each file is a JSON object:
{
"meta": { "vin": "...", "created_at": "...", "interval_seconds": 300 },
"records": [
{
"ts": "2025-05-25T10:00:00+00:00",
"charging": {
"batteryStatus": {
"currentSOC": { "value": 80, "unit": "%" },
"cruisingRangeElectric": { "value": 310, "unit": "km" }
}
}
}
]
}
Physical values are always {"value": …, "unit": …} objects.
Push server protocol
The server listens on --host:--port (default 0.0.0.0:9999).
- On connect: sends all records from the current day, sorted by timestamp.
- On each new poll: sends the new snapshot immediately.
All messages are newline-delimited JSON (one record per line, \n
terminated).
GUI client (gui_client.py)
python gui_client.py
python gui_client.py --host 192.168.1.10 --port 9999
Dark theme matching nmea_client. Three tabs:
Connector tab
Host / port fields, Connect / Disconnect button, and connection status.
Dashboard tab
Live tree view of the latest snapshot — domain → status object → field, showing value and unit. Expand state is preserved across updates.
Plot tab
8 plots (4 × 2) in a scrollable grid. Each plot has its own control bar:
- Dropdown +
+— select a signal and add it as a trace (max 4 per plot). - Colored chips (
name ×) — click to remove a trace. - Zoom / pan with mouse; crosshair cursor tracks mouse position.
Trace selections are persisted to
~/.config/we_monitor/plot_settings.json and restored automatically on
the next launch once matching signals arrive.
Signal labels use short human-readable names (e.g. SOC, range,
outside temp) defined in _TRACE_LABELS near the top of gui_client.py.
CLI test client (client.py)
python client.py
python client.py --host 192.168.1.10 --port 9999
Connects to the push server and prints every incoming snapshot as pretty-printed JSON with a running record counter.