Bluetooth-Devices / bthome-ble

Parser for BTHome BLE devices
https://bthome.io/
MIT License
67 stars 12 forks source link

Reception of advertising in the "Long Range" mode (Coded PHY S=8) does not work. #45

Closed pvvx closed 1 year ago

pvvx commented 1 year ago

The BT5.2 adapter supports "Extended Advertising" reception. Reception of advertising in the "Long Range" mode (Coded PHY S=8) does not work in BTHome-ble.

The test version of the "Long Range" thermometer is successfully received in nRF Connect: image

And connects successfully: image

Ernst79 commented 1 year ago

I'm afraid I don't have an BT5.2 adapter to test. Is the Bluetooth integration in HA able to receive this data when you enable debug logging?

pvvx commented 1 year ago

Home Assistant does not have a Coded PHY receive option. These are not problems with BT adapters.

pvvx commented 1 year ago

On any BT5.2-USB adapter:

image

image

bluetoothctl --version bluetoothctl: 5.66

image

Ernst79 commented 1 year ago

I'm not sure I completely understand the issue. You say:

Reception of advertising in the "Long Range" mode (Coded PHY S=8) does not work in BTHome-ble.

So, if you make the thermometer send data in "Long Range" mode (Coded PHY S=8)", it isn't received by the BTHome integration in Home Assistant.?

So, first thing to figure out, is the Bluetooth integration in HA receiving this data? As I understand from your reaction, it isn't.

Home Assistant does not have a Coded PHY receive option.

So, I think the issue is with the Bluetooth integration then, isn't it? Perhaps @bdraco can help with this?

pvvx commented 1 year ago

The integration does not have the ability to switch the adapter to work with CodedPHY.

Switch the adapter to work with CodedPHY: hcitool -i hci0 cmd 08 31 03 04 04 image

Launch Home Assistant and it will only receive in LongRange mode.

Find out the possibility of BT adapter

Information about adapter capabilities:

# btmgmt phy
Supported phys: BR1M1SLOT BR1M3SLOT BR1M5SLOT EDR2M1SLOT EDR2M3SLOT EDR2M5SLOT EDR3M1SLOT EDR3M3SLOT EDR3M5SLOT LE1MTX LE1MRX LE2MTX LE2MRX LECODEDTX LECODEDRX
Configurable phys: BR1M3SLOT BR1M5SLOT EDR2M1SLOT EDR2M3SLOT EDR2M5SLOT EDR3M1SLOT EDR3M3SLOT EDR3M5SLOT LE2MTX LE2MRX LECODEDTX LECODEDRX
Selected phys: BR1M1SLOT BR1M3SLOT BR1M5SLOT EDR2M1SLOT EDR2M3SLOT EDR2M5SLOT EDR3M1SLOT EDR3M3SLOT EDR3M5SLOT LECODEDTX LECODEDRX

# hciconfig -a
hci0:   Type: Primary  Bus: USB
        BD Address: 8C:88:2B:20:8B:42  ACL MTU: 1021:6  SCO MTU: 255:12
        UP RUNNING
        RX bytes:2020 acl:0 sco:0 events:178 errors:0
        TX bytes:23965 acl:0 sco:0 commands:178 errors:0
        Features: 0xff 0xff 0xff 0xfe 0xdb 0xfd 0x7b 0x87
        Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3
        Link policy: RSWITCH HOLD SNIFF PARK
        Link mode: SLAVE ACCEPT
        Name: 'nanopineoplus2'
        Class: 0x000000
        Service Classes: Unspecified
        Device Class: Miscellaneous,
        HCI Version: 5.1 (0xa)  Revision: 0x999
        LMP Version: 5.1 (0xa)  Subversion: 0x646b
        Manufacturer: Realtek Semiconductor Corporation (93)

This became possible not very long ago, when the errors in the kernel and the Bluez were removed. BT5.0+ adapters support switching to CodedPHY since 2016. BT5.0 support was first implemented in Android a couple of years ago, but not for all APIs...

Without a special option, if the adapter is reset by errors, the operation will switch back to 1M PHY. As a result, the integration requires a special flag to initialize the adapter in CodedPHY or 1M PHY mode.

PS: The "LongRange" mode means that this is an extended advertisement with "Primary PHY: LE Coded S=8" and "Secondary PHY: LE Coded S=8"

pvvx commented 1 year ago

I'm afraid I don't have an BT5.2 adapter to test.

All low-cost RTL8761B BT5.0

USB ID 0bda:8771 Realtek Semiconductor Corp. Bluetooth Radio HCI Version: 5.1 (0xa) LMP Version: 5.1 (0xa)

Example for test in nRFConnect: image

image

Do not distinguish random MAC?

So, I think the issue is with the Bluetooth integration then, isn't it? Perhaps @bdraco can help with this?

It is precisely because of blaming problems on others that Long Range has not worked anywhere since 2016.

image

PS2: How can "Periodic Advertisements" be used if "Unknown" is enabled through an unregulated timeout?

pvvx commented 1 year ago

There is no way to change the PHY type of the adapter during HA runtime. It is required to reboot the entire system, with switching during stop HA.

nRFConnect on smartphones accepts both 1M PHY and Coded PHY advertisements on the main BLE channels. And the current implementation of integrations in HA does not know how. The reception of Coded PHY was written in the BLE standards back in 2016...

Ernst79 commented 1 year ago

I don't blame @bdraco, he has been more than helpful for me with the development of BTHome. But all code for receiving Bluetooth data is being carried out by the Bluetooth integration. The BTHome integration is only using the parsed data from the Bluetooth integration to further parse it into entities. But all the data receiving logic is implemented in the Bluetooth integration in HA.

So, to my opinion, you should create an issue in the Home Assistant core github, and label it with the Bluetooth integration. In that way, @bdraco can have a look if it is possible to implement this. It is out of my capabilities to do this, unfortunately.

PS2. I'll create a separate issue for the Periodic Advertisements. We had the same issue for some of the Xiaomi sensors, like door sensors. We can implement the same fix for BTHome.

pvvx commented 1 year ago

Home Assistant Bluetooth support is entirely based on bleak so we only support what bleak supports.

Bleak not supports reading, writing and getting notifications from GATT servers, as well as a function for discovering BLE devices Bluetooth Core Specification Version 5.0 and next version?

Работа термометров в Home Assistant c Bluetooth LE Long Range.

BTHome->Bluetooth->Bleak->dbus->Bluez->kernel->adapter and in a circle. Everyone points to each other.

Ernst79 commented 1 year ago

Home Assistant does support reading characteristics. E.g. the xiaomi ble integration supports reading the battery from the plant sensor, which is only possible by reading characteristics.

https://github.com/home-assistant/core/blob/b407227d4a735d5337f3cf7a8d04a13fd82b8def/homeassistant/components/xiaomi_ble/__init__.py#L102

Anyway, @bdraco has made changes and improvement to bleak as well, when he developed the Bluetooth integration. So, if one is able to look into your request, we should ask him.

Ernst79 commented 1 year ago

About the pointing to each other, that is not what I want. I just try to say that your request is way out of my capabilities. So, unfortunately I can’t help with this, just because of my lack of experience.

pvvx commented 1 year ago

BTHome->Bluetooth->Bleak->dbus->Bluez->kernel->adapter and in a circle. Everyone points to each other. The solution is simple - switch the adapter to work in Bluetooth 5.0. - BTHome->Bluez->kernel->adapter

Bluetooth->Bleak->dbus->Bluez>kernel - This chain will not work with BT5.0 for years. There's also 'docker' involved

Ernst79 commented 1 year ago

I understand, but that is still way out of my capabilities. And I think the HA devs probably like a solution that works for every Bluetooth integration. Again, you should ask @bdraco, he can help thinking about a possible solution. I’ll ask him on discord if he is willing to have a look here.

pvvx commented 1 year ago

To date, switching is only relevant for BTHome for DIY sensors. Switching does not affect other HA integrations. The adapter will accept all BLE advertising options.

Or wait years for Linux to start initializing BT adapters in normal mode, and not BT4.0?

Again, you should ask @bdraco, he can help thinking about a possible solution.

Maybe ask Linus Torvalds? :)

PS: Then I make a decision: "LE Long Range" will be banned for english-speaking audiences on Linux for years to come.

Ernst79 commented 1 year ago

😄

Ok, I understand, only BTHome for now. But again, Its out of my capabilities. Its not that im not willing, but I know my limitation with regards to programming. And this is too difficult for me unfortunately.

pvvx commented 1 year ago

"Home Assistant" will never use Bluetooth 5.0 and above. On the sold board and on the RPi, the installed adapters are Bluetooth 4.0. ESPHome does not support new chips that support Bluetooth 5.0 and above. ESP32 is Bluetooth 4.0.

Asking them about it is useless.

The documentation for Home Assistant does not show that Bluetooth 5.0 is not supported. Probably, someone pays them extra so that the people do not have the opportunity to use the “LE Long Range”, introduced into the BLE standard back in 2016. The issue with "LE Long Range" and BT5.0 on Linux is dark. It started many years ago, when some Intel guys made changes to the kernel and BT drivers in Linux so that BLE would not develop - not support the Bluetooth SIG standards. Not without the complicity of Linus Torvalds... Google has fixed these bugs in Android.

The first part related to blocking the driver while receiving BLE ads has been patched. But not in all utilities. There is now no support for BT5.0 in Linux utilities and APIs. The old options don't have the option to select 'primary PHY' for any requests... Connection to BLE devices with ext. advertising is not fixed, and so on ...

PS: BLE in Linux is dead. If you don't agree that BLE is dead on Linux, start by adding an option to allow users to switch the adapter to BT5.0 mode. The rest of the "vicious circle" will be forced to correct their mistakes.

acinonyx commented 1 year ago

@pvvx please, correct me if I am wrong, but isn't the DBUS interface from bluez the missing link at the moment so that bleak, and eventually HA bluetooth integration and BTHome to support this feature?

I'm not too familiar with Bluez, but it seems to me that the management API is there, but not exposed to the DBUS Adapter API in any way.

pvvx commented 1 year ago

Начало завязки лежит в kernel. Там свои тараканы у подписывающих патчи и принимавших решения по развитию. И у них лицензия GNU - т.е. с авторскими правами. Т.е. что хотят, то и творят - могут принять ваши коды и поправки под своё авторство, а могут не не принять. Пока, с 2016 года, принимали только отрицательные решения по BLE от кентов из Intel, чтобы развития BLE в Linux не происходило. В итоге Google нарвалось и не может это сдвинуть уже несколько лет.

The beginning of the tie lies in the kernel. They have their own cockroaches signing patches and making decisions on development. And they have a GNU license - that is, with copyrights. That is, they do what they want - they can accept your codes and amendments under their authorship, or they cannot not accept. So far, since 2016, only negative decisions have been made on BLUE from Intel's kents, so that the development of BLE in Linux does not occur. As a result, Google has faced this and has not been able to provide BLE 5.0 support to all users in its APIs for several years.

Bluez does not have "primary PHY" parameters in API requests. Rebuilding of all queries is required.

Bleak works via DBUS. DBUS works with Bluez. Bluez works with kernel... Kernel works with drivers.

Drivers - ok since 2016. Kernel - error and no support. Partial support for BT4.0 only.

pvvx commented 1 year ago

Web Bluetooth API: Implementation Status :)

For today, BT 5.0 support is available only in Android and Mac via the internal API. Or on Chinese patched versions of linux distributions on small boards...

The Android WEB bluetooth API lacks support for scanning BT5.0+ formats. But, if the Chrome scan list has an entry of a MAC device with BT 5.0 and higher, then the connection is provided with any PHY and formats. Not on Linux.

To date, to connect to a device in version 4.2 according to the specification, you will need to change a lot of settings in Bluez. Or fix the kernel.

Bluez utilities do not support new API branches in Bluez. And new branches arose due to the lack of support in the old versions of the BT 5.0. But the BT4.2 specification does not work either. The problem with timeouts. Partial solution. But there is an error - it is necessary to rearrange line 43 to 41.

const unsigned char * const buf_end; // = buf + size;
    /* Skip event header */
    buf += 6;
        buf_end = buf + size;