hbldh / bleak

A cross platform Bluetooth Low Energy Client for Python using asyncio
MIT License
1.77k stars 294 forks source link

Cannot Retrieve Services / Attributes #397

Closed lbussy closed 2 years ago

lbussy commented 3 years ago

Description

My end goal is to get the battery level via python in a Raspberry Pi from a device with known battery level capabilities (verified with nRF Connect on iOS.) This is what I am trying to replace (gattool being deprecated):

gatttool -b 50-C2-A8-3D-80-7C --char-read -a 0x3b

What I Did

I did see issue #332 and as a result, I tested with both a Raspberry Pi Zero W Rev 1.1 as well as a Raspberry Pi 4 Model B Rev 1.1.

I started with the Bluetooth discovery example listed in the README:

#!/usr/bin/env python3

import asyncio
from bleak import BleakScanner

async def run():
    devices = await BleakScanner.discover()
    for d in devices:
        print(d)

loop = asyncio.get_event_loop()
loop.run_until_complete(run())

From this I did see my device:

$ sudo ./scanner.py
24:6F:28:2E:7F:9E: BLE Battery
70:93:85:D9:0F:7D: 70-93-85-D9-0F-7D
FC:8F:90:A6:1B:EC: [TV] Living room
12:25:EA:8A:1E:74: 12-25-EA-8A-1E-74
F4:BC:DA:32:96:39: D7881F01D551
50:C2:A8:3D:80:7C: 50-C2-A8-3D-80-7C  < -- This is my device
4E:20:58:22:F1:09: 4E-20-58-22-F1-09
5C:64:B6:41:50:AC: 5C-64-B6-41-50-AC
69:EB:E7:76:A4:4B: 69-EB-E7-76-A4-4B
23:EA:B9:9D:1D:97: 23-EA-B9-9D-1D-97
B8:BC:5B:61:AC:1A: [TV] living room
6F:98:8D:11:F8:17: 6F-98-8D-11-F8-17
50:65:83:6D:B2:5C: Tilt
68:D5:21:6F:80:2F: 68-D5-21-6F-80-2F
FC:5E:BC:EF:17:64: FC-5E-BC-EF-17-64

Then I tried the service_explorer_py example and replaced the address in main with the address of the device to which I want to connect:

#!/usr/bin/env python3

"""
Service Explorer
----------------
An example showing how to access and print out the services, characteristics and
descriptors of a connected GATT server.
Created on 2019-03-25 by hbldh <henrik.blidh@nedomkull.com>
"""

import platform
import asyncio
import logging
from bleak import BleakClient

async def run(address, debug=False):
    log = logging.getLogger(__name__)
    if debug:
        import sys

        log.setLevel(logging.DEBUG)
        h = logging.StreamHandler(sys.stdout)
        h.setLevel(logging.DEBUG)
        log.addHandler(h)

    async with BleakClient(address) as client:
        x = await client.is_connected()
        log.info("Connected: {0}".format(x))

        for service in client.services:
            log.info("[Service] {0}: {1}".format(
                service.uuid, service.description))
            for char in service.characteristics:
                if "read" in char.properties:
                    try:
                        value = bytes(await client.read_gatt_char(char.uuid))
                    except Exception as e:
                        value = str(e).encode()
                else:
                    value = None
                log.info(
                    "\t[Characteristic] {0}: (Handle: {1}) ({2}) | Name: {3}, Value: {4} ".format(
                        char.uuid,
                        char.handle,
                        ",".join(char.properties),
                        char.description,
                        value,
                    )
                )
                for descriptor in char.descriptors:
                    value = await client.read_gatt_descriptor(descriptor.handle)
                    log.info(
                        "\t\t[Descriptor] {0}: (Handle: {1}) | Value: {2} ".format(
                            descriptor.uuid, descriptor.handle, bytes(value)
                        )
                    )

if __name__ == "__main__":
    address = ("50:C2:A8:3D:80:7C")
    loop = asyncio.get_event_loop()
    loop.set_debug(True)
    loop.run_until_complete(run(address, True))

I receive the following:

$ sudo ./service_explorer.py
Executing <Task pending coro=<run() running at ./service_explorer.py:27> wait_for=<Future pending cb=[Deferred.asFuture.<locals>.checkCancel() at /usr/local/lib/python3.7/dist-packages/twisted/internet/defer.py:786, <TaskWakeupMethWrapper object at 0xb5abdd70>()] created at /usr/lib/python3.7/asyncio/base_events.py:396> cb=[_run_until_complete_cb() at /usr/lib/python3.7/asyncio/base_events.py:158] created at /usr/lib/python3.7/asyncio/base_events.py:563> took 0.346 seconds
Executing <Handle callWithLogger(<twisted.inte...at 0xb5b35f10>, <bound method...t 0xb5b35b10>>, <twisted.inte...at 0xb5b35f10>, True) at /usr/local/lib/python3.7/dist-packages/twisted/python/log.py:90 created at /usr/lib/python3.7/asyncio/selector_events.py:249> took 0.146 seconds
Executing <Handle callWithLogger(<twisted.inte...at 0xb5b35f10>, <bound method...t 0xb5b35b10>>, <twisted.inte...at 0xb5b35f10>, True) at /usr/local/lib/python3.7/dist-packages/twisted/python/log.py:90 created at /usr/lib/python3.7/asyncio/selector_events.py:249> took 0.144 seconds
Executing <Handle callWithLogger(<twisted.inte...at 0xb5b35f10>, <bound method...t 0xb5b35b10>>, <twisted.inte...at 0xb5b35f10>, True) at /usr/local/lib/python3.7/dist-packages/twisted/python/log.py:90 created at /usr/lib/python3.7/asyncio/selector_events.py:249> took 0.195 seconds

I get a new "Executing message every so often. It's not what I expected to see, and I certainly don't see any mention of services from which I may be able to figure out how to drill down and get the battery level.

I would be exceedingly grateful for any assistance in getting this seemingly simple piece of information out of my device.

dlech commented 3 years ago

Bleak does not require using sudo. Do you get the same results if you run without sudo?

lbussy commented 3 years ago

Thank you for the reply.

Running scanner.py as a regular user gives me:

$ ./scanner.py
Traceback (most recent call last):
  File "./scanner.py", line 12, in <module>
    loop.run_until_complete(run())
  File "/usr/lib/python3.7/asyncio/base_events.py", line 584, in run_until_complete
    return future.result()
  File "./scanner.py", line 7, in run
    devices = await BleakScanner.discover()
  File "/usr/local/lib/python3.7/dist-packages/bleak/backends/scanner.py", line 83, in discover
    async with cls(**kwargs) as scanner:
  File "/usr/local/lib/python3.7/dist-packages/bleak/backends/scanner.py", line 63, in __aenter__
    await self.start()
  File "/usr/local/lib/python3.7/dist-packages/bleak/backends/bluezdbus/scanner.py", line 123, in start
    ).asFuture(loop)
txdbus.error.RemoteError: org.freedesktop.DBus.Error.AccessDenied: Rejected send message, 2 matched rules; type="method_call", sender=":1.14" (uid=1000 pid=494 comm="python3 ./scanner.py ") interface="org.freedesktop.DBus.ObjectManager" member="GetManagedObjects" error name="(unset)" requested_reply="0" destination="org.bluez" (uid=0 pid=359 comm="/usr/lib/bluetooth/bluetoothd ")

With sudo:

$ sudo ./scanner.py
56:1D:FF:FE:90:74: 56-1D-FF-FE-90-74
2F:EC:10:83:7A:C3: 2F-EC-10-83-7A-C3
4C:B1:78:F5:61:62: 4C-B1-78-F5-61-62
FC:8F:90:A6:1B:EC: FC-8F-90-A6-1B-EC
49:6F:02:31:8A:7F: 49-6F-02-31-8A-7F
6B:A0:AF:3E:0D:87: 6B-A0-AF-3E-0D-87
04:C6:51:E4:E1:EA: 04-C6-51-E4-E1-EA
74:9C:3F:D2:0D:A9: 74-9C-3F-D2-0D-A9
28:2C:02:B4:D0:0E: R+_24_282C02B4D00E
50:65:83:6D:B2:5C: 50:65:83:6D:B2:5C   <--- This is the target this time
74:E7:7D:A6:BF:A6: 74-E7-7D-A6-BF-A6
75:4F:36:19:0C:70: 75-4F-36-19-0C-70
B8:BC:5B:61:AC:1A: B8-BC-5B-61-AC-1A
F4:BC:DA:32:96:39: D7881F01D551
FC:5E:BC:EF:17:64: FC-5E-BC-EF-17-64

Running service_explorer without sudo:

 $ ./service_explorer.py
Executing <Task pending coro=<run() running at ./service_explorer.py:27> wait_for=<Future pending cb=[Deferred.asFuture.<locals>.checkCancel() at /usr/local/lib/python3.7/dist-packages/twisted/internet/defer.py:786, <TaskWakeupMethWrapper object at 0xb5a3ee70>()] created at /usr/lib/python3.7/asyncio/base_events.py:396> cb=[_run_until_complete_cb() at /usr/lib/python3.7/asyncio/base_events.py:158] created at /usr/lib/python3.7/asyncio/base_events.py:563> took 0.441 seconds
Traceback (most recent call last):
  File "./service_explorer.py", line 64, in <module>
    loop.run_until_complete(run(address, True))
  File "/usr/lib/python3.7/asyncio/base_events.py", line 584, in run_until_complete
    return future.result()
  File "./service_explorer.py", line 27, in run
    async with BleakClient(address) as client:
  File "/usr/local/lib/python3.7/dist-packages/bleak/backends/client.py", line 59, in __aenter__
    await self.connect()
  File "/usr/local/lib/python3.7/dist-packages/bleak/backends/bluezdbus/client.py", line 95, in connect
    self.address, timeout=timeout, adapter=self._adapter
  File "/usr/local/lib/python3.7/dist-packages/bleak/backends/scanner.py", line 167, in find_device_by_address
    timeout=timeout, detection_callback=stop_if_detected, **kwargs
  File "/usr/local/lib/python3.7/dist-packages/bleak/backends/scanner.py", line 63, in __aenter__
    await self.start()
  File "/usr/local/lib/python3.7/dist-packages/bleak/backends/bluezdbus/scanner.py", line 123, in start
    ).asFuture(loop)
txdbus.error.RemoteError: org.freedesktop.DBus.Error.AccessDenied: Rejected send message, 2 matched rules; type="method_call", sender=":1.16" (uid=1000 pid=511 comm="python3 ./service_explorer.py ") interface="org.freedesktop.DBus.ObjectManager" member="GetManagedObjects" error name="(unset)" requested_reply="0" destination="org.bluez" (uid=0 pid=359 comm="/usr/lib/bluetooth/bluetoothd ")

With sudo:

sudo ./service_explorer.py
Executing <Task pending coro=<run() running at ./service_explorer.py:27> wait_for=<Future pending cb=[Deferred.asFuture.<locals>.checkCancel() at /usr/local/lib/python3.7/dist-packages/twisted/internet/defer.py:786, <TaskWakeupMethWrapper object at 0xb5b06cf0>()] created at /usr/lib/python3.7/asyncio/base_events.py:396> cb=[_run_until_complete_cb() at /usr/lib/python3.7/asyncio/base_events.py:158] created at /usr/lib/python3.7/asyncio/base_events.py:563> took 0.317 seconds
Executing <Handle callWithLogger(<twisted.inte...at 0xb5b7eeb0>, <bound method...t 0xb5b7eab0>>, <twisted.inte...at 0xb5b7eeb0>, True) at /usr/local/lib/python3.7/dist-packages/twisted/python/log.py:90 created at /usr/lib/python3.7/asyncio/selector_events.py:249> took 0.116 seconds

(and then it just repeats)

I did add the user to dialout, logout, and login, no changes in the results.

dlech commented 3 years ago

I think the user needs to be added to the bluetooth group rather than dialout. See #9.

lbussy commented 3 years ago

I did not see anything in #9 about that, however, did find #228, #356, and #358 which echoed your suggestion. I added my user to bluetooth and restarted bluetoothd and as you probably already suspect, I am able to run scanner.py as my regular user.

Running service_explorer.py as the regular user gives me a different error now at least:

Executing <Task pending coro=<run() running at ./service_explorer.py:27> wait_for=<Future pending cb=[Deferred.asFuture.<locals>.checkCancel() at /usr/local/lib/python3.7/dist-packages/twisted/internet/defer.py:786, <TaskWakeupMethWrapper object at 0xb5af0e90>()] created at /usr/lib/python3.7/asyncio/base_events.py:396> cb=[_run_until_complete_cb() at /usr/lib/python3.7/asyncio/base_events.py:158] created at /usr/lib/python3.7/asyncio/base_events.py:563> took 0.280 seconds
Traceback (most recent call last):
  File "./service_explorer.py", line 64, in <module>
    loop.run_until_complete(run(address, True))
  File "/usr/lib/python3.7/asyncio/base_events.py", line 584, in run_until_complete
    return future.result()
  File "./service_explorer.py", line 27, in run
    async with BleakClient(address) as client:
  File "/usr/local/lib/python3.7/dist-packages/bleak/backends/client.py", line 59, in __aenter__
    await self.connect()
  File "/usr/local/lib/python3.7/dist-packages/bleak/backends/bluezdbus/client.py", line 161, in connect
    await self.get_services()
  File "/usr/local/lib/python3.7/dist-packages/bleak/backends/bluezdbus/client.py", line 390, in get_services
    raise BleakError("Services discovery error")
bleak.exc.BleakError: Services discovery error

The await self.get_services() part has me curious. Is the MAC in the example supposed to be changed to the target device?

if __name__ == "__main__":
    address = ("50:65:83:6D:B2:5C")
    loop = asyncio.get_event_loop()
    loop.set_debug(True)
    loop.run_until_complete(run(address, True))
dlech commented 3 years ago

No idea where I got #9 from but whatever I was looking at was similar to the issues you found anyway.

Yes, you need to change the sample to match the address of the device you want as it looks like you have done.

That error looks like it is a timeout trying to resolve services:

https://github.com/hbldh/bleak/blob/e968a7b666b4ba76477e25c24887fa57afda0e19/bleak/backends/bluezdbus/client.py#L381-L390

You could try a branch I am working on instead of v0.10.0:

pip install --force-reinstall https://github.com/hbldh/bleak/archive/dbus-next-2.zip#egg=bleak

Not sure if it will make a difference or not but it changes the code where the error is happening.

lbussy commented 3 years ago

Okay, so some progress. I spun up a quick ESP32 to serve a BLEacon. service_discovery.py yielded the following:

$ ./service_explorer.py
Executing <Task pending coro=<run() running at ./service_explorer.py:27> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0xb5a97bb0>()] created at /usr/lib/python3.7/asyncio/base_events.py:396> cb=[_run_until_complete_cb() at /usr/lib/python3.7/asyncio/base_events.py:158] created at /usr/lib/python3.7/asyncio/base_events.py:563> took 0.170 seconds
Executing <Handle MessageBus._message_reader() created at /usr/lib/python3.7/asyncio/selector_events.py:249> took 0.139 seconds
Executing <Handle MessageBus._message_reader() created at /usr/lib/python3.7/asyncio/selector_events.py:249> took 0.118 seconds
Executing <Handle MessageBus._message_reader() created at /usr/lib/python3.7/asyncio/selector_events.py:249> took 0.139 seconds
Connected: True
[Service] 00001801-0000-1000-8000-00805f9b34fb: Generic Attribute Profile
        [Characteristic] 00002a05-0000-1000-8000-00805f9b34fb: (Handle: 2) (indicate) | Name: Service Changed, Value: None
                [Descriptor] 00002902-0000-1000-8000-00805f9b34fb: (Handle: 4) | Value: b'\x02\x00'
Task was destroyed but it is pending!
source_traceback: Object created at (most recent call last):
  File "./service_explorer.py", line 64, in <module>
    loop.run_until_complete(run(address, True))
  File "/usr/lib/python3.7/asyncio/base_events.py", line 571, in run_until_complete
    self.run_forever()
  File "/usr/lib/python3.7/asyncio/base_events.py", line 539, in run_forever
    self._run_once()
  File "/usr/lib/python3.7/asyncio/base_events.py", line 1767, in _run_once
    handle._run()
  File "/usr/lib/python3.7/asyncio/events.py", line 88, in _run
    self._context.run(self._callback, *self._args)
  File "./service_explorer.py", line 27, in run
    async with BleakClient(address) as client:
  File "/usr/local/lib/python3.7/dist-packages/bleak/backends/client.py", line 59, in __aenter__
    await self.connect()
  File "/usr/local/lib/python3.7/dist-packages/bleak/backends/bluezdbus/client.py", line 261, in connect
    asyncio.create_task(self._disconnect_monitor())
  File "/usr/lib/python3.7/asyncio/tasks.py", line 325, in create_task
    return loop.create_task(coro)
task: <Task pending coro=<BleakClientBlueZDBus._disconnect_monitor() running at /usr/local/lib/python3.7/dist-packages/bleak/backends/bluezdbus/client.py:282> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0xb5949eb0>()] created at /usr/lib/python3.7/asyncio/base_events.py:396> created at /usr/lib/python3.7/asyncio/tasks.py:325>

Connecting to my intended device failed however:

 $ ./service_explorer.py
Executing <Task pending coro=<run() running at ./service_explorer.py:27> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0xb5acdc30>()] created at /usr/lib/python3.7/asyncio/base_events.py:396> cb=[_run_until_complete_cb() at /usr/lib/python3.7/asyncio/base_events.py:158] created at /usr/lib/python3.7/asyncio/base_events.py:563> took 0.164 seconds
ERROR:root:A message handler raised an exception: 'Address'.
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/dist-packages/dbus_next/message_bus.py", line 656, in _process_message
    result = handler(msg)
  File "/usr/local/lib/python3.7/dist-packages/bleak/backends/bluezdbus/scanner.py", line 294, in _parse_msg
    props["Address"], props["Alias"], props, props.get("RSSI", 0)
KeyError: 'Address'

WARNING:asyncio:Executing <Handle MessageBus._message_reader() created at /usr/lib/python3.7/asyncio/selector_events.py:249> took 0.286 seconds
ERROR:root:A message handler raised an exception: 'Address'.
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/dist-packages/dbus_next/message_bus.py", line 656, in _process_message
    result = handler(msg)
  File "/usr/local/lib/python3.7/dist-packages/bleak/backends/bluezdbus/scanner.py", line 294, in _parse_msg
    props["Address"], props["Alias"], props, props.get("RSSI", 0)
KeyError: 'Address'

{Same error message x 10}

WARNING:asyncio:Executing <Handle MessageBus._message_reader() created at /usr/lib/python3.7/asyncio/selector_events.py:249> took 0.168 seconds
ERROR:root:A message handler raised an exception: 'Address'.
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/dist-packages/dbus_next/message_bus.py", line 656, in _process_message
    result = handler(msg)
  File "/usr/local/lib/python3.7/dist-packages/bleak/backends/bluezdbus/scanner.py", line 294, in _parse_msg
    props["Address"], props["Alias"], props, props.get("RSSI", 0)
KeyError: 'Address'

{Same error message x 10}

WARNING:asyncio:Executing <Handle MessageBus._message_reader() created at /usr/lib/python3.7/asyncio/selector_events.py:249> took 0.123 seconds
ERROR:root:A message handler raised an exception: 'Address'.
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/dist-packages/dbus_next/message_bus.py", line 656, in _process_message
    result = handler(msg)
  File "/usr/local/lib/python3.7/dist-packages/bleak/backends/bluezdbus/scanner.py", line 294, in _parse_msg
    props["Address"], props["Alias"], props, props.get("RSSI", 0)
KeyError: 'Address'

WARNING:asyncio:Executing <Handle MessageBus._message_reader() created at /usr/lib/python3.7/asyncio/selector_events.py:249> took 0.250 seconds
ERROR:root:A message handler raised an exception: 'Address'.
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/dist-packages/dbus_next/message_bus.py", line 656, in _process_message
    result = handler(msg)
  File "/usr/local/lib/python3.7/dist-packages/bleak/backends/bluezdbus/scanner.py", line 294, in _parse_msg
    props["Address"], props["Alias"], props, props.get("RSSI", 0)
KeyError: 'Address'

{Same error message x 4}

WARNING:asyncio:Executing <Handle MessageBus._message_reader() created at /usr/lib/python3.7/asyncio/selector_events.py:249> took 0.102 seconds
ERROR:root:A message handler raised an exception: 'Address'.
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/dist-packages/dbus_next/message_bus.py", line 656, in _process_message
    result = handler(msg)
  File "/usr/local/lib/python3.7/dist-packages/bleak/backends/bluezdbus/scanner.py", line 294, in _parse_msg
    props["Address"], props["Alias"], props, props.get("RSSI", 0)
KeyError: 'Address'

WARNING:asyncio:Executing <Handle MessageBus._message_reader() created at /usr/lib/python3.7/asyncio/selector_events.py:249> took 0.155 seconds
Traceback (most recent call last):
  File "./service_explorer.py", line 64, in <module>
    loop.run_until_complete(run(address, True))
  File "/usr/lib/python3.7/asyncio/base_events.py", line 584, in run_until_complete
    return future.result()
  File "./service_explorer.py", line 27, in run
    async with BleakClient(address) as client:
  File "/usr/local/lib/python3.7/dist-packages/bleak/backends/client.py", line 59, in __aenter__
    await self.connect()
  File "/usr/local/lib/python3.7/dist-packages/bleak/backends/bluezdbus/client.py", line 119, in connect
    "Device with address {0} was not found.".format(self.address)
bleak.exc.BleakError: Device with address 50:65:83:6d:b2:5c was not found.

In the "I'm not sure if this is interesting or not" category: I mentioned I have a Pi Zero and a Pi 4. The tests above were on the Zero (and of course painfully slow). I tried on the Pi 4 as well. This is with 0.10.0:

$ ./service_discovery.py
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/dist-packages/bleak/backends/bluezdbus/client.py", line 139, in connect
    ).asFuture(loop)
txdbus.error.RemoteError: org.freedesktop.DBus.Error.UnknownObject: Method "Connect" with signature "" on interface "org.bluez.Device1" doesn't exist

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "./service_discovery.py", line 64, in <module>
    loop.run_until_complete(run(address, True))
  File "/usr/lib/python3.7/asyncio/base_events.py", line 584, in run_until_complete
    return future.result()
  File "./service_discovery.py", line 27, in run
    async with BleakClient(address) as client:
  File "/usr/local/lib/python3.7/dist-packages/bleak/backends/client.py", line 59, in __aenter__
    await self.connect()
  File "/usr/local/lib/python3.7/dist-packages/bleak/backends/bluezdbus/client.py", line 146, in connect
    self.address
bleak.exc.BleakError: Device with address 50:65:83:6D:B2:5C could not be found. Try increasing `timeout` value or moving the device closer.

So I then installed the other branch you recommended and got this:

$ ./service_discovery.py                                              Traceback (most recent call last):
  File "./service_discovery.py", line 64, in <module>
    loop.run_until_complete(run(address, True))
  File "/usr/lib/python3.7/asyncio/base_events.py", line 584, in run_until_complete
    return future.result()
  File "./service_discovery.py", line 27, in run
    async with BleakClient(address) as client:
  File "/usr/local/lib/python3.7/dist-packages/bleak/backends/client.py", line 59, in __aenter__
    await self.connect()
  File "/usr/local/lib/python3.7/dist-packages/bleak/backends/bluezdbus/client.py", line 119, in connect
    "Device with address {0} was not found.".format(self.address)
bleak.exc.BleakError: Device with address 50:65:83:6D:B2:5C was not found.

I am not sure if the difference is interesting or not.

What I do see however is that I am failing to connect to the device I can see with a different scanning tool. When I go back to my ESP32 "BLEacon" I get this:

$ ./service_discovery.py
Connected: True
[Service] 00001801-0000-1000-8000-00805f9b34fb: Generic Attribute Profile
        [Characteristic] 00002a05-0000-1000-8000-00805f9b34fb: (Handle: 2) (indicate) | Name: Service Changed, Value: None
                [Descriptor] 00002902-0000-1000-8000-00805f9b34fb: (Handle: 4) | Value: b'\x02\x00'

(and then a stack trace probably related to threading)

So, it looks like (and please tell me if you think I am off-track) I have a "me" issue to fix. It also looks like I was more successful with your newer branch, but I'm not sure what differences you expected to see.

I'll continue to dig and report what I am able to figure out. Thank you very much for your help so far. It's challenging keeping up with us knuckle-draggers I am sure.

dlech commented 3 years ago

We really appreciate people like you that don't give up and take the time to dig into issues like this too. Dealing with such a wide variety of hardware devices is always going to be challenging. :smile:

dhalbert commented 3 years ago

I have not looked closely at your traces, but I recall that bluez treats the battery service specially and intercepts it, rather than just passing it through as a regular service. I do not know the exact details but here is an example of what a websearch would turn up: https://stackoverflow.com/questions/49078659/check-battery-level-of-connected-bluetooth-device-on-linux

lbussy commented 3 years ago

Dealing with such a wide variety of hardware devices is always going to be challenging.

I can't even imagine. I have a couple of ESP-based projects and it's amazing to me how you get differences even between the knockoffs of the same device.

I recall that bluez treats the battery service specially and intercepts it, rather than just passing it through as a regular service.

Now that's interesting. I did find an example of an implementation for headsets that uses AT commands via RFCOMM. I was able to confirm that this is not a viable approach for my device. The discussion did lead me to trying bluetoothctl and within that, the gatt commands which seem to be available therein. My "dummy" ESP32 device does allow me to list attributes:

[bluetooth]# list-attributes
Missing device address argument
[bluetooth]# list-attributes 24:6F:28:2E:7F:9E
Primary Service
        /org/bluez/hci0/dev_24_6F_28_2E_7F_9E/service0001
        00001801-0000-1000-8000-00805f9b34fb
        Generic Attribute Profile
Characteristic
        /org/bluez/hci0/dev_24_6F_28_2E_7F_9E/service0001/char0002
        00002a05-0000-1000-8000-00805f9b34fb
        Service Changed
Descriptor
        /org/bluez/hci0/dev_24_6F_28_2E_7F_9E/service0001/char0002/desc0004
        00002902-0000-1000-8000-00805f9b34fb
        Client Characteristic Configuration

... sadly my intended target device does not. The only other tool I have right now is nRF Connect (on my iPhone) and with that, I can connect to my device and see the battery level. Therefore I know it works somehow. Finding the "how" is my challenge.

I also found getsenic/gatt-python which made it very easy to get services from my dummy device:

$ gattctl --connect 24:6f:28:2e:7f:9e
Connecting...
Terminate with Ctrl+C
[24:6f:28:2e:7f:9e] Discovered, alias = BLE Battery
[24:6f:28:2e:7f:9e] Connected
[24:6f:28:2e:7f:9e] Discovered, alias = BLE Battery
[24:6f:28:2e:7f:9e] Resolved services
[24:6f:28:2e:7f:9e]  Service [0000180f-0000-1000-8000-00805f9b34fb]
[24:6f:28:2e:7f:9e]    Characteristic [00002a19-0000-1000-8000-00805f9b34fb]
[24:6f:28:2e:7f:9e]  Service [00001801-0000-1000-8000-00805f9b34fb]
[24:6f:28:2e:7f:9e]    Characteristic [00002a05-0000-1000-8000-00805f9b34fb]

Alas, still no joy on my intended target. I am unable to make a connection, which jives with what I have been able to do with this library. But again, the nRF tool does connect, adding to the mystery:

IMG_0462 PNG

IMG_0463 PNG

Can you imagine how fast development would be if things worked the first try? I mean, forget virus vaccines, that would be a game changer.

dlech commented 2 years ago

We have some related issues, like #393 open, so closing this as a duplicate.