Skip to content
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

How can I activate notify if both notify and indicate are in the characteristic at the same time? #526

Closed
chandong83 opened this issue Apr 24, 2021 · 4 comments · Fixed by #620
Labels
Backend: pythonnet Issues or PRs relating to the .NET/pythonnet backend Backend: WinRT Issues or PRs relating to the WinRT backend

Comments

@chandong83
Copy link

chandong83 commented Apr 24, 2021

  • bleak version: 0.11.0
  • Python version: 3.7.8
  • Operating System: windows 10
  • BlueZ version (bluetoothctl -v) in case of Linux:

Description

Hello,
Thanks for sharing a great library.

i'm using bleak to control BLE(bluetooth low energy) devices in Python.
and i was trying to control a BLE device that included notify and indicate properties in one characteristic,
so there was a problem that only indicate is activated.

so when i checked the bleak source code, it was found that if indicate exists, activate it as indicate, and if not, check notify and activate it as notify, and start_notify works.

the following is the relevant source code and link.

https://github.com/hbldh/bleak/blob/develop/bleak/backends/winrt/client.py

    async def start_notify(
            self,
            char_specifier: Union[BleakGATTCharacteristic, int, str, uuid.UUID],
            callback: Callable[[int, bytearray], None],
            **kwargs
        ) -> None:
            ...
            ...
            characteristic_obj = characteristic.obj
            if (
                characteristic_obj.characteristic_properties
                & GattCharacteristicProperties.INDICATE
            ):
                cccd = GattClientCharacteristicConfigurationDescriptorValue.INDICATE
            elif (
                characteristic_obj.characteristic_properties
                & GattCharacteristicProperties.NOTIFY
            ):
                cccd = GattClientCharacteristicConfigurationDescriptorValue.NOTIFY
            else:
                cccd = GattClientCharacteristicConfigurationDescriptorValue.NONE
    
            fcn = _notification_wrapper(bleak_callback, asyncio.get_event_loop())
            event_handler_token = characteristic_obj.add_value_changed(fcn)
            self._notification_callbacks[characteristic.handle] = event_handler_token
            status = await characteristic_obj.write_client_characteristic_configuration_descriptor_async(
                cccd
            )

What I Did

what is the best way to deal with it in this case?
so i implemented the code below to use "notify", but it doesn't look good.

    async with BleakClient(address, timeout=5.0) as client:
        client.set_disconnected_callback(on_disconnect)                        
        services = await client.get_services()        
        for service in services:
            for characteristic in service.characteristics:
                if characteristic.uuid == read_write_charcteristic_uuid:  
                    if 'notify' in characteristic.properties:
                        # if "indicate" is exist remove it
                        if 'indicate' in characteristic.properties:
                            characteristic.properties.remove('indicate')
                        # then "notify" becomes active.
                        await client.start_notify(notify_charcteristic, callback)

thank you

@dlech
Copy link
Collaborator

dlech commented Apr 24, 2021

Apple doesn't allow selecting notifications or indications separately and doesn't specify what happens if a characteristic allows both.

BlueZ is similar in that the D-Bus API doesn't allow specifying which to enable. But since it is open source, we can see that it will prefer notifications over indications.

So it would be nice if someone could test the behavior on Apple to see what it does. But I would suggest that we change the Windows backends to prefer notifications over indications just like BlueZ. My experience has been that indications aren't really used much and tend to have long timeouts. (I would be interested to know if others have had a different experience.)

@dlech dlech added Backend: pythonnet Issues or PRs relating to the .NET/pythonnet backend Backend: WinRT Issues or PRs relating to the WinRT backend labels Apr 24, 2021
@chandong83
Copy link
Author

@dlech
Thank you for answer.

I didn't doubt it because on android, esp32 and nrf52, i can choose notify and indicate.

thanks for the good information.
and thanks to you, I learned a lot.

@hbldh
Copy link
Owner

hbldh commented Apr 24, 2021

The reason I chose indication over notification is because that is the way it is done in the MS UWP samples: https://github.com/microsoft/Windows-universal-samples/blob/b1cb20f191d3fd99ce89df50c5b7d1a6e2382c01/Samples/BluetoothLE/cs/Scenario2_Client.xaml.cs#L382

It seems like a force_notify keyword in the Windows backend start_notify might be called for.

@chandong83
Copy link
Author

chandong83 commented Apr 25, 2021

@hbldh

Thank you for answer.

Yes I understand what you mean (for window sample code). But I didn't understand the content well below it.

"It seems like a force_notify keyword in the Windows backend start_notify might be called for."

i'm sorry, does that mean that I can directly add the force_notify keyword in the library to change notify first? Or is there another way?

Thank you

@dlech dlech reopened this Apr 25, 2021
hbldh added a commit that referenced this issue Aug 10, 2021
hbldh added a commit that referenced this issue Aug 10, 2021
hbldh added a commit that referenced this issue Aug 12, 2021
@dlech dlech closed this as completed in #620 Oct 6, 2021
dlech added a commit that referenced this issue Oct 17, 2021
Added
-----

* Allow 16-bit UUID string arguments to ``get_service()`` and ``get_characteristic()``.
* Added ``register_uuids()`` to augment the uuid-to-description mapping.
* Added support for Python 3.10.
* Added ``force_indicate`` keyword argument for WinRT backend client's ``start_notify`` method. Fixes #526.
* Added python-for-android backend.

Changed
-------

* Changed from ``winrt`` dependency to ``bleak-winrt``.
* Improved error when connecting to device fails in WinRT backend. Fixes #647.
* Changed examples to use ``asyncio.run()``.
* Changed the default notify method for the WinRT backend from ``Indicate`` to ``Notify``.
* Refactored GATT error handling in WinRT backend.
* Changed Windows Bluetooth packet capture instructions. Fixes #653.
* Replaced usage of deprecated ``@abc.abstractproperty``.
* Use ``asyncio.get_running_loop()`` instead of ``asyncio.get_event_loop()``.

Removed
-------

* Removed ``dotnet`` backend.
* Dropped support for Python 3.6.
* Removed ``use_cached`` kwarg from ``BleakClient`` ``connect()`` and ``get_services()`` methods. Fixes #646.

Fixed
-----

* Fixed unused timeout in the implementation of BleakScanner's ``find_device_by_address()`` function.
* Fixed BleakClient ignoring the ``adapter`` kwarg. Fixes #607.
* Fixed writing descriptors in WinRT backend. Fixes #615.
* Fixed race on disconnect and cleanup of BlueZ matches when device disconnects early. Fixes #603.
* Fixed memory leaks on Windows.
* Fixed protocol error code descriptions on WinRT backend. Fixes #532.
* Fixed race condition hitting assentation in BlueZ ``disconnect()`` method. Fixes #641.
* Fixed enumerating services on a device with HID service on WinRT backend. Fixes #599.
* Fixed subprocess running to check BlueZ version each time a client is created. Fixes #602.
* Fixed exception when discovering services after reconnecting in CoreBluetooth backend.
@dlech dlech mentioned this issue Oct 17, 2021
karlp added a commit to etactica/bleak that referenced this issue Jan 6, 2023
Added a few user friendly helpers to auto switch to
write/write_without_response where appropriate, rather than simply
failing.  The BGAPI would simply send the other style as requested, and
the remote device would simply ignore it.

For "start_notify", the "force_indicate" kwarg has been used, to support
both notify and indicate, as in the WinRT backend,
see also hbldh#526 for more information

Signed-off-by: Karl Palsson <karlp@etactica.com>
karlp added a commit to etactica/bleak that referenced this issue Jan 9, 2023
Added a few user friendly helpers to auto switch to
write/write_without_response where appropriate, rather than simply
failing.  The BGAPI would simply send the other style as requested, and
the remote device would simply ignore it.

For "start_notify", the "force_indicate" kwarg has been used, to support
both notify and indicate, as in the WinRT backend,
see also hbldh#526 for more information

Signed-off-by: Karl Palsson <karlp@etactica.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Backend: pythonnet Issues or PRs relating to the .NET/pythonnet backend Backend: WinRT Issues or PRs relating to the WinRT backend
Projects
None yet
3 participants