From 34163453bc52632da959228e310e89b3fc1bcb06 Mon Sep 17 00:00:00 2001 From: "firstof9@gmail.com" Date: Fri, 21 Aug 2026 11:37:46 -0700 Subject: [PATCH 1/3] docs: add agent skills and instructions for autonomous coding - Add AGENTS.md with architecture overview, mixin design, session rules, testing patterns, and PR guidelines - Add openevse-dev-workflow skill for running test, lint, and typecheck commands - Add openevse-api-guide skill for endpoints, RAPI commands, version checks, and exception conventions --- .agents/skills/openevse-api-guide/SKILL.md | 78 +++++++++++++ .agents/skills/openevse-dev-workflow/SKILL.md | 77 +++++++++++++ AGENTS.md | 108 ++++++++++++++++++ 3 files changed, 263 insertions(+) create mode 100644 .agents/skills/openevse-api-guide/SKILL.md create mode 100644 .agents/skills/openevse-dev-workflow/SKILL.md create mode 100644 AGENTS.md diff --git a/.agents/skills/openevse-api-guide/SKILL.md b/.agents/skills/openevse-api-guide/SKILL.md new file mode 100644 index 0000000..26e4a4b --- /dev/null +++ b/.agents/skills/openevse-api-guide/SKILL.md @@ -0,0 +1,78 @@ +--- +name: openevse-api-guide +description: >- + Use this skill when implementing, refactoring, or testing OpenEVSE charger + commands, REST API endpoints, RAPI commands, properties, or exception handling in python-openevse-http. +--- + +# OpenEVSE API & Command Implementation Guide + +This skill provides architectural guidelines, endpoint conventions, and error handling patterns for developing `python-openevse-http`. + +## Architecture + +The main client `OpenEVSE` combines several mixins: +- `CommandsMixin` (`openevsehttp/commands.py`): Command execution methods. +- `PropertiesMixin` (`openevsehttp/properties.py`): Configuration & state properties. +- `SensorsMixin` (`openevsehttp/sensors.py`): Energy, current, voltage, temperature telemetry. +- `WebsocketMixin` (`openevsehttp/websocket.py`): Real-time event streams. + +## Endpoints & RAPI Commands Reference + +| Action | HTTP Endpoint (v4+) | RAPI Command (v2/v3) | Method | +| :--- | :--- | :--- | :--- | +| Status | `/status` | N/A | GET | +| Config | `/config` | N/A | GET / POST | +| Manual Override | `/override` | `$FE` (enable) / `$FS` (sleep) | GET / POST / PATCH / DELETE | +| Soft Current Limit | `/override` (charge_current) | `$SC [N\|V]` | POST | +| Shaper Mode | `/shaper` | N/A | POST | +| Divert Mode | `/divertmode` or `/config` | N/A | POST | +| Module Restart | `/restart` (`device: gateway\|evse`) | `$FR` (evse restart) | POST | +| Firmware Update | `/update` | N/A | POST (multipart or JSON URL) | + +## Firmware Version Branching + +Always check firmware compatibility using `self._version_check(min_version)`: +```python +if self._version_check("4.0.1"): + # Use HTTP REST endpoint + response = await self.process_request(url=f"{self.url}override", method="patch") +else: + # Fallback to RAPI command for older firmware + response, msg = await self.send_command("$FE" if state == 254 else "$FS") +``` + +If a feature is not supported on older firmware: +```python +if not self._version_check("4.1.0"): + _LOGGER.debug("Feature not supported for older firmware.") + raise UnsupportedFeature +``` + +## Exception Handling Conventions + +All custom exceptions inherit from `OpenEVSEError(Exception)`. + +- **`CommandFailedError`**: Raise when a command returns an error response, fails HTTP verification, or returns `$NK` / `RAPI_ERRORS`. +- **`UnknownStateError`**: Raise when prior charger state or configuration is required to determine the command payload (e.g. toggling) but is missing or `None`. +- **`FirmwareResolutionError`**: Raise when GitHub release download URL cannot be determined from the release metadata. +- **`UnsupportedFeature`**: Raise when charger firmware is below the minimum supported version for a feature. +- **`AuthenticationError`**: Raise on 401 unauthorized. + +```python +from .exceptions import CommandFailedError, UnknownStateError, UnsupportedFeature +``` + +## Writing Tests for Commands + +When testing command methods: +1. Use fixtures from `tests/conftest.py` (`test_charger`, `test_charger_v2`, `test_charger_new`). +2. Mock responses using `mock_aioclient`: + ```python + mock_aioclient.post( + TEST_URL_CONFIG, + status=200, + body='{"msg": "done"}', + ) + ``` +3. Test success paths, failure responses (`CommandFailedError`), missing state paths (`UnknownStateError`), and older firmware version behavior (`UnsupportedFeature` / RAPI commands). diff --git a/.agents/skills/openevse-dev-workflow/SKILL.md b/.agents/skills/openevse-dev-workflow/SKILL.md new file mode 100644 index 0000000..7c8f5be --- /dev/null +++ b/.agents/skills/openevse-dev-workflow/SKILL.md @@ -0,0 +1,77 @@ +--- +name: openevse-dev-workflow +description: >- + Use this skill when running tests, formatting code, checking linters, + running type checks, or managing tox environments in python-openevse-http. +--- + +# OpenEVSE Development & Testing Workflow + +This skill guides you through executing tests, linting, formatting, and type checks within the `python-openevse-http` repository. + +## Environment & Tooling + +The project uses `tox` for managing isolated virtual environments and running test tools (`pytest`, `ruff`, `mypy`). + +### 1. Running Unit Tests + +Run full test suite via tox: +```bash +tox -e py314 +``` + +To run fast targeted test runs with the existing tox environment: +```bash +# Run all tests +.tox/py314/bin/pytest + +# Run a specific test file +.tox/py314/bin/pytest tests/test_commands.py + +# Run a single test function +.tox/py314/bin/pytest tests/test_commands.py -k "test_toggle_override" + +# Run with verbose output and stdout +.tox/py314/bin/pytest -v -s tests/test_client.py +``` + +### 2. Formatting & Linting (Ruff) + +Check formatting and linting: +```bash +tox -e lint +``` + +To auto-format or auto-fix lint errors: +```bash +# Format code +.tox/lint/bin/ruff format ./ + +# Auto-fix linting issues +.tox/lint/bin/ruff check --fix openevsehttp tests +``` + +### 3. Type Checking (Mypy) + +Run static type checks: +```bash +tox -e mypy +``` +Or directly: +```bash +.tox/mypy/bin/mypy openevsehttp +``` + +### 4. Running All CI Checks Together + +Before submitting PRs or finalizing tasks, verify everything in one step: +```bash +tox -e py314,lint,mypy +``` + +### 5. Pre-commit Hooks + +Pre-commit hooks are configured via `.pre-commit-config.yaml`. They run automatically on `git commit`, or you can trigger them manually: +```bash +pre-commit run --all-files +``` diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..5cdc728 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,108 @@ +# Agent Guidelines for python-openevse-http + +This document outlines key architecture, conventions, workflows, and testing practices for agentic assistants operating in this repository. + +--- + +## 1. Project Overview & Architecture + +`python-openevse-http` is an asynchronous Python library for interacting with OpenEVSE electric vehicle chargers via their HTTP REST API, WebSocket streams, and RAPI commands. + +### Core Modules & Mixins +The main client class `OpenEVSE` in `openevsehttp/client.py` inherits from multiple mixins: +- **`openevsehttp/client.py`**: Core client lifecycle, authentication, request processing (`process_request`, `send_command`), status updates (`update`), and session management. +- **`openevsehttp/commands.py` (`CommandsMixin`)**: Charger commands (e.g. `set_override`, `toggle_override`, `clear_override`, `set_current`, `set_charge_mode`, `divert_mode`, `set_shaper`, `toggle_shaper`, `restart_wifi`, `restart_evse`, `update_firmware`). +- **`openevsehttp/properties.py` (`PropertiesMixin`)**: Charger properties, configuration parsing, state decoding (`states`, `divert_mode`), firmware version parsing. +- **`openevsehttp/sensors.py` (`SensorsMixin`)**: Sensor values, telemetry, power/voltage calculations. +- **`openevsehttp/websocket.py` (`WebsocketMixin`, `OpenEVSEWebsocket`)**: Real-time websocket communication and state change listeners. +- **`openevsehttp/exceptions.py`**: Typed library exceptions inheriting from `OpenEVSEError`. + +### Client Session Requirement +- `OpenEVSE` uses caller-provided `aiohttp.ClientSession` (via `session=...`). If not provided, accessing network operations raises `RuntimeError(ERROR_SESSION_REQUIRED)`. +- The session must run on the active event loop. + +--- + +## 2. Firmware Version Handling & RAPI Compatibility + +OpenEVSE chargers run various firmware versions (v2.x, v3.x, v4.x, v5.x) with different capabilities: +- **`self._version_check(min_version, max_version="")`**: Use this helper to conditionally execute HTTP API endpoints (v4+) versus RAPI command fallbacks (v2/v3, e.g. `$FE`, `$FS`, `$SC`, `$FR`). +- Always handle version edge cases (e.g. non-semver development strings like `4.1.2.dev`). +- Raise `UnsupportedFeature` if a feature is not supported on older firmware. + +--- + +## 3. Exception Handling + +All custom exceptions inherit from `OpenEVSEError(Exception)`: +- `CommandFailedError`: Command execution failure, RAPI rejection (`$NK`), or error HTTP response. +- `UnknownStateError`: Required state or configuration missing before command execution (e.g. toggle state). +- `FirmwareResolutionError`: GitHub release asset resolution failure. +- `AuthenticationError`: HTTP 401 / auth failures. +- `UnsupportedFeature`: Feature not available for current firmware version. +- `ParseJSONError`, `InvalidType`, `MissingMethod`, `MissingSerial`, `AlreadyListening`. + +Export all public exception classes in `openevsehttp/__init__.py`. + +--- + +## 4. Development & Testing Workflow + +### Running Tests +Use `tox` for isolated environments: +```bash +# Run unit tests on Python 3.14 / active environment +tox -e py314 + +# Or run pytest directly within the tox environment +.tox/py314/bin/pytest + +# Target specific test files +.tox/py314/bin/pytest tests/test_commands.py -k "test_toggle_override" +``` + +### Linting & Formatting +```bash +# Run ruff formatting check & linter +tox -e lint + +# Format code automatically +.tox/lint/bin/ruff format ./ + +# Run linter with auto-fixes +.tox/lint/bin/ruff check --fix openevsehttp tests +``` + +### Type Checking +```bash +tox -e mypy +# Or directly: +.tox/mypy/bin/mypy openevsehttp +``` + +--- + +## 5. Testing & Mocking Guidelines + +- Tests use `pytest` with `pytest-asyncio` (`asyncio_default_fixture_loop_scope = "function"`). +- Test fixtures in `tests/conftest.py`: + - `test_charger`: Standard v4 charger client with mocked endpoints. + - `test_charger_v2`: Legacy v2 firmware mock. + - `test_charger_new`: Newer v4 fixture with shaper and modern endpoints. + - `test_charger_auth`: Authenticated charger mock. + - `mock_aioclient`: `AiohttpClientMocker` instance for intercepting HTTP requests (`get`, `post`, `patch`, `delete`). +- Fixture data files are located in `tests/fixtures/` (`v4_json/`, `v2_json/`). + +--- + +## 6. Commit & Pull Request Guidelines + +- **Semantic PR Titles**: Use conventional commit titles matching `.github/release-drafter.yml`: + - `feat:` New features / enhancements + - `fix:` Bug fixes + - `refactor:` Refactoring / code quality + - `test:` Test additions / updates + - `docs:` Documentation changes + - `chore:` Maintenance / dependency updates +- Fill out the checklist in `.github/pull_request_template.md`. +- Ensure all tests (`tox -e py314`), linting (`tox -e lint`), and type checks (`tox -e mypy`) pass before submitting PRs. From 558387707976a51d50ec2936d0e21ed0b907cdd7 Mon Sep 17 00:00:00 2001 From: "firstof9@gmail.com" Date: Fri, 21 Aug 2026 11:40:56 -0700 Subject: [PATCH 2/3] docs: add instructions for validating endpoints against upstream OpenEVSE firmware repos --- .agents/skills/openevse-api-guide/SKILL.md | 22 ++++++++++++++++++++++ AGENTS.md | 9 ++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/.agents/skills/openevse-api-guide/SKILL.md b/.agents/skills/openevse-api-guide/SKILL.md index 26e4a4b..a819693 100644 --- a/.agents/skills/openevse-api-guide/SKILL.md +++ b/.agents/skills/openevse-api-guide/SKILL.md @@ -63,6 +63,28 @@ All custom exceptions inherit from `OpenEVSEError(Exception)`. from .exceptions import CommandFailedError, UnknownStateError, UnsupportedFeature ``` +## Validating Endpoints Against Firmware Repositories + +When adding, modifying, or debugging endpoints and RAPI commands, cross-reference against the upstream OpenEVSE firmware sources: + +- **WiFi Gateway Firmware (v3/v4/v5)**: [`OpenEVSE/ESP32_WiFi_V4.x`](https://github.com/OpenEVSE/ESP32_WiFi_V4.x) +- **Legacy WiFi Firmware (v2)**: [`OpenEVSE/ESP8266_WiFi_v2.x`](https://github.com/OpenEVSE/ESP8266_WiFi_v2.x) +- **OpenEVSE Controller Firmware (RAPI)**: [`OpenEVSE/open_evse`](https://github.com/OpenEVSE/open_evse) + +### What to Verify in Firmware Sources: +1. **Route & Method Handlers**: + - Check `src/http.cpp`, `src/web_server.cpp`, or `src/web_server.h` in `ESP32_WiFi_V4.x` to confirm HTTP methods (`GET`, `POST`, `PATCH`, `DELETE`). + - Confirm expected query parameters or JSON body fields (e.g. `divertmode=...`, `{"device": "gateway"}`, `{"charge_current": ...}`). +2. **Response Formats & Statuses**: + - Verify success and error response payloads (e.g., `{"msg": "done"}`, `{"result": "OK", "msg": "..."}`, or plain string messages like `"Current Shaper state changed"`). + - Update `SUCCESS_ANSWERS` in `openevsehttp/const.py` if new success indicators are introduced. +3. **Firmware Version Thresholds**: + - Check git history or release tags in `ESP32_WiFi_V4.x` to determine when a route or feature was introduced, ensuring accurate `_version_check("x.y.z")` values. +4. **RAPI Command Specifications**: + - Check `src/rapi.cpp` or OpenEVSE controller docs for valid RAPI commands (e.g., `$SC`, `$FE`, `$FS`, `$FR`, `$ST`) and return formats (`$OK`, `$NK`). +5. **Mock Test Fixtures**: + - Update or add mock JSON payloads under `tests/fixtures/v4_json/` and `tests/fixtures/v2_json/` to mirror real firmware response shapes. + ## Writing Tests for Commands When testing command methods: diff --git a/AGENTS.md b/AGENTS.md index 5cdc728..44339bd 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -23,13 +23,20 @@ The main client class `OpenEVSE` in `openevsehttp/client.py` inherits from multi --- -## 2. Firmware Version Handling & RAPI Compatibility +## 2. Firmware Version Handling & Upstream Validation OpenEVSE chargers run various firmware versions (v2.x, v3.x, v4.x, v5.x) with different capabilities: - **`self._version_check(min_version, max_version="")`**: Use this helper to conditionally execute HTTP API endpoints (v4+) versus RAPI command fallbacks (v2/v3, e.g. `$FE`, `$FS`, `$SC`, `$FR`). - Always handle version edge cases (e.g. non-semver development strings like `4.1.2.dev`). - Raise `UnsupportedFeature` if a feature is not supported on older firmware. +### Validating Endpoints Against Firmware Sources +When adding or updating endpoints, payload keys, or RAPI commands, cross-reference against: +- **WiFi Gateway (v3/v4/v5)**: [`OpenEVSE/ESP32_WiFi_V4.x`](https://github.com/OpenEVSE/ESP32_WiFi_V4.x) (routes in `src/http.cpp`, `src/web_server.cpp`) +- **Legacy WiFi (v2)**: [`OpenEVSE/ESP8266_WiFi_v2.x`](https://github.com/OpenEVSE/ESP8266_WiFi_v2.x) +- **Controller / RAPI**: [`OpenEVSE/open_evse`](https://github.com/OpenEVSE/open_evse) (commands in `src/rapi.cpp`) +Verify HTTP methods, expected JSON fields, success/error payload shapes, and version thresholds. + --- ## 3. Exception Handling From a4df1f89e7bf79a6487080d99bf6c7766ed39b09 Mon Sep 17 00:00:00 2001 From: "firstof9@gmail.com" Date: Fri, 21 Aug 2026 11:43:07 -0700 Subject: [PATCH 3/3] docs: add instructions for using PR and issue templates --- .agents/skills/openevse-dev-workflow/SKILL.md | 10 +++++++++ AGENTS.md | 21 +++++++++++++++---- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/.agents/skills/openevse-dev-workflow/SKILL.md b/.agents/skills/openevse-dev-workflow/SKILL.md index 7c8f5be..5be3888 100644 --- a/.agents/skills/openevse-dev-workflow/SKILL.md +++ b/.agents/skills/openevse-dev-workflow/SKILL.md @@ -75,3 +75,13 @@ Pre-commit hooks are configured via `.pre-commit-config.yaml`. They run automati ```bash pre-commit run --all-files ``` + +### 6. Pull Requests & Issue Creation + +- **Pull Requests**: + - Always use the template in [`.github/pull_request_template.md`](../../.github/pull_request_template.md). + - Include a summary, issue link (`Fixes #`), type of change, and completed checklist. + - Follow conventional commits in PR titles (`feat:`, `fix:`, `refactor:`, `test:`, `docs:`, `chore:`). +- **Issues & Feature Requests**: + - Use [`.github/ISSUE_TEMPLATE/bug_report.yml`](../../.github/ISSUE_TEMPLATE/bug_report.yml) for bugs (`[Bug]: `). + - Use [`.github/ISSUE_TEMPLATE/feature_request.yml`](../../.github/ISSUE_TEMPLATE/feature_request.yml) for feature requests (`[Feature Request]: `). diff --git a/AGENTS.md b/AGENTS.md index 44339bd..8e515c3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -102,14 +102,27 @@ tox -e mypy --- -## 6. Commit & Pull Request Guidelines - -- **Semantic PR Titles**: Use conventional commit titles matching `.github/release-drafter.yml`: +## 6. Commit, Pull Request & Issue Guidelines + +### Creating Pull Requests +- **Use the PR Template**: Always structure PR descriptions according to [`.github/pull_request_template.md`](.github/pull_request_template.md): + - **Description**: Provide a clear summary of changes, motivation, and link related issues (`Fixes #`). + - **Type of change**: Check the relevant boxes (`Bug fix`, `New feature`, `Breaking change`, `Code quality / Refactoring`, `Documentation update`). + - **Checklist**: Complete all checklist items before opening or marking ready for review. +- **Semantic PR Titles**: Use conventional commit titles matching [`.github/release-drafter.yml`](.github/release-drafter.yml): - `feat:` New features / enhancements - `fix:` Bug fixes - `refactor:` Refactoring / code quality - `test:` Test additions / updates - `docs:` Documentation changes - `chore:` Maintenance / dependency updates -- Fill out the checklist in `.github/pull_request_template.md`. - Ensure all tests (`tox -e py314`), linting (`tox -e lint`), and type checks (`tox -e mypy`) pass before submitting PRs. + +### Creating Issues & Feature Requests +Always follow the templates in [`.github/ISSUE_TEMPLATE/`](.github/ISSUE_TEMPLATE/): +- **Bug Reports** ([`bug_report.yml`](.github/ISSUE_TEMPLATE/bug_report.yml)): + - Prefix title with `[Bug]: `. + - Include: Description, Steps to Reproduce, Expected Behavior, Environment Info (Library version, Python version, OpenEVSE WiFi Firmware version), and Debug Logs / Stack Trace. +- **Feature Requests** ([`feature_request.yml`](.github/ISSUE_TEMPLATE/feature_request.yml)): + - Prefix title with `[Feature Request]: `. + - Include: Problem statement, Desired solution, Alternatives considered, and Context.