Add Boneco devices

I think I have made progress but not sure

I’m stuck on trying to bypass the handshake and stop it from disconnecting. Any suggestions?

Start with bleakclient.start_notify(CHARACTERISTIC_AUTH, callback) and def callback(sender: int, data: bytearray) -> None.
Your callback should check that sender == 0x026 and

  • Save “nonce” if len(data) == 20 and data[0] == 1
  • Save “auth level/step” from data[1] if data[0] == 4 and data[2] == 2
  • Save “device key” from data[3:19] if data[0:3] == b'\x06\x00\x00'

After getting “nonce” you should also call bleakclient.start_notify(CHARACTERISTIC_AUTH_AND_SERVICE, callback2) and start calling bleakclient.write_gatt_char(CHARACTERISTIC_AUTH_AND_SERVICE, some_data) for moving between auth states

callback2 just checks that sender == 0x029 and data[1] & 1 == 1

CHARACTERISTIC_AUTH = "fdce2347-1013-4120-b919-1dbb32a2d132"
CHARACTERISTIC_AUTH_AND_SERVICE = "fdce2348-1013-4120-b919-1dbb32a2d132"

Auth states: GOT_NONCE → CONFIRM_WAITING (here you press button on device) → CONFIRMED → GOT_DEVICE_KEY → AUTH_SUCCESS

im just getting this error

Started notifications for AUTH characteristic
callback invoked with sender: fdce2347-1013-4120-b919-1dbb32a2d132 (Handle: 38): Unknown, data: 0101c88b5474b03218a41249a5d396afcca20000
callback invoked with sender: fdce2347-1013-4120-b919-1dbb32a2d132 (Handle: 38): Unknown, data: 0400010000000000000000000000000000000000

with this script

import asyncio
from bleak import BleakClient

CHARACTERISTIC_AUTH = "fdce2347-1013-4120-b919-1dbb32a2d132"
CHARACTERISTIC_AUTH_AND_SERVICE = "fdce2348-1013-4120-b919-1dbb32a2d132"

DEVICE_MAC_ADDRESS = "E1:A6:44:55:39:CA"

# Global variables to store the data and state
nonce = None
auth_level_step = None
device_key = None
auth_state = "INIT"

def callback(sender: str, data: bytearray) -> None:
    global nonce, auth_level_step, device_key, auth_state
    print(f"callback invoked with sender: {sender}, data: {data.hex()}")

    if sender == CHARACTERISTIC_AUTH:
        if len(data) == 20 and data[0] == 1:
            nonce = data
            auth_state = "GOT_NONCE"
            print("Nonce saved:", nonce.hex())
            asyncio.create_task(start_notify_auth_and_service())
        elif data[0] == 4 and data[2] == 2:
            auth_level_step = data[1]
            auth_state = "CONFIRM_WAITING"
            print("Auth level/step saved:", auth_level_step)
        elif data[0:3] == b'\x06\x00\x00':
            device_key = data[3:19]
            auth_state = "GOT_DEVICE_KEY"
            print("Device key saved:", device_key.hex())
            auth_state = "AUTH_SUCCESS"
            print("Authentication successful")

def callback2(sender: str, data: bytearray) -> None:
    print(f"callback2 invoked with sender: {sender}, data: {data.hex()}")
    if sender == CHARACTERISTIC_AUTH_AND_SERVICE and (data[1] & 1) == 1:
        print("Callback2 triggered with valid data.")
        # Here you can implement the logic to move between authentication states

async def start_notify_auth_and_service():
    print("Connecting to start AUTH_AND_SERVICE notifications...")
    async with BleakClient(DEVICE_MAC_ADDRESS) as client:
        await client.start_notify(CHARACTERISTIC_AUTH_AND_SERVICE, callback2)
        some_data = bytearray([0x01, 0x02, 0x03])  # Replace this with actual data as needed
        await asyncio.sleep(1)  # Allow time for notifications to stabilize
        await client.write_gatt_char(CHARACTERISTIC_AUTH_AND_SERVICE, some_data)
        print("Started notifications for AUTH_AND_SERVICE characteristic")

async def main():
    print(f"Connecting to device {DEVICE_MAC_ADDRESS}...")
    async with BleakClient(DEVICE_MAC_ADDRESS) as client:
        await client.start_notify(CHARACTERISTIC_AUTH, callback)
        print("Started notifications for AUTH characteristic")

        while auth_state != "AUTH_SUCCESS":
            await asyncio.sleep(1)
            if auth_state == "GOT_NONCE":
                print("Press the button on the device to confirm...")

if __name__ == "__main__":
    asyncio.run(main())

Can you please share your code? I am new to bluetooth communication to be true, but want to try it.

I think you have a mistake in sender == CHARACTERISTIC_AUTH you should use something like str(sender).split(' ')[0] == CHARACTERISTIC_AUTH

I updated the script but still couldn’t get it to work

import asyncio
from bleak import BleakClient
from bleak.exc import BleakError, BleakDBusError

CHARACTERISTIC_AUTH = "fdce2347-1013-4120-b919-1dbb32a2d132"
CHARACTERISTIC_AUTH_AND_SERVICE = "fdce2348-1013-4120-b919-1dbb32a2d132"

DEVICE_MAC_ADDRESS = "E1:A6:44:55:39:CA"

# Global variables to store the data and state
nonce = None
auth_level_step = None
device_key = None
auth_state = "INIT"

def callback(sender: str, data: bytearray) -> None:
    global nonce, auth_level_step, device_key, auth_state
    sender_str = str(sender).split(' ')[0]
    print(f"callback invoked with sender: {sender_str}, data: {data.hex()}")

    if sender_str == CHARACTERISTIC_AUTH:
        if len(data) == 20 and data[0] == 1:
            nonce = data
            auth_state = "GOT_NONCE"
            print("Nonce saved:", nonce.hex())
            asyncio.create_task(start_notify_auth_and_service())
        elif data[0] == 4 and data[2] == 2:
            auth_level_step = data[1]
            auth_state = "CONFIRM_WAITING"
            print("Auth level/step saved:", auth_level_step)
        elif data[0:3] == b'\x06\x00\x00':
            device_key = data[3:19]
            auth_state = "GOT_DEVICE_KEY"
            print("Device key saved:", device_key.hex())
            auth_state = "AUTH_SUCCESS"
            print("Authentication successful")

def callback2(sender: str, data: bytearray) -> None:
    sender_str = str(sender).split(' ')[0]
    print(f"callback2 invoked with sender: {sender_str}, data: {data.hex()}")
    if sender_str == CHARACTERISTIC_AUTH_AND_SERVICE and (data[1] & 1) == 1:
        print("Callback2 triggered with valid data.")
        # Implement the logic to move between authentication states

async def start_notify_auth_and_service():
    retry_attempts = 3
    for attempt in range(retry_attempts):
        try:
            print("Connecting to start AUTH_AND_SERVICE notifications...")
            async with BleakClient(DEVICE_MAC_ADDRESS) as client:
                await client.start_notify(CHARACTERISTIC_AUTH_AND_SERVICE, callback2)
                some_data = bytearray([0x01, 0x02, 0x03])  # Replace this with actual data as needed
                await asyncio.sleep(1)  # Allow time for notifications to stabilize
                await client.write_gatt_char(CHARACTERISTIC_AUTH_AND_SERVICE, some_data)
                print("Started notifications for AUTH_AND_SERVICE characteristic")
                break
        except BleakDBusError as e:
            print(f"Failed to start notifications (attempt {attempt + 1}): {e}")
            await asyncio.sleep(2)
        except BleakError as e:
            print(f"BLE error (attempt {attempt + 1}): {e}")
            await asyncio.sleep(2)

async def main():
    print(f"Connecting to device {DEVICE_MAC_ADDRESS}...")
    try:
        async with BleakClient(DEVICE_MAC_ADDRESS) as client:
            await client.start_notify(CHARACTERISTIC_AUTH, callback)
            print("Started notifications for AUTH characteristic")

            while auth_state != "AUTH_SUCCESS":
                await asyncio.sleep(1)
                if auth_state == "GOT_NONCE":
                    print("Press the button on the device to confirm...")
    except BleakDBusError as e:
        print(f"Failed to connect to device: {e}")
    except BleakError as e:
        print(f"BLE error: {e}")

if __name__ == "__main__":
    asyncio.run(main())