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]
ifdata[0] == 4 and data[2] == 2
- Save “device key” from
data[3:19]
ifdata[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())