Skip to main content

blesession

PyPI Python versions CI License: MIT

One BLE session, instrumented — for Home Assistant BLE integrations built on bleak.

Connect, subscribe to notifications, exchange frames with per-step timeouts, disconnect — and come out the other side with where the time went, where it failed, which radio it went over, and one sentence on what that most likely means, ready to publish as sensor attributes so a failed session at 3 am can be read off the entity without debug logging.

Status

Verified on device over a Bluetooth proxy. The library is tested without Home Assistant (pytest). Adopting it? docs/adopting.md is a whole integration end to end: what to write, what the library writes for you, every report key, and how to test it without bleak or Home Assistant. docs/design.md is the why — what belongs here, what deliberately does not, and how a Bluetooth-proxy route works without importing Home Assistant. See CHANGELOG.md for releases.

The design is extracted from integrations that already carry this instrumentation (and had drifted apart), and is meant to be adopted by others that today each hand-roll the same notification wait and have no failure attribution at all.

Install

pip install blesession

Requires Python 3.13+. The core depends only on bleak / bleak-retry-connector; blesession.hass imports Home Assistant lazily and is not needed outside HA.

What it provides

piece one line
ble_session() connect inside the block (or reuse a link left up), watch the link, bounded disconnect in finally
Notifications queued replies from one characteristic; every wait names its step and ends the moment the link drops
SessionTrace nested stage timings; the innermost stage an exception escaped from
stage vocabulary unreachable · connect · session · auth · transfer · finish · disconnect, plus a device detail
run_attempts() the lock-per-attempt / fresh-handle-per-attempt contract; policy stays yours
blesession.hass.ble_device_or_raise() the handle, resolved fresh inside the attempt, or Unreachable
blesession.hass.radio_facts() via, via_type, rssi, paths, advertised_via as scanner names, and via_unconfirmed (a flag)
link.py the one place that probes bleak / habluetooth internals for the radio a link took
blesession.testing FakeClient / fake_connect() so every integration's tests fake bleak the same way
build_report() fixed attribute key order; generic likely-cause sentences with a translatable key, your device sentences first
SessionReports the last session and the last failure, so a success does not erase the evidence
errors ConnectionError subclasses so an off device never becomes a traceback

What it does not provide

Retry counts, backoff, packet pacing, lock scope, bonding and pairing, cooldowns, advertisement parsing, protocol frames. Those are the parts each integration learned from its own device and keeps.

Layout

src/blesession/         pure Python + bleak, tested without Home Assistant
src/blesession/hass.py  imports homeassistant lazily; only used inside HA
docs/adopting.md        how to use it, with a whole integration
docs/design.md          why it is shaped this way
from blesession import Notifications, SessionTrace, ble_session, build_report, stages

trace = SessionTrace(stage_map={"start": stages.AUTH})
try:
    async with ble_session(ble_device, trace=trace) as client:
        async with Notifications(client, NOTIFY_UUID, settle=0.5) as replies:
            with trace.timed("start"):
                await client.write_gatt_char(WRITE_UUID, START, response=False)
                await replies.next(timeout=5, step="start")
            with trace.timed("transfer"):
                ...
except ConnectionError as exc:          # every session error is one
    report = build_report(operation="write", trace=trace, exc=exc,
                          facts=radio_facts(hass, address, trace.link), noun="device")
    # {'operation': 'write', 'success': False, 'error': ..., 'failed_stage': 'auth',
    #  'failed_detail': 'start', 'likely_cause': ..., 'via': ..., 'connect_s': ..., ...}

Development & testing

pip install -e ".[dev]"
pytest                 # unit tests; FakeClient fakes bleak the same way for adopters
ruff check . && ruff format --check .
mypy                   # type-check src/ (the package ships py.typed)
python -m build

CI runs on every push/PR (.github/workflows/ci.yml): ruff lint+format, mypy, the test suite on Python 3.13/3.14 (plus a lowest-pinned-dependencies job), and a build that asserts py.typed and the licence are in the wheel.

Releasing: add a version section to CHANGELOG.md (behaviour changes go under Changed with before/after), bump version in pyproject.toml, merge, then tag: pushing a v* tag triggers .github/workflows/release.yml to build and publish to PyPI (trusted publishing).

License

MIT

Metadata

Release files for blesession 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for blesession 0.3.0
File Size Uploaded
blesession-0.3.0.tar.gz 56.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for blesession 0.3.0
File Interpreter ABI Platform
blesession-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 87.0 kB

Release files / blesession-0.3.0.tar.gz

Download URL blesession-0.3.0.tar.gz
Size 56.0 kB
Tags Source
SHA-256 checksum
How to use checksums
199e3ed37017b9b3eee2b1faa35fbd439cea5ce4c9ed104aee5c5bf38ad0e7b0
BLAKE2b-256 checksum
How to use checksums
f23f88933ed5c1b293750468a66d130e7ab9a9b88689939babd78be6f0a880bf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log

Release files / blesession-0.3.0-py3-none-any.whl

Download URL blesession-0.3.0-py3-none-any.whl
Size 31.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
78270a1ad31a5e2ee3a5c22f2712f3b8f721ff9b57e7c2c0bd662e101e6a6eb9
BLAKE2b-256 checksum
How to use checksums
060e381baeff4c81e423e31fb2d261fa33b7ad799541eccf44761fa4f10f41a8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page