Metadata-Version: 2.4
Name: esp-protocomm
Version: 0.1.0
Summary: Unofficial Python client for Espressif's protocomm: BLE transport, security1 handshake, and Wi-Fi provisioning for ESP32 devices
Author: Clark Communications Corporation
License-Expression: Apache-2.0
Project-URL: Homepage, https://github.com/electrification-bus/esp-protocomm
Project-URL: Source, https://github.com/electrification-bus/esp-protocomm
Keywords: esp32,esp-idf,protocomm,provisioning,ble,wifi,espressif
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: System :: Hardware
Classifier: Topic :: Software Development :: Embedded Systems
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: NOTICE
Requires-Dist: protobuf>=4.25
Requires-Dist: cryptography>=41
Provides-Extra: ble
Requires-Dist: bleak>=0.22; extra == "ble"
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
Dynamic: license-file

# esp-protocomm

A Python client for **protocomm**, Espressif's transport for ESP-IDF unified provisioning: the security1 handshake, the BLE transport, and Wi-Fi provisioning. It talks to any ESP32 device running protocomm, over Bluetooth Low Energy, from a laptop or a server.

**Unofficial.** Not affiliated with, endorsed by, or supported by Espressif Systems. Portions are adapted from ESP-IDF under the Apache License 2.0; see [`NOTICE`](NOTICE) for per-file attribution and a list of the changes made.

## Install

```bash
pip install esp-protocomm          # the session: handshake, Wi-Fi provisioning
pip install "esp-protocomm[ble]"   # adds the radio (bleak)
```

The base install needs no Bluetooth stack, so the handshake and the protobuf schemas can be exercised in CI. Only `BleTransport` requires the extra.

## Use

```python
import asyncio
from esp_protocomm import Security1, establish_session, provision_wifi
from esp_protocomm.ble import BleTransport

async def main():
    async with BleTransport("XX:XX:XX:XX:XX:XX") as transport:
        security = await establish_session(transport, Security1(pop="abcd1234"))
        status = await provision_wifi(transport, security, ssid="my-network", passphrase="...")
        print(status)

asyncio.run(main())
```

The endpoint name-to-UUID map is read from the device's `0x2901` descriptors rather than hardcoded, so a product that registers its own endpoint alongside the standard ones works without changes here.

## Scope

What this is: the protocomm session and the standard `prov-session` / `prov-config` endpoints.

What it is not: a device's own application commands. Those ride over the session this library establishes, on their own endpoint, and belong in that product's code. Keeping that boundary is why this is a separate library.

Security scheme support is **security1** (X25519 key exchange, AES-CTR, proof-of-possession). The protobuf definitions for security0 and security2 are present because they ship together upstream, but only security1 has a client here.

## Development

```bash
pip install -e ".[dev]"
pytest tests/ -v
ruff check . && ruff format --check .
```

Tests run against an in-process fake device that implements the device side of the handshake with the same primitives as the client, so they exercise the real key exchange, the real AES-CTR keystream, and the real framing. No radio, no hardware.

## Releasing

Publishing uses PyPI Trusted Publishing (OIDC), so there is no API token in this repository and there should not be one. Tag a version and the `Release` workflow builds, checks that the wheel carries `LICENSE` and `NOTICE`, and publishes.

Before the **first** release, PyPI needs to be told which workflow is allowed to publish. Because the project does not exist there yet, this is a *pending publisher* at [pypi.org/manage/account/publishing](https://pypi.org/manage/account/publishing/):

| Field | Value |
| --- | --- |
| PyPI Project Name | `esp-protocomm` |
| Owner | `electrification-bus` |
| Repository name | `esp-protocomm` |
| Workflow name | `release.yml` |
| Environment name | `pypi` |

Workflow name is the **filename**, not the `name:` inside it, and the environment must match the job's `environment:` key. The pending publisher converts to a normal one on the first successful publish.

```bash
git tag v0.1.0 && git push origin v0.1.0
```

## License

Apache-2.0. See [`LICENSE`](LICENSE) and [`NOTICE`](NOTICE).
