Update README for server/client split
Reflect new layout (server/, client/), separate requirements.txt files, python -m server.main entry point, and server/install.sh location. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,45 +7,40 @@ A PyQt5 GUI client visualises the data in real time.
|
|||||||
## Repository layout
|
## Repository layout
|
||||||
|
|
||||||
```
|
```
|
||||||
collect.py — collector daemon (entry point)
|
|
||||||
gui_client.py — PyQt5 GUI client
|
|
||||||
client.py — minimal CLI test client
|
|
||||||
server/
|
server/
|
||||||
|
main.py — collector entry point (CLI + credential loading)
|
||||||
|
collect.py — run() main loop
|
||||||
data_model.py — domain extractors, collect_snapshot()
|
data_model.py — domain extractors, collect_snapshot()
|
||||||
network.py — TCP push server (accept loop + broadcast)
|
network.py — TCP push server (accept loop + broadcast)
|
||||||
storage_helpers.py — load / save JSON store, midnight rotation helpers
|
storage_helpers.py — load / save JSON store, midnight rotation helpers
|
||||||
we_connect.py — CarConnectivity login and vehicle selection
|
we_connect.py — CarConnectivity login and vehicle selection
|
||||||
log_config.py — logging setup
|
log_config.py — logging setup
|
||||||
utils/
|
requirements.txt — server dependencies
|
||||||
jay_diff.py — JSON diff / merge library
|
install.sh — systemd user service installer (server only)
|
||||||
|
client/
|
||||||
|
gui_client.py — PyQt5 GUI client
|
||||||
|
client.py — minimal CLI test client
|
||||||
|
requirements.txt — client dependencies
|
||||||
credentials/ — JSON config files (gitignored)
|
credentials/ — JSON config files (gitignored)
|
||||||
requirements.txt
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Requirements
|
## Server
|
||||||
|
|
||||||
```
|
### Install (systemd user service)
|
||||||
pip install carconnectivity carconnectivity-connector-volkswagen PyQt5 pyqtgraph
|
|
||||||
```
|
|
||||||
|
|
||||||
Or use the installer which also sets up a systemd user service:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
cd server
|
||||||
|
chmod +x install.sh
|
||||||
./install.sh
|
./install.sh
|
||||||
|
# then edit ~/.config/we_monitor/credentials.json
|
||||||
|
systemctl --user start we_monitor
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
### Manual start
|
||||||
|
|
||||||
## Collector (`collect.py`)
|
|
||||||
|
|
||||||
Connects via CarConnectivity, polls selected domains at a configurable interval, and
|
|
||||||
appends timestamped 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
|
```bash
|
||||||
python collect.py -c credentials/my_car.json
|
pip install -r server/requirements.txt
|
||||||
|
python -m server.main -c credentials/my_car.json
|
||||||
```
|
```
|
||||||
|
|
||||||
Username and password can also be supplied via environment variables
|
Username and password can also be supplied via environment variables
|
||||||
@@ -54,7 +49,7 @@ Username and password can also be supplied via environment variables
|
|||||||
```bash
|
```bash
|
||||||
export WC_USER=me@example.com
|
export WC_USER=me@example.com
|
||||||
export WC_PASS=secret
|
export WC_PASS=secret
|
||||||
python collect.py -c credentials/my_car.json
|
python -m server.main -c credentials/my_car.json
|
||||||
```
|
```
|
||||||
|
|
||||||
### Credentials file
|
### Credentials file
|
||||||
@@ -166,27 +161,33 @@ The first message sent to a new client is always `jay_diff_full({}, record[0])`,
|
|||||||
i.e. an `update_add` containing every field of the first record. Subsequent
|
i.e. an `update_add` containing every field of the first record. Subsequent
|
||||||
messages contain only the fields that changed.
|
messages contain only the fields that changed.
|
||||||
|
|
||||||
Enable `--diff` on the server **and** on the client (`client.py --diff` or the
|
Enable `--diff` on the server **and** on the client (`client/client.py --diff` or the
|
||||||
**Diff mode** checkbox in the GUI Connector tab). Both sides must agree — a
|
**Diff mode** checkbox in the GUI Connector tab). Both sides must agree — a
|
||||||
mismatch produces garbled output.
|
mismatch produces garbled output.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## GUI client (`gui_client.py`)
|
## Client
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python gui_client.py
|
pip install -r client/requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### GUI client (`client/gui_client.py`)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python client/gui_client.py
|
||||||
```
|
```
|
||||||
|
|
||||||
Dark-theme PyQt5 application. Three tabs: **Connector**, **Dashboard**,
|
Dark-theme PyQt5 application. Three tabs: **Connector**, **Dashboard**,
|
||||||
**Plot**. Connection settings, trace selections, and time windows are persisted
|
**Plot**. Connection settings, trace selections, and time windows are persisted
|
||||||
to `~/.config/we_monitor/plot_settings.json` and restored on the next launch.
|
to `~/.config/we_monitor/plot_settings.json` and restored on the next launch.
|
||||||
|
|
||||||
### Connector tab
|
#### Connector tab
|
||||||
|
|
||||||
| Control | Description |
|
| Control | Description |
|
||||||
|---------|-------------|
|
|---------|-------------|
|
||||||
| **Host / Port** | Address of the `collect.py` push server |
|
| **Host / Port** | Address of the push server |
|
||||||
| **Diff mode** checkbox | Must match the server's `--diff` setting |
|
| **Diff mode** checkbox | Must match the server's `--diff` setting |
|
||||||
| **Connect / Disconnect** | Opens or closes the TCP connection |
|
| **Connect / Disconnect** | Opens or closes the TCP connection |
|
||||||
| **Status** | Shows `Connected`, `Disconnected`, or the error message |
|
| **Status** | Shows `Connected`, `Disconnected`, or the error message |
|
||||||
@@ -195,18 +196,18 @@ Clicking **Connect** saves the current host, port, and diff-mode setting. All
|
|||||||
plot data is cleared on each connect so the fresh server history is never mixed
|
plot data is cleared on each connect so the fresh server history is never mixed
|
||||||
with stale local data.
|
with stale local data.
|
||||||
|
|
||||||
### Dashboard tab
|
#### Dashboard tab
|
||||||
|
|
||||||
Live tree view of the most recent snapshot. The hierarchy mirrors the JSON
|
Live tree view of the most recent snapshot. The hierarchy mirrors the JSON
|
||||||
structure: domain → status object → field, with value and unit shown inline.
|
structure: domain → status object → field, with value and unit shown inline.
|
||||||
Expand / collapse state is preserved across updates.
|
Expand / collapse state is preserved across updates.
|
||||||
|
|
||||||
### Plot tab
|
#### Plot tab
|
||||||
|
|
||||||
Eight plots arranged in a 4 × 2 scrollable grid. Each plot is independent and
|
Eight plots arranged in a 4 × 2 scrollable grid. Each plot is independent and
|
||||||
has its own control bar.
|
has its own control bar.
|
||||||
|
|
||||||
#### Control bar (per plot)
|
**Control bar (per plot)**
|
||||||
|
|
||||||
| Control | Description |
|
| Control | Description |
|
||||||
|---------|-------------|
|
|---------|-------------|
|
||||||
@@ -216,7 +217,7 @@ has its own control bar.
|
|||||||
| **Time window spinner** | Show the last 1–24 hours of data (per plot) |
|
| **Time window spinner** | Show the last 1–24 hours of data (per plot) |
|
||||||
| **Date label** (right-aligned) | Shows the calendar date(s) of the visible window — single date or `YYYY-MM-DD – YYYY-MM-DD` when the view spans midnight |
|
| **Date label** (right-aligned) | Shows the calendar date(s) of the visible window — single date or `YYYY-MM-DD – YYYY-MM-DD` when the view spans midnight |
|
||||||
|
|
||||||
#### Plot area
|
**Plot area**
|
||||||
|
|
||||||
* **X axis** — time of day in `HH:MM:SS` format; no locale-dependent date prefix.
|
* **X axis** — time of day in `HH:MM:SS` format; no locale-dependent date prefix.
|
||||||
* **Y axis** — auto-zooms to fit the visible data on the first draw after connect
|
* **Y axis** — auto-zooms to fit the visible data on the first draw after connect
|
||||||
@@ -227,7 +228,7 @@ has its own control bar.
|
|||||||
sampled value for every active trace, with a colored bullet and unit.
|
sampled value for every active trace, with a colored bullet and unit.
|
||||||
* **Legend** — trace names and colors, shown inside the plot area.
|
* **Legend** — trace names and colors, shown inside the plot area.
|
||||||
|
|
||||||
#### Mouse interaction
|
**Mouse interaction**
|
||||||
|
|
||||||
| Action | Effect |
|
| Action | Effect |
|
||||||
|--------|--------|
|
|--------|--------|
|
||||||
@@ -236,13 +237,11 @@ has its own control bar.
|
|||||||
| Click + drag | Pan the view |
|
| Click + drag | Pan the view |
|
||||||
| Right-click | pyqtgraph context menu (export, auto-range, …) |
|
| Right-click | pyqtgraph context menu (export, auto-range, …) |
|
||||||
|
|
||||||
---
|
### CLI test client (`client/client.py`)
|
||||||
|
|
||||||
## CLI test client (`client.py`)
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python client.py --host 192.168.1.10 --port 9999
|
python client/client.py --host 192.168.1.10 --port 9999
|
||||||
python client.py --diff # reconstruct from diff stream
|
python client/client.py --diff # reconstruct from diff stream
|
||||||
```
|
```
|
||||||
|
|
||||||
Connects to the push server and prints every incoming snapshot as
|
Connects to the push server and prints every incoming snapshot as
|
||||||
@@ -258,11 +257,15 @@ pretty-printed JSON with a running record counter.
|
|||||||
|
|
||||||
## Module reference
|
## Module reference
|
||||||
|
|
||||||
### `collect.py`
|
### `server/main.py`
|
||||||
|
|
||||||
Entry point for the collector daemon. Parses CLI / credentials-file arguments,
|
Entry point for the collector daemon. Parses CLI / credentials-file arguments
|
||||||
establishes the CarConnectivity session, starts the push server, and runs the main
|
and calls `run()`.
|
||||||
poll loop.
|
|
||||||
|
### `server/collect.py`
|
||||||
|
|
||||||
|
`run(args)` — establishes the CarConnectivity session, starts the push server,
|
||||||
|
and runs the main poll loop.
|
||||||
|
|
||||||
### `server/data_model.py`
|
### `server/data_model.py`
|
||||||
|
|
||||||
@@ -315,22 +318,7 @@ Authenticates and returns a connected `CarConnectivity` instance.
|
|||||||
`select_vehicle(wc, vin) → (vehicle, error)`
|
`select_vehicle(wc, vin) → (vehicle, error)`
|
||||||
Returns the target vehicle (first available if `vin` is empty) or an error string.
|
Returns the target vehicle (first available if `vin` is empty) or an error string.
|
||||||
|
|
||||||
### `utils/jay_diff.py`
|
### `client/gui_client.py` — class overview
|
||||||
|
|
||||||
Lightweight JSON diff / patch library.
|
|
||||||
|
|
||||||
`jay_diff_full(old, new, combine_upd_add=True) → dict`
|
|
||||||
Computes a diff between two dicts. With `combine_upd_add=True` (the default
|
|
||||||
used everywhere in this project) the result uses `update_add` for all additions
|
|
||||||
and updates, plus a separate `delete` key. Returns `{}` when nothing changed.
|
|
||||||
|
|
||||||
`jay_merge_full(old, diff) → dict`
|
|
||||||
Applies a `jay_diff_full` diff to `old`. The diff structure is self-describing:
|
|
||||||
if `diff` contains none of the known diff keys (`update`, `update_add`, `add`,
|
|
||||||
`delete`) and `old` is empty, `diff` is returned as-is (full-snapshot
|
|
||||||
passthrough for bootstrap).
|
|
||||||
|
|
||||||
### `gui_client.py` — class overview
|
|
||||||
|
|
||||||
| Class | Role |
|
| Class | Role |
|
||||||
|-------|------|
|
|-------|------|
|
||||||
|
|||||||
Reference in New Issue
Block a user