# Notes for LLM contributors

A short orientation file for an LLM working in this repo. Skim before making
changes and keep edits consistent with what's described here. Read
[README.md](README.md) for the user-facing intro.

## What this project is

`pySwitchbot` is a pure-Python library for controlling SwitchBot IoT devices
over **Bluetooth LE** (with some SwitchBot cloud HTTP calls). It backs the
SwitchBot integration in [Home Assistant](https://www.home-assistant.io/).

Built on [`bleak`](https://github.com/hbldh/bleak) +
[`bleak-retry-connector`](https://github.com/Bluetooth-Devices/bleak-retry-connector)
for the BLE transport, `aiohttp` for the cloud API, and
`cryptography`/`pyOpenSSL` for encrypted devices (locks, etc.). It ships its
own advertisement parsing — it does not depend on the `bluetooth-devices`
adv-parser stack.

## Disclosing autonomous contributions

This repo receives a high volume of autonomous, agent-generated pull requests.
When an account is AI-driven, maintainers can only review and have a real
technical discussion if they know **who is responsible** for it.

- If a PR is produced by an autonomous agent, **name the human or team
  responsible** in the PR description (and ideally on the account profile).
- Undisclosed drive-by PRs with no human owner are routinely closed — a single
  line of attribution is what makes the change reviewable.

## Code style

- **Docstrings: terse, default to single-line.** A docstring is the function's
  contract, not a narrative. Almost every docstring should be one line —
  `"""Summary."""`. Multi-line is the exception, only when there's non-obvious
  caller-visible behaviour the signature and parameter names don't convey.
  Note `D1xx` (missing-docstring) rules are ignored — don't add docstrings
  just to satisfy a linter; add them when they carry contract.

- **Comments: same bar — default to none.** Add one only when the _why_ is
  non-obvious: a hidden constraint, a subtle invariant, a workaround for a
  specific device quirk or bug. If removing the comment wouldn't confuse a
  future reader, don't write it. **Don't remove existing comments** unless the
  code they describe is gone.

- **Keep it out of docstrings/comments:** rationale/motivation, issue numbers
  ("closes #N"), and prose that just restates the code. Those belong in the PR
  body and commit message — git already remembers.

- **Python 3.11+.** `python_requires=">=3.11"`, ruff `target-version = "py311"`,
  pyupgrade `--py311-plus`. Don't introduce 3.12+-only syntax.

- **Line length 88**, ruff-enforced (`E501` itself is ignored, but ruff-format
  reflows to 88). Imports sorted by ruff/isort,
  `known-first-party = ["pySwitchbot", "tests"]`.

## Where things live

| Path                      | What                                                                                                                                      |
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `switchbot/__init__.py`   | Public API surface — re-exports device classes, enums, `GetSwitchbotDevices`, `parse_advertisement_data`                                  |
| `switchbot/adv_parser.py` | Central BLE advertisement dispatcher — maps service/model bytes to a device type + parser. Touch this to detect a new device              |
| `switchbot/adv_parsers/`  | One pure-function parser per device family (`bot.py`, `curtain.py`, `lock.py`, `meter.py`, `hub2.py`, …)                                  |
| `switchbot/devices/`      | One module per device class (what callers instantiate); `device.py` holds the `SwitchbotDevice` / `SwitchbotEncryptedDevice` base classes |
| `switchbot/const/`        | Enums and constants by domain; `SwitchbotModel` and the exception classes                                                                 |
| `switchbot/models.py`     | `SwitchBotAdvertisement` dataclass                                                                                                        |
| `switchbot/discovery.py`  | `GetSwitchbotDevices` — BLE scan + per-type getters                                                                                       |
| `tests/`                  | Pytest suite                                                                                                                              |

Adding a device usually touches: a parser in `adv_parsers/`, a dispatch entry
in `adv_parser.py`, a class in `devices/`, model/const in `const/`, and an
export in `__init__.py`.

## Running tests

This project uses [`poetry`](https://python-poetry.org/) for packaging and
dependency management.

```bash
poetry install
poetry run pytest --cov=switchbot tests
```

CI (`.github/workflows/ci.yml`) runs the suite on Python 3.11–3.14 in a
separate `test` job, runs the pre-commit hooks in a `lint` job, and uploads
coverage to Codecov.

## Commit / PR conventions

- **Conventional Commits**, enforced by the `commitizen` commit-msg pre-commit
  hook (default ruleset). Types: `build`, `chore`, `ci`, `docs`, `feat`,
  `fix`, `perf`, `refactor`, `revert`, `style`, `test`. Examples:
  - `feat: add support for the SwitchBot Hub 3`
  - `fix(lock): handle empty advertisement payload`
- **Use a feature branch.** PRs opened from a fork's default branch are
  auto-closed by `auto-close-default-branch-prs.yml`.
- **Pre-commit auto-fixes; re-stage.** `ruff --fix`, `ruff-format`,
  `pyupgrade`, `codespell`, prettier, and the standard pre-commit-hooks run on
  commit and rewrite files in place; when a hook edits a file the commit
  aborts — re-stage and commit again. (pre-commit.ci also autofixes on PRs.)
- **No PR template / no CONTRIBUTING.md** — the body is freeform; describe what
  the change does and why, and link the issue if one exists.
- **Releases are automatic:** on push to `main`, the `release` job in
  `ci.yml` runs [python-semantic-release](https://python-semantic-release.readthedocs.io/),
  which derives the next version from the Conventional Commit messages, bumps
  `pyproject.toml` + `switchbot/__version__.py`, updates `CHANGELOG.md`, tags,
  creates the GitHub Release, and publishes to PyPI. The commit `type` drives
  the bump (`fix` → patch, `feat` → minor, `!`/`BREAKING CHANGE` → major).

## Reporting security issues

Report suspected vulnerabilities privately to the maintainers — not in a public
issue, PR, or commit that names the bug class and affected code path.
