Skip to main content

openble-bondtouch

The Bond Touch bracelet BLE protocol (Impossible Labs), read from the Bond Touch Android app (11.2.0).

  • openble.bondtouch.uuids: the Bond services and characteristics, spelled out one by one because their fourth group differs, and the advertised names.
  • openble.bondtouch.identify: matches advertisements, picks the generation from the GATT table and the ff10 API version byte, and lists what each generation needs.
  • openble.bondtouch.v2: V2, V4 and Mini. The ffa4 state, ffa5 events and touch recording, the 20-byte ffa6 frames (0x26 LED and motor steps, 0x33 three-LED frames, run queue) and the 0x27 config properties.
  • openble.bondtouch.v1: the original Bond Touch. Its [cmdId, seq, payload] commands, ffa7 results, 11 fixed LED colours, and gaps worked out from arrival times.
  • openble.bondtouch.v3: Bond More. The ffb1 commands and reports, and the ffb2 touch frames of 50 ms samples.
  • openble.bondtouch.patterns: the [press, gap, …, press] millisecond patterns every generation shares, and the conversion to V3 samples.
  • openble.bondtouch.link: BraceletLink answers the token, AUID and paired-signal requests, collects touches, and sends commands one at a time with the app's pauses. On V1 it also waits for each result.

Pure Python 3.11+ with no dependencies and no Bluetooth stack. BraceletLink takes a write(uuid, payload) coroutine and is fed notifications, so it runs over bleak, a test double, or anything else.

Everything here comes from static reading of the app, checked against one live bracelet: a V2 (Bond002, firmware 2.6.4) over bleak on macOS. Setup (including taking over from the official app with a double-tap), colours, played patterns with vibration, and received touches work on it. V1, V3, V4 and Mini have not been run yet. The manual records what that run showed and the questions still open.

pip install openble-bondtouch

Build frames

from openble.bondtouch import v2, v3
from openble.bondtouch.identify import generation_of
from openble.bondtouch.patterns import to_samples

generation_of(b"\x44")
# 'v4'

v2.show_colour((0x23, 0xE0, 0xE8)).hex(" ")
# '26 00 00 00 00 00 01 23 e0 e8 50 00 00 00 00 00 00 ff ff 00'

v2.play_touch([400, 200, 300], (0xFF, 0, 0))  # two 0x26 steps, then 32 00 11
v3.touch_frames(to_samples([400, 200, 300]), (0xFF, 0, 0), slot=1)

Drive a bracelet with bleak

import asyncio

from bleak import BleakClient
from openble.bondtouch.link import BraceletLink, detect_generation, notify_uuids


async def touch(address: str, auid: int) -> None:
    async with BleakClient(address) as client:

        async def read(uuid: str) -> bytes:
            return bytes(await client.read_gatt_char(uuid))

        async def write(uuid: str, payload: bytes) -> None:
            # A V2 on 2.6.4 offers ffa6 without response only.
            char = client.services.get_characteristic(uuid)
            response = "write" in char.properties
            await client.write_gatt_char(uuid, payload, response=response)

        services = [service.uuid for service in client.services]
        generation = await detect_generation(read, services)
        link = BraceletLink(write, generation, auid, read=read)
        for uuid in notify_uuids(generation):
            await client.start_notify(uuid, lambda c, data, u=uuid: link.feed(u, data))
        await link.start()
        await link.wait_connected()
        await link.play([400, 200, 400], (0xFF, 0x44, 0xA6))
        message = await link.touches.get()  # the wearer's next touch
        print(message.pattern, message.slot)
        await link.close()

Pick any 32-bit AUID and keep it. A bracelet set up with another AUID, for example by the official app, reports AUID_ERROR (and link.needs_setup), goes to its out-of-box state and flashes. The app then asks the wearer to double-tap it to continue, which the link answers.

Newer firmware also asks for OS-level bonding after setup. The app triggers it by writing v2.ancs(True) on V2, by subscribing to uuids.BOND_TRIGGER on V4 and Mini, and with createBond() on V3 (client.pair() in bleak). Once bonded it writes v2.after_bonding(generation).

Choices the manual leaves open

Where the app's code did not settle a detail, this library picks one and says so in the docstring:

  • v2.play_blend blends the colour at the start of each 200 ms frame.
  • patterns.to_samples squeezes patterns longer than 10 s by rounding run boundaries to the nearest sample.
  • BraceletLink.clear_colour on V1 sends colour black.
  • BraceletLink sends V1 command seq from 0 after each connection.

Protocol notes

docs/bond-touch-ble-protocol.md: discovery, the GATT layout, the connection lifecycle, each generation's state, events and commands, firmware updates and the open questions.

Not affiliated with Impossible Labs. The name identifies the devices this interoperates with.

License

MIT License, copyright 2026 Kadima Tech.

Metadata

Release files for openble-bondtouch 0.1.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 openble-bondtouch 0.1.0
File Size Uploaded Provenance
openble_bondtouch-0.1.0.tar.gz 47.0 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for openble-bondtouch 0.1.0
File Interpreter ABI Platform
openble_bondtouch-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 74.7 kB

Release files / openble_bondtouch-0.1.0.tar.gz

Download URL openble_bondtouch-0.1.0.tar.gz
Size 47.0 kB
Tags Source
SHA-256 checksum
How to use checksums
efccad0b1bc866febba54eb865517ddb880236785ca3c805da43fa6faf64f2cc
BLAKE2b-256 checksum
How to use checksums
d1c5e116e91f5f50ae277a5efbfc1d34f42171eceeb56c59ef1b59f44e92a205
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 24, 2026.

Transparency log

Release files / openble_bondtouch-0.1.0-py3-none-any.whl

Download URL openble_bondtouch-0.1.0-py3-none-any.whl
Size 27.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
60f7c84bdf23b6f34b6f24d96af821e9e8c73fe666b1f13321b7c0703abec1a7
BLAKE2b-256 checksum
How to use checksums
297fdcdc879ccc05ff08a5be0c949c782e656fa328d733503159dbd616cbe2fd
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 24, 2026.

Transparency log

Security for openble-bondtouch 0.1.0

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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for openble_bondtouch-0.1.0.tar.gz

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 24, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

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