From ab2efb3d8b80638959708c8eb688f2477999dab0 Mon Sep 17 00:00:00 2001 From: Jimmy Allen Date: Wed, 1 Apr 2026 20:20:37 -0400 Subject: [PATCH] Update README to match codebase --- README.md | 159 +++++++++++++++++++++++++++--------------------------- 1 file changed, 80 insertions(+), 79 deletions(-) diff --git a/README.md b/README.md index 4d2d6db..e87799d 100644 --- a/README.md +++ b/README.md @@ -1,53 +1,77 @@ # 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. -- Renders a command table for OBD modes `01`, `02`, `03`, `04`, `06`, `07`, and `09`. -- Polls commands asynchronously with a global queries-per-second limit. -- Deduplicates concurrent reads of the same OBD command. -- 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. -- Streams application logs inside the terminal UI. +- A Textual dashboard for live vehicle data +- An async OBD interface built on `python-OBD` +- A per-command TTL cache with hot-reloaded overrides from `command_ttl.conf` +- A simulated adapter path for development and tests + +The primary entry point is [`obd2_tui.py`](/Users/jallen/workspace/obd2/obd2_tui.py). + +## 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 -- `obd2_tui.py`: main Textual app, CLI entry point, keyboard bindings, command polling, and inline TTL editing. -- `obd2_interface.py`: async OBD abstraction, connection lifecycle, rate limiting, caching, TTL config reloads, and simulation support. -- `models.py`: Pydantic models for the live telemetry report and scan definitions. -- `ui.css`: Textual stylesheet for the dashboard, command table, and log panel. -- `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. -- `requirements.txt`: Python dependencies. +- [`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`](/Users/jallen/workspace/obd2/obd2_interface.py): adapter connection lifecycle, rate limiting, caching, TTL config reloads, and simulated interface support +- [`models.py`](/Users/jallen/workspace/obd2/models.py): Pydantic models for shared telemetry state and scan definitions +- [`ui.css`](/Users/jallen/workspace/obd2/ui.css): Textual styling for the dashboard, data table, TTL editor, and log panel +- [`command_ttl.conf`](/Users/jallen/workspace/obd2/command_ttl.conf): command-specific cache TTL overrides in milliseconds +- [`test.py`](/Users/jallen/workspace/obd2/test.py): unit tests covering report normalization, interface behavior, simulation, caching, and UI helpers +- [`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` - - 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. +`OBD2App` builds a dashboard with: -2. `OBD2Interface` in `obd2_interface.py` - - Connects to the adapter through `python-OBD`. - - Serializes outbound queries through a worker queue. - - Enforces a global rate limit. - - Maintains a TTL cache keyed by command name. - - Watches `command_ttl.conf` and hot-reloads TTL overrides. +- Five metric cards +- A command table for the selected OBD mode +- A TTL editor bound to the highlighted command +- An in-app log panel -`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 -- Python 3.11+ recommended +- Python 3.11 or newer recommended - 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: @@ -59,7 +83,7 @@ pip install -r requirements.txt ## Running -Run against a real OBD adapter: +Run against a real adapter: ```bash python3 obd2_tui.py @@ -71,10 +95,11 @@ Run in simulated mode: python3 obd2_tui.py --simulated ``` -Optional flags: +Available flags: -- `--qps`: maximum OBD queries per second across the app. Default: `10.0` -- `--ttl-config`: path to the TTL override file. Default: `command_ttl.conf` +- `--simulated`: use generated telemetry instead of a hardware adapter +- `--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: @@ -82,40 +107,25 @@ Example: 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 - `q`: quit - `b`: toggle metric card border style - `e`: focus the TTL editor - `escape`: return focus to the command table -- `left` / `right`: previous or next OBD mode -- `shift+up` / `shift+down`: jump to top or bottom of the table -- `1`, `2`, `3`, `4`, `6`, `7`, `9`: switch directly to that OBD mode +- `left` / `right`: switch to the previous or next OBD mode +- `shift+up` / `shift+down`: jump to the top or bottom of the table +- `1`, `2`, `3`, `4`, `6`, `7`, `9`: jump directly to a supported OBD mode ## TTL Configuration -`command_ttl.conf` uses the format: +`command_ttl.conf` uses: ```text COMMAND_NAME,ttl_ms ``` -Examples: +Example: ```text SPEED,10 @@ -126,35 +136,26 @@ GET_DTC,86400000 Notes: -- TTL values are stored in milliseconds. -- A value of `0` effectively disables caching for that command. -- The app reloads the file automatically while running. -- Editing a TTL in the UI writes the updated value back to the configured TTL file. +- TTL values are stored in milliseconds +- `0` disables caching for that command +- Blank lines and comment lines beginning with `#` are ignored +- 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 -Run the unit tests with: +Run the test suite with: ```bash 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 -- Query rate limiting -- Cache hit and cache expiry behavior -- TTL override parsing and persistence -- Simulated connection behavior -- Display formatting and duration parsing helpers +## Notes -## Current Environment Note - -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. - -## 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`. +- 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 +- Logging is routed into the UI through a custom `logging.Handler`