Files
we_monitor/README.md
T
jensandClaude Sonnet 4.6 5944b0a7a4 collect: add diff to credentials file; --diff overrides it
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>
2026-05-26 15:09:54 +02:00

199 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
credentials/ — JSON config files (gitignored)
requirements.txt
```
## Requirements
```
pip install weconnect PyQt5 pyqtgraph
```
Or use the installer which also sets up a systemd user service:
```bash
./install.sh
```
## Collector (`collect.py`)
Connects to WeConnect, polls selected domains at a configurable interval, and
appends records to a rotating JSON log. Simultaneously runs a TCP push server
so clients receive every new snapshot the moment it is collected.
### Quick start
```bash
python collect.py -c credentials/my_car.json
```
Username and password can also be supplied via environment variables
(override the credentials file):
```bash
export WC_USER=me@example.com
export WC_PASS=secret
python collect.py -c credentials/my_car.json
```
### Credentials file
All connection and collection settings live in a single JSON file:
```json
{
"credentials": {
"username": "me@example.com",
"password": "secret"
},
"vin": "WVWZZZE1ZMP000000",
"domains": ["charging", "measurements", "readiness"],
"interval_s": 300,
"host": "0.0.0.0",
"port": 9999,
"log_dir": "./logs"
}
```
| Key | Default | Description |
|-----|---------|-------------|
| `credentials.username` | — | WeConnect / MyVolkswagen email |
| `credentials.password` | — | WeConnect password |
| `vin` | first vehicle | Target VIN |
| `domains` | `["charging","measurements","readiness"]` | Domains to collect (list or `"all"`) |
| `interval_s` | `300` | Collection interval in seconds |
| `host` | `"0.0.0.0"` | Push server bind address |
| `port` | `9999` | Push server TCP port |
| `log_dir` | `"./logs"` | Directory for rotating JSON log files |
| `diff` | `false` | Enable diff mode for push server transmission |
### CLI reference
CLI flags override the corresponding credentials file value when given.
| Flag | Overrides | Description |
|------|-----------|-------------|
| `-c FILE` | — | Credentials / settings file |
| `-u / -p` | `credentials.username/password` | Username / password (also `WC_USER` / `WC_PASS`) |
| `-d DOMAINS` | `domains` | Domains to collect (comma-separated or `all`) |
| `-i SECONDS` | `interval_s` | Collection interval in seconds |
| `--host HOST` | `host` | Push server bind address |
| `--port PORT` | `port` | Push server TCP port |
| `--log-dir DIR` | `log_dir` | Directory for rotating log files |
| `--max-records N` | — | Keep only the last N records per file |
| `--diff` | `diff` | Send diffs instead of full snapshots (must match client setting) |
| `--dry` | — | Skip WeConnect; run push server only (for testing) |
| `-v` | — | Verbose / debug logging |
| `--list-domains` | — | Print available domains and exit |
**Available domains:** `charging`, `climatisation`, `measurements`,
`readiness`, `parking`, `access`
### Log rotation
A new file is started automatically after midnight UTC; previous files are kept
intact. On startup and on each new client connection the collector sends the
last 24 hours of records, so clients always receive a full rolling window
regardless of when midnight falls.
### Output format
Log files are named `YYYY_MM_DD_HH_MM_SS_<VIN>.json` and contain:
```json
{
"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 the `host`:`port` from the credentials file (default `0.0.0.0:9999`).
* On connect: sends all records from the last 24 hours, sorted by timestamp.
* On each new poll: sends the new snapshot immediately.
All messages are **newline-delimited JSON** (one record per line, `\n` terminated).
### Diff mode (`--diff`)
When enabled on the server, the history burst is compressed: the first
record is sent in full, subsequent records as `jay_diff_full` diffs
(`{"_diff": true, "update_add": {…}, "delete": {…}}`). Live snapshots
are also diffed against the previous broadcast. Enable `--diff` on the
client side (`client.py`) or check **Diff mode** in the GUI Connector
tab to reconstruct full snapshots from the stream. Both sides must
agree — a mismatch produces garbled output.
## GUI client (`gui_client.py`)
```bash
python gui_client.py
```
Dark theme. Three tabs:
### Connector tab
Enter host and port, then click **Connect**. Settings are saved automatically
and restored on the next launch. All plot data is cleared on each
connect so fresh server history is never mixed with stale local data.
### 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:
* **Time window spinner** — show the last 124 hours (per plot).
* **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.
* When available data is less than the selected window, the x-axis adjusts
to the actual data extent — no empty gap on the left.
Trace selections, time windows, and connection settings are persisted to
`~/.config/we_monitor/plot_settings.json` and restored automatically on
the next launch.
## CLI test client (`client.py`)
```bash
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.