Skip to content

aioble: Connecting to the Apple Media Service (Pico-W) #686

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
neil-morrison44 opened this issue Jun 18, 2023 · 16 comments
Open

aioble: Connecting to the Apple Media Service (Pico-W) #686

neil-morrison44 opened this issue Jun 18, 2023 · 16 comments

Comments

@neil-morrison44
Copy link

Hi,

I'm trying to use a Pi Pico W to connect to the Apple Media Service, but I'm running into a few issues.

async def connectBLE():
    connection = await aioble.advertise(
        _ADV_INTERVAL_MS,
        name="AMS",
        services=[_AMS_UUID],
        appearance=0,
        manufacturer=(0xABCD, b"1234"),
    )
    print("Connection from", connection.device)
    return connection

_AMS_UUID = bluetooth.UUID("89D3502B-0F36-433A-8EF4-C502AD55F8DC")
_AMS_ENTITY_UPDATE = bluetooth.UUID("2F7CABCE-808D-411F-9A0C-BB92BA96C102")
_ADV_INTERVAL_MS = const(250000)

async def main():
    ams_service = aioble.Service(_AMS_UUID)
    aioble.register_services(ams_service)

    connection = await connectBLE()
    ams_service = await connection.service(_AMS_UUID)
    ams_entity_update_characteristic = await ams_service.characteristic(
        _AMS_ENTITY_UPDATE
    )
    await ams_entity_update_characteristic.subscribe(notify=True)

This'll connect, find the services, characteristics but then throws:

Traceback (most recent call last):
  File "<stdin>", line 160, in <module>
  File "uasyncio/core.py", line 1, in run
  File "uasyncio/core.py", line 1, in run_until_complete
  File "uasyncio/core.py", line 1, in run_until_complete
  File "<stdin>", line 139, in main
  File "aioble/client.py", line 430, in subscribe
  File "aioble/client.py", line 295, in write
GattError: 5

On the .subscribe(notify=True) bit, not sure how / if I can look up the GattError: 5 bit for more info?

There is a CircuitPython implementation here, https://docs.circuitpython.org/projects/ble_apple_media/en/latest/index.html

Which uses a "Service Solicitation" advertisement - what's the method for constructing that in aioble? I'm guessing custom adv_data & resp_data but I'm unsure of the format, etc.

That implementation also pairs to the connecting device, but when I insert a await connection.pair() I get

Traceback (most recent call last):
  File "<stdin>", line 161, in <module>
  File "uasyncio/core.py", line 1, in run
  File "uasyncio/core.py", line 1, in run_until_complete
  File "uasyncio/core.py", line 1, in run_until_complete
  File "<stdin>", line 124, in main
  File "<stdin>", line 99, in connectBLE
  File "aioble/device.py", line 256, in pair
  File "aioble/security.py", line 171, in pair
ValueError: unknown config param

Which I guess is due to the Pico-W implementation not (currently?) supporting something in ble.config(bond=bond, le_secure=le_secure, mitm=mitm, io=io)

Thanks

@sebastian-blohm
Copy link

Hi!
Were you able to find out what GattError: 5 means? I'm seeing the same in a similar context.

@neil-morrison44
Copy link
Author

No I couldn’t work it out, dug into the code a bit to see if I could find it’s origin but even that didn’t help much (though I might not have gone to a deep enough layer)

@puppet13th
Copy link

@neil-morrison44 if you want to pico-w to connect to anything you should use central role( scan and connect ) like this aioble example. the code that you're using now is for peripheral mode( aioble.advertise )

@neil-morrison44
Copy link
Author

@puppet13th peripheral mode is correct for the Apple Media Service, the phone is the central device.

@puppet13th
Copy link

from this picture there is MS and MR. what is pico role there?

@puppet13th
Copy link

puppet13th commented Sep 20, 2023

@neil-morrison44 after connection try add these line:

await connection.exchange_mtu()
await connection.pair( bond=False, le_secure=False, mitm=False )

if those config not implemented for pico-w yet you can edit security.py comment out 171 line:
ble.config(bond=bond, le_secure=le_secure, mitm=mitm, io=io)

@neil-morrison44
Copy link
Author

@puppet13th puppet13th it'd be the MR device - I believe that's roughly what I tried back in June which threw the error, but it may well be supported now if there's been updates so I'll have another go on the latest MicroPython at some point & update this

@puppet13th
Copy link

@neil-morrison44 i have not use any pico-w board yet, have you check if ble pair implemented in pico-w port? on esp32 port pair only implemented since firmware version 1.20

@foxt
Copy link

foxt commented Nov 13, 2023

Yeah - it seems like BLE.gap_pair is not present on the Pico W, so aioble.pair will fail with AttributeError: 'BLE' object has no attribute 'gap_pair'

@hoihu
Copy link

hoihu commented Feb 4, 2024

I'm facing the same issue with my raspberry pico w. I'm trying to read the current time service characteristic from an iPhone.

I guess the gatt error 5 is the GATTS_ERROR_INSUFFICIENT_AUTHENTICATION as specified in https://docs.micropython.org/en/latest/library/bluetooth.html#event-handling

That makes somewhat sense when the peripheral is not paired / bonded to the iPhone. However, when adding the await connection.pair() to the code, it fails with ValueError: unknown config param .

As I interepret the code in modbluetooth.c this could only be case when the bonding support is not compiled in. But MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING seems to be defined in the the make file (?)

Also note that the example from the official repo https://github.com/micropython/micropython/blob/master/examples/bluetooth/ble_bonding_peripheral.py does not seem to work anymore, giving the same fault at https://github.com/micropython/micropython/blob/master/examples/bluetooth/ble_bonding_peripheral.py#L70

(using the nightly build version as of 3.2.2024)

@hoihu
Copy link

hoihu commented Feb 4, 2024

But MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING seems to be defined in the the make file (?)

huh looking into it it may not be... since it uses btstack not nimble (at least from the build output)? Means bonding support is not enabled on the rp2 port?

@andrewleech
Copy link
Contributor

Yeah I'm pretty sure bonding is currently only supported on stm32

@hoihu
Copy link

hoihu commented Feb 4, 2024

Yeah I'm pretty sure bonding is currently only supported on stm32

thanks for the feedback. Yeah I feared that a bit... pitty since bonding is sometimes required to readout characteristics.

studying the release notes: https://micropython.org/resources/micropython-ChangeLog.txt it was mentioned that the esp32 port is also supporting bonding from 1.20 onward... but haven't tested that. I'll give it a shot with a pyboard d.

In general, it would be good to have an overview with a list of ports: <ble_features>.

@hoihu
Copy link

hoihu commented Feb 5, 2024

Ok so the bonding support is not enabled on the pico w, but it can be done via

diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt
index 3a46fdaa7..2ced4e86e 100644
--- a/ports/rp2/CMakeLists.txt
+++ b/ports/rp2/CMakeLists.txt
@@ -284,6 +284,7 @@ if (MICROPY_BLUETOOTH_BTSTACK)
 
     target_compile_definitions(${MICROPY_TARGET} PRIVATE
         MICROPY_BLUETOOTH_BTSTACK=1
+        MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING=1
         MICROPY_BLUETOOTH_BTSTACK_CONFIG_FILE=\"btstack_inc/btstack_config.h\"
     )

recompiling and then the ValueError: unknown config param faults are disappearing. On the mobile device, a pairing request pops up (depending on the selected pairing option). So far so good.

However it doesn't continue any further from there. If I confirm it on the mobile it doesn't seem to continue the bonding process.

I then enabled the logs via aioble.core.log_level = 3 and checked if there are any incoming events that are not handled, but nope.

@andrewleech
Copy link
Contributor

Yeah the problem is a bunch of C functions would need to be written to recieve any pairing and bonding events from btstack and convert those events into the form that aioble expects. I wrote some of the initial stm versions of these a few years ago for nimble, but btstack was not supported on my hardware (stm32wb55) so I wasn't able to prepare the code for that stack.

If you take a look in https://github.com/micropython/micropython/blob/master/extmod/nimble/modbluetooth_nimble.c at everywhere enabled by MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING you'll see the bulk of the code supporting this feature, there probably needs to be more of this for btstack in https://github.com/micropython/micropython/blob/master/extmod/btstack/modbluetooth_btstack.c (though some support is already there from micropython/micropython@a1fcf30 )

@hoihu
Copy link

hoihu commented Feb 11, 2024

I'll give it a shot with a pyboard d.

so I tried - but faced isses... see. micropython/micropython#13639

@andrewleech thanks for the pointers! I had a look around those files and I also think it should be doable. But what I really need is a working (uPy-) example of a platform where bonding is known to work, to get a feeling of how the interactions works during the bonding process. For example, it's still unclear to me if addr_mode set to 2 is a requirement for bonding.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants