Update README to match codebase
This commit is contained in:
159
README.md
159
README.md
@ -1,53 +1,77 @@
|
|||||||
# OBD2 Terminal Dashboard
|
# OBD2 Terminal Dashboard
|
||||||
|
|
||||||
This repository contains a Textual-based terminal dashboard for querying an OBD-II adapter and presenting live vehicle telemetry alongside raw command output.
|
This repository contains a Textual-based terminal dashboard for querying an OBD-II adapter and rendering live telemetry, per-command values, editable cache TTLs, and application logs in one terminal UI.
|
||||||
|
|
||||||
`scanbus.py` is intentionally excluded from this README.
|
## Overview
|
||||||
|
|
||||||
## What It Does
|
The application combines:
|
||||||
|
|
||||||
- Displays live dashboard metrics for speed, RPM, fuel level, oil temperature, and coolant temperature.
|
- A Textual dashboard for live vehicle data
|
||||||
- Renders a command table for OBD modes `01`, `02`, `03`, `04`, `06`, `07`, and `09`.
|
- An async OBD interface built on `python-OBD`
|
||||||
- Polls commands asynchronously with a global queries-per-second limit.
|
- A per-command TTL cache with hot-reloaded overrides from `command_ttl.conf`
|
||||||
- Deduplicates concurrent reads of the same OBD command.
|
- A simulated adapter path for development and tests
|
||||||
- Caches command results using a default TTL plus per-command overrides from `command_ttl.conf`.
|
|
||||||
- Supports a simulated mode for UI development without a physical adapter.
|
The primary entry point is [`obd2_tui.py`](/Users/jallen/workspace/obd2/obd2_tui.py).
|
||||||
- Streams application logs inside the terminal UI.
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Displays live metrics for speed, RPM, fuel level, coolant temperature, and oil temperature
|
||||||
|
- Shows command data for OBD modes `01`, `02`, `03`, `04`, `06`, `07`, and `09`
|
||||||
|
- Polls core telemetry continuously while only querying table rows visible in the current viewport
|
||||||
|
- Deduplicates concurrent reads of the same OBD command through a shared pending-query map
|
||||||
|
- Enforces a global query-per-second limit across all outbound adapter requests
|
||||||
|
- Caches command results with a default TTL plus command-specific overrides
|
||||||
|
- Reloads TTL overrides automatically when `command_ttl.conf` changes
|
||||||
|
- Lets the user edit a selected command TTL directly from the UI
|
||||||
|
- Supports simulated telemetry for local development without hardware
|
||||||
|
- Streams logs into the application log panel
|
||||||
|
|
||||||
## Repository Layout
|
## Repository Layout
|
||||||
|
|
||||||
- `obd2_tui.py`: main Textual app, CLI entry point, keyboard bindings, command polling, and inline TTL editing.
|
- [`obd2_tui.py`](/Users/jallen/workspace/obd2/obd2_tui.py): Textual application, CLI parsing, mode switching, viewport-aware polling, and TTL editing
|
||||||
- `obd2_interface.py`: async OBD abstraction, connection lifecycle, rate limiting, caching, TTL config reloads, and simulation support.
|
- [`obd2_interface.py`](/Users/jallen/workspace/obd2/obd2_interface.py): adapter connection lifecycle, rate limiting, caching, TTL config reloads, and simulated interface support
|
||||||
- `models.py`: Pydantic models for the live telemetry report and scan definitions.
|
- [`models.py`](/Users/jallen/workspace/obd2/models.py): Pydantic models for shared telemetry state and scan definitions
|
||||||
- `ui.css`: Textual stylesheet for the dashboard, command table, and log panel.
|
- [`ui.css`](/Users/jallen/workspace/obd2/ui.css): Textual styling for the dashboard, data table, TTL editor, and log panel
|
||||||
- `command_ttl.conf`: command-specific cache TTL overrides in milliseconds.
|
- [`command_ttl.conf`](/Users/jallen/workspace/obd2/command_ttl.conf): command-specific cache TTL overrides in milliseconds
|
||||||
- `test.py`: unit tests for report normalization, interface behavior, caching, TTL updates, simulation, and UI helpers.
|
- [`test.py`](/Users/jallen/workspace/obd2/test.py): unit tests covering report normalization, interface behavior, simulation, caching, and UI helpers
|
||||||
- `requirements.txt`: Python dependencies.
|
- [`requirements.txt`](/Users/jallen/workspace/obd2/requirements.txt): Python dependencies
|
||||||
|
|
||||||
## Architecture
|
## How It Works
|
||||||
|
|
||||||
The application has two main layers:
|
### UI layer
|
||||||
|
|
||||||
1. `OBD2App` in `obd2_tui.py`
|
`OBD2App` builds a dashboard with:
|
||||||
- Builds the terminal UI with Textual.
|
|
||||||
- Polls a small set of key telemetry commands continuously for the metric cards.
|
|
||||||
- Polls the currently visible rows in the selected OBD mode table.
|
|
||||||
- Lets the user edit a selected command's cache TTL from the UI.
|
|
||||||
|
|
||||||
2. `OBD2Interface` in `obd2_interface.py`
|
- Five metric cards
|
||||||
- Connects to the adapter through `python-OBD`.
|
- A command table for the selected OBD mode
|
||||||
- Serializes outbound queries through a worker queue.
|
- A TTL editor bound to the highlighted command
|
||||||
- Enforces a global rate limit.
|
- An in-app log panel
|
||||||
- Maintains a TTL cache keyed by command name.
|
|
||||||
- Watches `command_ttl.conf` and hot-reloads TTL overrides.
|
|
||||||
|
|
||||||
`SimulatedOBD2Interface` swaps in a fake connection that generates dynamic values for development and testing.
|
The app refresh loop does two things on each pass:
|
||||||
|
|
||||||
|
1. Queries the five telemetry commands needed for the metric cards
|
||||||
|
2. Queries only the currently visible command rows for the selected mode
|
||||||
|
|
||||||
|
Results are then applied back into the metric displays and table cells.
|
||||||
|
|
||||||
|
### Interface layer
|
||||||
|
|
||||||
|
`OBD2Interface` is responsible for:
|
||||||
|
|
||||||
|
- Connecting to the OBD adapter
|
||||||
|
- Serializing outbound queries through a worker queue
|
||||||
|
- Enforcing the global QPS limit
|
||||||
|
- Caching query results by command name
|
||||||
|
- Deduplicating in-flight requests for the same command
|
||||||
|
- Loading and reloading TTL overrides from disk
|
||||||
|
|
||||||
|
If a live adapter is unavailable, `SimulatedOBD2Interface` uses a synthetic connection that generates changing telemetry values and a few representative string responses such as VIN and DTC output.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- Python 3.11+ recommended
|
- Python 3.11 or newer recommended
|
||||||
- An ELM327-compatible OBD-II adapter for real vehicle data
|
- An ELM327-compatible OBD-II adapter for real vehicle data
|
||||||
- Terminal support suitable for a Textual application
|
- A terminal environment that supports Textual applications
|
||||||
|
|
||||||
Install dependencies:
|
Install dependencies:
|
||||||
|
|
||||||
@ -59,7 +83,7 @@ pip install -r requirements.txt
|
|||||||
|
|
||||||
## Running
|
## Running
|
||||||
|
|
||||||
Run against a real OBD adapter:
|
Run against a real adapter:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 obd2_tui.py
|
python3 obd2_tui.py
|
||||||
@ -71,10 +95,11 @@ Run in simulated mode:
|
|||||||
python3 obd2_tui.py --simulated
|
python3 obd2_tui.py --simulated
|
||||||
```
|
```
|
||||||
|
|
||||||
Optional flags:
|
Available flags:
|
||||||
|
|
||||||
- `--qps`: maximum OBD queries per second across the app. Default: `10.0`
|
- `--simulated`: use generated telemetry instead of a hardware adapter
|
||||||
- `--ttl-config`: path to the TTL override file. Default: `command_ttl.conf`
|
- `--qps`: maximum OBD queries per second across the app, default `10.0`
|
||||||
|
- `--ttl-config`: path to the TTL override file, default `command_ttl.conf`
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@ -82,40 +107,25 @@ Example:
|
|||||||
python3 obd2_tui.py --simulated --qps 25 --ttl-config command_ttl.conf
|
python3 obd2_tui.py --simulated --qps 25 --ttl-config command_ttl.conf
|
||||||
```
|
```
|
||||||
|
|
||||||
## UI Behavior
|
|
||||||
|
|
||||||
The dashboard is composed of:
|
|
||||||
|
|
||||||
- Metric cards for the five primary telemetry values
|
|
||||||
- A command table for the selected OBD mode
|
|
||||||
- A TTL editor bound to the currently highlighted command
|
|
||||||
- An in-app log panel
|
|
||||||
|
|
||||||
The polling strategy is selective:
|
|
||||||
|
|
||||||
- Core telemetry commands are always queried so the metric cards stay current.
|
|
||||||
- The mode table queries only commands that are currently visible in the viewport.
|
|
||||||
- Duplicate requests for the same command are coalesced through the interface queue and cache.
|
|
||||||
|
|
||||||
## Keyboard Controls
|
## Keyboard Controls
|
||||||
|
|
||||||
- `q`: quit
|
- `q`: quit
|
||||||
- `b`: toggle metric card border style
|
- `b`: toggle metric card border style
|
||||||
- `e`: focus the TTL editor
|
- `e`: focus the TTL editor
|
||||||
- `escape`: return focus to the command table
|
- `escape`: return focus to the command table
|
||||||
- `left` / `right`: previous or next OBD mode
|
- `left` / `right`: switch to the previous or next OBD mode
|
||||||
- `shift+up` / `shift+down`: jump to top or bottom of the table
|
- `shift+up` / `shift+down`: jump to the top or bottom of the table
|
||||||
- `1`, `2`, `3`, `4`, `6`, `7`, `9`: switch directly to that OBD mode
|
- `1`, `2`, `3`, `4`, `6`, `7`, `9`: jump directly to a supported OBD mode
|
||||||
|
|
||||||
## TTL Configuration
|
## TTL Configuration
|
||||||
|
|
||||||
`command_ttl.conf` uses the format:
|
`command_ttl.conf` uses:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
COMMAND_NAME,ttl_ms
|
COMMAND_NAME,ttl_ms
|
||||||
```
|
```
|
||||||
|
|
||||||
Examples:
|
Example:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
SPEED,10
|
SPEED,10
|
||||||
@ -126,35 +136,26 @@ GET_DTC,86400000
|
|||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
|
|
||||||
- TTL values are stored in milliseconds.
|
- TTL values are stored in milliseconds
|
||||||
- A value of `0` effectively disables caching for that command.
|
- `0` disables caching for that command
|
||||||
- The app reloads the file automatically while running.
|
- Blank lines and comment lines beginning with `#` are ignored
|
||||||
- Editing a TTL in the UI writes the updated value back to the configured TTL file.
|
- Editing a value in the UI writes the updated TTL back to the configured file
|
||||||
|
- The interface reloads TTL overrides automatically while the app is running
|
||||||
|
|
||||||
|
The TTL editor accepts plain millisecond values as well as duration suffixes such as `10ms`, `30s`, `1m`, and `1h`.
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
Run the unit tests with:
|
Run the test suite with:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 -m unittest -v test.py
|
python3 -m unittest -v test.py
|
||||||
```
|
```
|
||||||
|
|
||||||
The tests cover:
|
The current workspace environment has the required dependencies installed, and this command passes.
|
||||||
|
|
||||||
- Report value normalization
|
## Notes
|
||||||
- Query rate limiting
|
|
||||||
- Cache hit and cache expiry behavior
|
|
||||||
- TTL override parsing and persistence
|
|
||||||
- Simulated connection behavior
|
|
||||||
- Display formatting and duration parsing helpers
|
|
||||||
|
|
||||||
## Current Environment Note
|
- The terminal dashboard is the main supported runtime path
|
||||||
|
- [`obd2_interface.py`](/Users/jallen/workspace/obd2/obd2_interface.py) also includes a standalone `__main__` path that logs report snapshots outside the TUI
|
||||||
In the current workspace environment, `python3 -m unittest -v test.py` fails immediately because `pydantic` is not installed. After installing dependencies from `requirements.txt`, the test command should be rerun.
|
- Logging is routed into the UI through a custom `logging.Handler`
|
||||||
|
|
||||||
## Development Notes
|
|
||||||
|
|
||||||
- Logging is routed into the Textual `RichLog` panel through a custom logging handler.
|
|
||||||
- The codebase uses `Report` as the shared mutable telemetry state for the UI.
|
|
||||||
- `command_ttl.conf` is large because it predefines cache behavior for many standard OBD commands.
|
|
||||||
- `obd2_interface.py` also contains a non-TUI `__main__` path that continuously logs report snapshots, but the primary entry point for normal use is `obd2_tui.py`.
|
|
||||||
|
|||||||
Reference in New Issue
Block a user