-
Notifications
You must be signed in to change notification settings - Fork 259
Description
Предварительное описание решения.
Для примера можно взять:
Low-cost Realtek RTL8761BU BT adapter
USB ID 0bda:8771 Realtek Semiconductor Corp. Bluetooth Radio
Сurrent version of Linux fw on RTL8761BU supports Bluetooth Core ver 5.4:
# hciconfig hci2 version
hci2: Type: Primary Bus: USB
BD Address: 8C:88:2B:00:E7:EA ACL MTU: 1021:6 SCO MTU: 255:12
HCI Version: (0xd) Revision: 0xddd5
LMP Version: (0xd) Subversion: 0xc761
Manufacturer: Realtek Semiconductor Corporation (93)
Для работы HA c LE Long Range в интеграции “Bluetooth” желательно установить последнюю версию bluez и добавить в файле /lib/systemd/system/bluetooth.service
ExecStart=/usr/local/libexec/bluetooth/bluetoothd --experimental
Из-за неверной инициализации адаптеров BT5.+ в Bluez, перед запуском Home Assistant необходимо переключить BT адаптер на работу в режим Bluetoch 5.0:
hcitool -i hci1 cmd 08 31 03 05 05
или во всех режимах PHY 1M/2M/Coded:
hcitool -i hci1 cmd 08 31 03 07 07
Номер hciN - свой.
Проверить переключение возможно в btmon (log btmon):
@ RAW Open: hcitool (privileged) version 2.22
< HCI Command: LE Set Default PHY (0x08|0x0031) plen 3
All PHYs preference: 0x03
No TX PHY preference
No RX PHY preference
TX PHYs preference: 0x07
LE 1M
LE 2M
LE Coded
RX PHYs preference: 0x07
LE 1M
LE 2M
LE Coded
> HCI Event: Command Complete (0x0e) plen 4
LE Set Default PHY (0x08|0x0031) ncmd 2
Status: Success (0x00)
В итоге, в интеграции "BTHome" получаем успешный прием термометров со стандартной рекламой и работающих в LE Long Range:
Если адаптер будет работать неустойчиво, тогда HA может его переинициализировать и настройка на работу в Coded PHY (Long Range) собьется. Ожидать официальной поддержки в интеграции “Bluetooth” нет никакой возможности. Выбранный автором API “Bleak” не позволяет управлять PHY адаптера и не предвидится никакой поддержки BLUETOOTH SPECIFICATION Version 5.0 от 2016 года.
BLUETOOTH SPECIFICATION Version 5.0 | Vol 1, Part C page 291
Core Specification Change History
9 CHANGES FROM v4.2 TO 5.0
9.1 NEW FEATURES
Several new features are introduced in the Bluetooth Core Specification 5.0
Release. The major areas of improvement are:
• Slot Availability Mask (SAM)
• 2 Msym/s PHY for LE
• LE Long Range
• High Duty Cycle Non-Connectable Advertising
• LE Advertising Extensions
• LE Channel Selection Algorithm #2
Проверить адаптер на совместимость возможно с помощью команд:
# 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:00:E7:EA ACL MTU: 1021:6 SCO MTU: 255:12
UP RUNNING
RX bytes:6245694 acl:0 sco:0 events:46360 errors:0
TX bytes:33016 acl:0 sco:0 commands:222 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: PERIPHERAL ACCEPT
Name: 'nanopi-r5s'
Class: 0x400000
Service Classes: Telephony
Device Class: Miscellaneous,
HCI Version: (0xd) Revision: 0xddd5
LMP Version: (0xd) Subversion: 0xc761
Manufacturer: Realtek Semiconductor Corporation (93)
Установка вариантов PHY в btmgmt работает не совсем корректно (в некоторых вариантах имеются ошибки). Но и с помощью этой программы возможно установить необходимые PHY.
Для этого необходимо:
- Вывести текущие установки PHY:
# btmgmt -i 1 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 LE1MTX LE1MRX
- К вариантам 'Selected phys' добавить опции ‘LECODEDTX’ и ‘LECODEDRX’:
# btmgmt -i 1 phy BR1M1SLOT BR1M3SLOT BR1M5SLOT EDR2M1SLOT EDR2M3SLOT EDR2M5SLOT EDR3M1SLOT EDR3M3SLOT EDR3M5SLOT LE1MTX LE1MRX LECODEDTX LECODEDRX
PHY Configuration successfully set
Для установки PHY через API в bluez смотреть /doc/mgmt-api.txt.
Set PHY Configuration Command
=============================
Command Code: 0x0045
Controller Index: <controller id>
Command Parameters: Selected_PHYs (4 Octet)
Return Parameters:
This command is used to set the default PHY to the controller.
This will be stored and used for all the subsequent scanning
and connection initiation.
The list of supported PHYs can be retrieved via the
Get PHY Configuration command. Selecting unsupported or
deselecting default PHYs will result in an Invalid Parameter
error.
This can be called at any point to change the Selected PHYs.
Refer Get PHY Configuration command for PHYs parameter.
This command generates a Command Complete event on success
or a Command Status event on failure.
Possible errors: Invalid Parameters
Invalid Index
Или через hci_send_cmd(). Пример для Python (неполный и не совсем корректный):
import os
import sys
import struct
import bluetooth._bluetooth as _bt
OGF_LE_CTL = 0x08
OCF_SET_DEFAULT_PHY = 0x0031
def set_hci_phy(hci_sock, phy):
# save current filter
old_filter = hci_sock.getsockopt(_bt.SOL_HCI, _bt.HCI_FILTER, 14)
# Setup socket filter to receive only events related to the
# write_inquiry_mode command
flt = _bt.hci_filter_new()
_bt.hci_filter_set_ptype(flt, _bt.HCI_EVENT_PKT)
_bt.hci_filter_set_event(flt, _bt.EVT_CMD_COMPLETE);
_bt.hci_filter_set_opcode(flt, _bt.cmd_opcode_pack(OGF_LE_CTL, OCF_SET_DEFAULT_PHY))
hci_sock.setsockopt( _bt.SOL_HCI, _bt.HCI_FILTER, flt )
#< HCI Command: ogf 0x08, ocf 0x0031, plen 3 [ 03 05 05 ]
_bt.hci_send_cmd(hci_sock, OGF_LE_CTL, OCF_SET_DEFAULT_PHY, phy)
#> HCI Event: 0x0e plen 4 02 31 20 00
pkt = hci_sock.recv(255)
status = struct.unpack("xxxxxxB", pkt)[0]
print(status)
# restore old filter
hci_sock.setsockopt( _bt.SOL_HCI, _bt.HCI_FILTER, old_filter )
return status
if __name__ == "__main__":
dev_id = 1
hci_sock = _bt.hci_open_dev(dev_id)
status = set_hci_phy(hci_sock, struct.pack("<BBB", 3, 5, 5))
_bt.hci_close_dev(dev_id)