Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions .claude/skills/release/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
---
name: release
description: Cut a new batcontrol release. Use when asked to prepare, create, or finalize a release, bump the version for a release, or write release notes. Covers the prepare-release workflow, release notes, tagging, and the follow-up steps (next dev version, HA add-on promotion).
---

# Release batcontrol

Versioning: `X.Y.Zdev` during development, `X.Y.Z` for releases. The version lives in
`src/batcontrol/__pkginfo__.py` (`__version__`) and is mirrored in
`pyproject.toml` `[tool.bumpversion] current_version`. All version changes go through
`bump-my-version` (config in `pyproject.toml`) — never edit the version by hand, the two
locations would drift.

Execution policy: run the preparation steps directly, but STOP and ask for confirmation
before every irreversible/outward-facing action — triggering the Prepare Release workflow,
pushing a tag, and publishing the GitHub release.

## Step 1 — Preconditions (check, do not skip)

1. Current version is a `dev` version (`grep __version__ src/batcontrol/__pkginfo__.py`).
2. `main` is green: latest runs of the `pytest` and `pylint` workflows passed.
3. All PRs intended for the release are merged; nothing release-critical open.
4. `./run_tests.sh` passes locally.
5. Docs for new features exist under `docs/` (they publish independently via `docs.yml`).

## Step 2 — Draft the release notes

The Prepare Release workflow creates the GitHub release body with a placeholder — the notes
are written by hand. Draft them now:

1. Find the previous release tag: `git tag --sort=-v:refname | head -1` (or the GitHub
releases page if the local clone has no tags).
2. Collect merged changes since then: `git log <prev-tag>..main --oneline --merges` or the
GitHub compare view; group by category the way the HA add-on changelog does
(Major New Features / Enhancements / Technical Updates / Breaking Changes), one bullet
per change with PR number `(#NNN)`.
3. Keep the draft ready — it is pasted into the draft release in Step 4.

## Step 3 — Run the Prepare Release workflow [CONFIRM FIRST]

Preferred path — trigger `prepare-release.yml` (workflow_dispatch, on `main`) via the GitHub
MCP actions tools or the GitHub UI (Actions -> "Prepare Release" -> Run workflow). It:

- runs `bump-my-version bump release --commit` (drops the `dev` suffix, e.g.
`0.8.1dev` -> `0.8.1`),
- builds wheel + sdist with `uv build --no-sources`,
- creates a **draft** GitHub release with tag `X.Y.Z` and both artifacts attached,
- opens a PR `prepare-release-<timestamp>` -> `main` with the version bump commit.

Fallback (workflow unavailable): do the same steps locally on a branch —
`uv pip install bump-my-version && bump-my-version bump release --commit`, `uv build
--no-sources .`, push branch, open PR, create the draft release with the artifacts manually.

## Step 4 — Finalize [CONFIRM before tag push and publish]

1. Review and merge the release PR into `main`.
2. Tag the merged commit: `git tag X.Y.Z <merge-commit> && git push origin X.Y.Z`.
The tag push triggers `docker-image.yml` (multi-arch Docker build).
3. Paste the release notes from Step 2 into the draft release, verify the wheel asset is
named exactly `batcontrol-X.Y.Z-py3-none-any.whl` (the HA add-on Dockerfile downloads it
under that name), then publish the release.
4. Verify the Docker image workflow run succeeds.

## Step 5 — Open the next development cycle

Bump `main` to the next dev version: trigger the `Bump version` workflow
(`bump_version.yml`) with bump-type `patch` — bump-my-version rolls `X.Y.Z` to
`X.Y.(Z+1)dev` and opens a `bump-version/...` PR. Merge it.

## Step 6 — Promote into the Home Assistant add-on

The stable HA add-on (`MaStr/batcontrol_ha_addon`, directory `batcontrol/`) pins its
`version` to a release tag and downloads that release wheel. Switch to that repo and run its
`release-addon` skill to promote this release (options/schema sync, changelog, version).

## Checklist

```
[ ] main green, tests pass locally, dev version confirmed
[ ] Release notes drafted (PRs since last tag, categorized)
[ ] Prepare Release workflow run (confirmed by user)
[ ] Release PR merged
[ ] Tag X.Y.Z pushed (confirmed by user) -> Docker build green
[ ] Draft release: notes added, wheel asset name verified, published (confirmed by user)
[ ] Next dev version bumped on main (bump-type: patch)
[ ] HA add-on promotion done (release-addon skill in MaStr/batcontrol_ha_addon)
```
65 changes: 58 additions & 7 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
# CLAUDE.md — batcontrol

Primary contribution guidelines: [`.github/copilot-instructions.md`](.github/copilot-instructions.md)
batcontrol charges a home battery when grid prices are cheap and preserves it for expensive
hours, based on dynamic tariffs, solar forecast, and consumption forecast. Python 3.9-3.13
(primary target: 3.11). Full contribution guidelines:
[`.github/copilot-instructions.md`](.github/copilot-instructions.md)

## Commands

```bash
./run_tests.sh # full suite + coverage (creates .venv via uv)
uv venv --python 3.13 --allow-existing # setup only
uv pip install -e '.[test]' pylint autopep8 # lint tools are not part of the test extras
uv run pytest tests/ -k <name> # single test / subset
uv run pylint src/batcontrol # target score >= 9.0 (10 if achievable)
uv run autopep8 --in-place <file> # PEP8 formatting
```

## Module Map

Expand All @@ -16,20 +30,57 @@ src/batcontrol/
scheduler.py # Main loop
mqtt_api.py # State publishing + runtime config overrides
evcc_api.py # evcc integration
config/batcontrol_config_dummy.yaml # Reference config — every parameter documented here
tests/ # pytest suite (mirrors package layout)
docs/ # MkDocs user docs -> https://mastr.github.io/batcontrol/
scripts/ # Standalone verification/helper scripts (committed)
tmp/ # Throwaway experiments — NEVER committed
```

## Architecture

- **Logic types:** `default` (price-based) and `next` (price-based + peak shaving), selected via `battery_control.type` in config.
- **Factory pattern:** inverter, tariff, and forecast providers all use `*_interface.py` base classes with a factory in `<module>.py`.
- **Expert tuning:** `battery_control_expert` config block sets attributes directly on logic instances.
- **MQTT API:** publishes state and accepts runtime overrides (min/max SoC, charge rate) via retained topics.
- **Interval resolution:** 15-minute internally — see `interval_utils.py` and `docs/15-min-transform.md`.
- **Logic types:** `default` (price-based) and `next` (price-based + peak shaving), selected via
`battery_control.type` in config.
- **Factory pattern:** inverter, tariff, and forecast providers all use `*_interface.py` base
classes with a factory in `<module>.py`. New providers: implement the interface, register in
the factory, add config keys.
- **Expert tuning:** `battery_control_expert` config block sets attributes directly on logic
instances.
- **MQTT API:** publishes state and accepts runtime overrides (min/max SoC, charge rate) via
retained topics.
- **Interval resolution:** 15-minute internally — see `interval_utils.py` and
`docs/development/15-min-transform.md`.

## Change Checklist

1. New/changed config parameter -> add it to `config/batcontrol_config_dummy.yaml` with an
explanatory comment.
2. New functionality -> add pytest in `tests/`; bug fix -> add a regression test for the bug.
3. User-facing behavior -> update or add a page under `docs/` and register new pages in
`mkdocs.yml`.
4. Run `./run_tests.sh` and pylint before committing.
5. Config parameters must also be mirrored into the Home Assistant add-on repo
(`MaStr/batcontrol_ha_addon`: `options:` + `schema:` in the add-on `config.yaml`). That repo
ships a `port-batcontrol-change` skill which automates the steps.

## Releasing

Use the `release` skill (`.claude/skills/release/SKILL.md`). Short version: versions are
managed by bump-my-version (`pyproject.toml` + `src/batcontrol/__pkginfo__.py`, never edit by
hand); the `Prepare Release` workflow drops the `dev` suffix, builds the wheel, and creates a
draft GitHub release + version-bump PR; the pushed tag triggers the Docker build; afterwards
`main` is bumped to the next `dev` version and the release is promoted into the HA add-on repo
(`release-addon` skill there).

## Known Pitfalls

- ASCII-only in source code — no umlauts, special chars, emoji, even in log messages. Does not apply to documentation in `docs/`.
- ASCII-only in source code — no umlauts, special chars, emoji, even in log messages. Does not
apply to documentation in `docs/`.
- Peak shaving config is nested inside calculation parameters (not top-level).
- `§14a EnWG` dynamic network fees live in `dynamictariff/network_fees.py`.
- `resilient_wrapper.py` wraps inverter calls — test with the wrapper, not the raw backend.
- Never commit anything from `tmp/`.
- The HA add-on Dockerfiles in `MaStr/batcontrol_ha_addon` copy `entrypoint_ha.sh`,
`config/load_profile_default.csv`, and the `config/` folder from this repo by path — renaming
or moving these files breaks the add-on build.
- Branch names: `copilot/feature-name` or `copilot/bugfix-name` (unless the harness assigns one).