Closed camm73 closed 3 years ago
What app are you using for connecting to the Raspberry Pi from your iPhone? Are you using the functionality in settings? As that will probably not work as the iPhone will not know what to do with the custom CPU Temperature Service.
I would recommend using a generic Bluetooth Low Energy scanning and exploration tool like nRF Connect to initially connect and prove it works.
I have found to get reliable connection to Android phones it is best to put the controller into le
only mode. This is done in the /etc/bluetooth/main.conf file
. Ensure that it contains the following:
ControllerMode = le
The following explanation of this is from /etc/bluetooth/main.conf
:
Restricts all controllers to the specified transport. Default value is "dual", i.e. both BR/EDR and LE enabled (when supported by the HW).` Possible values: "dual", "bredr", "le"
You can also do this from the command line with:
sudo btmgmt power off
sudo btmgmt le on
sudo btmgmt bredr off
sudo btmgmt power on
Thanks for the quick reply! So I've been testing this via a few apps including nRF Connect and still get a pairing request shortly after connecting to the BLE peripheral running on the Pi. This is also the case if I use non-Apple devices, so it doesn't seem to be client related.
What makes me think it is something related to a secure characteristic is that I modified Bluez running on the Pi so that the static bool change_security(struct bt_att_chan *chan, uint8_t ecode)
function found in https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/src/shared/att.c
always rejects automatic security level escalation (similar to the new config option that they added to the newest Bluez version), and this successfully stops pairing requests while allowing the peripheral to operate as expected.
This is a fine temporary fix, but I thought I'd share this in case it is a bug related to how bluezero is creating characteristics.
Thanks for the update although I am struggling to understand why you are seeing the issue.
Are you using a stock image on the Raspberry Pi? What version of Bluez do you have installed?
The code you linked to was changed a couple of years ago to add EATT support. This would seem to link to the 5.54 release:
http://www.bluez.org/release-of-bluez-5-54-and-5-53/ https://www.phoronix.com/scan.php?page=news_item&px=BlueZ-5.54-Released
I think the stock RPi OS is still shipping with 5.50. I've just done a full upgrade on one of my old RPi 3+ and it has 5.50 and is working fine.
So it's a stock Raspbian buster image (kernel version: 4.19.97-v71+) (haven't upgraded to RPi OS yet) with Bluez 5.50 running on a Raspberry Pi 4. However, I've also noticed this issue running on a Pi 3+ in the past.
I just double checked and it is actually an older 3B that I'm running on. There have been some firmware issues on the latest Raspberry Pi's. Have you checked service bluetooth status
for errors? Also journalctl -u bluetooth
.
Another thing to help debug is try running sudo btmon
in a different window to see what is reported there when you have the error. You can write the btmon output to a file and take it into wireshark. Sometime this helps filter the information.
I've included the full details of the machine I've run the test on.
pi@raspberry:~ $ cat /etc/os-release
PRETTY_NAME="Raspbian GNU/Linux 10 (buster)"
NAME="Raspbian GNU/Linux"
VERSION_ID="10"
VERSION="10 (buster)"
VERSION_CODENAME=buster
ID=raspbian
ID_LIKE=debian
HOME_URL="http://www.raspbian.org/"
SUPPORT_URL="http://www.raspbian.org/RaspbianForums"
BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"
pi@raspberry:~ $ uname -a
Linux SensePi 5.4.79-v7+ #1373 SMP Mon Nov 23 13:22:33 GMT 2020 armv7l GNU/Linux
pi@SensePi:~ $ dpkg -l | grep bluez
ii bluez 5.50-1.2~deb10u1+rpt2 armhf Bluetooth tools and daemons
ii bluez-firmware 1.2-4+rpt8 all Firmware for Bluetooth devices
ii bluez-obexd 5.50-1.2~deb10u1+rpt2 armhf bluez obex daemon
ii bluez-test-tools 5.50-1.2~deb10u1+rpt2 armhf test tools of bluez
pi@raspberry:~ $ pinout
,--------------------------------.
| oooooooooooooooooooo J8 +====
| 1ooooooooooooooooooo | USB
| +====
| Pi Model 3B V1.2 |
| +----+ +====
| |D| |SoC | | USB
| |S| | | +====
| |I| +----+ |
| |C| +======
| |S| | Net
| pwr |HDMI| |I||A| +======
`-| |--------| |----|V|-------'
Revision : a02082
SoC : BCM2837
RAM : 1024Mb
Storage : MicroSD
USB ports : 4 (excluding power)
Ethernet ports : 1
Wi-fi : True
Bluetooth : True
Camera ports (CSI) : 1
Display ports (DSI): 1
I just started playing around with BLE, this library and the Raspberry Pi and I find a similar (or the same?) issue:
Both the project cpu_temperature.py
or a modified version were I was playing around with characteristics and units (0x2A1C characteristic) behave the same way. Event completely removing the service (so just advertising data) seems to trigger "something" (not sure what) against the nRF Connect iOS which makes it respond with a:
> ACL Data RX: Handle 64 flags 0x02 dlen 9
ATT: Error Response (0x01) len 4
Read Request (0x0a)
Handle: 0x0016
Error: Insufficient Authentication (0x05)
, and then make the PI request authentication (which would fail if not set beforehand, of course)
I have borrowed an iPhone to do some testing. I ran btmon
while I connected, read the characteristic, started notify, and disconnected. I wrote the output to a file. i.e. sudo btmon -w cpu_ios.log
and then opened the output in wireshark
to do some packet analysis.
I am an inexperienced wireshark
user but it seems to be complaining about not being able to read the battery service: battery level
which is something not part of the custom CPU service of the example.
The error response does not prevent me from connecting to the CPU monitor service and reading the temperature value.
I did see different behaviour when I also had bluetoothctl
open as that would cause the pop-up on the iPhone and in bluetoothctl
. My assumption is that because there is an agent
registered it tries to get authentication for the battery service: battery level
I repeated the example with Android and can confirm that I don't see the issue reported with Android.
The next area of investigation is to understand why the iOS devices are asking for battery level information that is not part of the service being connected to. I suspect it is one of the other profiles that are available on the iOS devices
I'll try to find out, it is puzzling and I raised a ticket to the nFR Connect app as well. Thanks for the quick check, Barry.
@ukBaz For whatever it is worth, I am trying to use this library for Peripheral purposes and experiencing the same thing when connecting from an iOS device. It is only the following code:
# Create peripheral
cpu_monitor = peripheral.Peripheral(adapter_address, local_name='RPi')
# Add service
cpu_monitor.add_service(srv_id=1, uuid=SRVC, primary=True)
# Add characteristic
cpu_monitor.add_characteristic(srv_id=1, chr_id=1, uuid=COMMAND_CHRC,
value=[], notifying=False,
flags=['write', 'write-without-response'],
write_callback=write_value,
read_callback=None,
notify_callback=None)
# Publish peripheral and start event loop
cpu_monitor.publish()
And disabling br/edr, secure-conn, bondable all fail to make a difference. btmon seems to indicate that, as you noted, it requires pairing / authentication regardless:
< ACL Data TX: Handle 64 flags 0x00 dlen 7 #127 [hci0] 18.053612
ATT: Read Request (0x0a) len 2
Handle: 0x000c
> ACL Data RX: Handle 64 flags 0x02 dlen 9 #128 [hci0] 18.112663
ATT: Error Response (0x01) len 4
Read Request (0x0a)
Handle: 0x000c
Error: Insufficient Authentication (0x05)
< ACL Data TX: Handle 64 flags 0x00 dlen 6 #129 [hci0] 18.113607
SMP: Security Request (0x0b) len 1
Authentication requirement: Bonding, No MITM, Legacy, No Keypresses (0x01)
> HCI Event: Number of Completed Packets (0x13) plen 5 #130 [hci0] 18.114406
Num handles: 1
Handle: 64
Count: 2
> ACL Data RX: Handle 64 flags 0x02 dlen 11 #131 [hci0] 18.114428
ATT: Read By Type Request (0x08) len 6
Handle range: 0x0001-0x0005
Attribute type: Device Name (0x2a00)
> ACL Data RX: Handle 64 flags 0x02 dlen 11 #132 [hci0] 18.172625
SMP: Pairing Request (0x01) len 6
IO capability: KeyboardDisplay (0x04)
OOB data: Authentication data not present (0x00)
Authentication requirement: Bonding, No MITM, Legacy, No Keypresses (0x01)
Max encryption key size: 16
Initiator key distribution: EncKey IdKey (0x03)
Responder key distribution: EncKey IdKey (0x03)
@ MGMT Event: Authentication Failed (0x0011) plen 8 {0x0002} [hci0] 18.172761
LE Address: 5B:9B:23:6F:DF:EB (Resolvable)
Status: Authentication Failed (0x05)
@ MGMT Event: Authentication Failed (0x0011) plen 8 {0x0001} [hci0] 18.172761
LE Address: 5B:9B:23:6F:DF:EB (Resolvable)
Status: Authentication Failed (0x05)
< ACL Data TX: Handle 64 flags 0x00 dlen 6 #133 [hci0] 18.172854
SMP: Pairing Failed (0x05) len 1
Do you have any suggestions on how we might be able to workaround this at least in the meantime? In another issue, https://github.com/ukBaz/python-bluezero/issues/291 (which coincidentally I believe was running into this problem as well, but misunderstanding it) you mentioned that the example doesn't handle pairing, which implied that maybe there is a way to handle it via additional python code? Is that the case? We would prefer for our use case to not have to manually intervene and pair via bluetoothctl if possible.
Thanks!
Also, I'm not sure if this might be related or not, but I've also noticed that while the local_name worked / was used the very first time, ever since then I can't get it to work and the device name instead shows up as "raspberrypi". Is this a known issue / is there a way to get the local_name to show instead? If this is unrelated to the other issue let me know and I can open a separate issue if needed.
I usually set both name and alias. Not sure, but I think the name is considered ephemeral and doesn’t get linked to the mac addresses by the scanner (or most probably by the Bluez core).
My best guess on why the Battery Service is causing the pairing is one of the other profiles. If I list the default state of the Bluetooth on my RPi I get:
[bluetooth]# show
Controller B8:27:EB:22:57:E0 (public)
Name: SensePi
Alias: RPi_UART
Class: 0x000c0000
Powered: yes
Discoverable: yes
Pairable: yes
UUID: Headset AG (00001112-0000-1000-8000-00805f9b34fb)
UUID: Generic Attribute Profile (00001801-0000-1000-8000-00805f9b34fb)
UUID: A/V Remote Control (0000110e-0000-1000-8000-00805f9b34fb)
UUID: Generic Access Profile (00001800-0000-1000-8000-00805f9b34fb)
UUID: PnP Information (00001200-0000-1000-8000-00805f9b34fb)
UUID: A/V Remote Control Target (0000110c-0000-1000-8000-00805f9b34fb)
UUID: Audio Source (0000110a-0000-1000-8000-00805f9b34fb)
UUID: Audio Sink (0000110b-0000-1000-8000-00805f9b34fb)
UUID: Headset (00001108-0000-1000-8000-00805f9b34fb)
Modalias: usb:v1D6Bp0246d0532
Discovering: no
If I do a pulseaudio -k
it removes quite a few:
Controller B8:27:EB:22:57:E0 (public)
Name: SensePi
Alias: RPi_UART
Class: 0x00000000
Powered: yes
Discoverable: yes
Pairable: yes
UUID: Generic Attribute Profile (00001801-0000-1000-8000-00805f9b34fb)
UUID: A/V Remote Control (0000110e-0000-1000-8000-00805f9b34fb)
UUID: PnP Information (00001200-0000-1000-8000-00805f9b34fb)
UUID: A/V Remote Control Target (0000110c-0000-1000-8000-00805f9b34fb)
UUID: Generic Access Profile (00001800-0000-1000-8000-00805f9b34fb)
Modalias: usb:v1D6Bp0246d0532
Discovering: no
Some of the newer versions of audio gateway profiles have added indicator support to report such things as headset battery level.
I don't have access to an iOS device currently so if you can test that to see if it makes any difference.
With the local_name
, I wonder if this is linked to the underlying BlueZ API changing. This could be related to #333
@tnarik thanks for the tip - will try that.
One last update on my side for now; I think I was able to (temporarily?) workaround this pairing issue by adding one more btmgmt command to the list:
sudo btmgmt io-cap 3
I say temporarily because I believe this is representing it as "NoInputNoOutput" which I think is basically just a hack workaround for now. Let me know if there is anything else I can help with investigating here.
Thanks!
Thanks @ukBaz - will try that as well and see if it makes a difference. Will keep you all posted.
I didn’t try any of this yet ( https://stackoverflow.com/questions/59214524/since-bluez-5-48-iphones-require-pairing-when-connecting-on-a-ble-gap-periphera ) but I think the reason is the version of Bluez.
Thanks @tnarik . I remember reading about this on the BlueZ mailing list a few years ago. https://marc.info/?l=linux-bluetooth&m=152154683807490&w=2
It looks like modifying /lib/systemd/system/bluetooth.service to remove the unwanted plugins is the best way forward.
Just for a bit of completeness:
>bluetoothctl
[tnarikPhone]# info AA:AA:AA:BB:BB:BB
Device AA:AA:AA:BB:BB:BB(public)
Name: tnarikPhone
Alias: tnarikPhone
Appearance: 0x0040
Icon: phone
Paired: yes
Trusted: no
Blocked: no
Connected: yes
LegacyPairing: no
UUID: Generic Access Profile (00001800-0000-1000-8000-00805f9b34fb)
UUID: Generic Attribute Profile (00001801-0000-1000-8000-00805f9b34fb)
UUID: Current Time Service (00001805-0000-1000-8000-00805f9b34fb)
UUID: Device Information (0000180a-0000-1000-8000-00805f9b34fb)
UUID: Battery Service (0000180f-0000-1000-8000-00805f9b34fb)
UUID: Vendor specific (7905f431-b5ce-4e99-a40f-4b1e122d00d0)
UUID: Vendor specific (89d3502b-0f36-433a-8ef4-c502ad55f8dc)
UUID: Vendor specific (9fa480e0-4967-4542-9390-d343dc5d04ae)
UUID: Vendor specific (d0611e78-bbb4-4591-a5f8-487910ae4366)
So we can see UUID: Device Information (0000180a-0000-1000-8000-00805f9b34fb)
Then, on my RPi (called picake
):
1668:May 31 09:26:55 picake bluetoothd[4572]: src/plugin.c:plugin_init() Loading builtin plugins
1669:May 31 09:26:55 picake bluetoothd[4572]: src/plugin.c:add_plugin() Loading hostname plugin
1670:May 31 09:26:55 picake bluetoothd[4572]: src/plugin.c:add_plugin() Loading wiimote plugin
1671:May 31 09:26:55 picake bluetoothd[4572]: src/plugin.c:add_plugin() Loading autopair plugin
1672:May 31 09:26:55 picake bluetoothd[4572]: src/plugin.c:add_plugin() Loading policy plugin
1673:May 31 09:26:55 picake bluetoothd[4572]: src/plugin.c:add_plugin() Loading neard plugin
1674:May 31 09:26:55 picake bluetoothd[4572]: src/plugin.c:add_plugin() Loading sap plugin
1675:May 31 09:26:55 picake bluetoothd[4572]: src/plugin.c:add_plugin() Loading a2dp plugin
1676:May 31 09:26:55 picake bluetoothd[4572]: src/plugin.c:add_plugin() Loading avrcp plugin
1677:May 31 09:26:55 picake bluetoothd[4572]: src/plugin.c:add_plugin() Loading network plugin
1678:May 31 09:26:55 picake bluetoothd[4572]: src/plugin.c:add_plugin() Loading input plugin
1679:May 31 09:26:55 picake bluetoothd[4572]: src/plugin.c:add_plugin() Loading hog plugin
1680:May 31 09:26:55 picake bluetoothd[4572]: src/plugin.c:add_plugin() Loading health plugin
1681:May 31 09:26:55 picake bluetoothd[4572]: src/plugin.c:add_plugin() Loading gap plugin
1682:May 31 09:26:55 picake bluetoothd[4572]: src/plugin.c:add_plugin() Loading scanparam plugin
1683:May 31 09:26:55 picake bluetoothd[4572]: src/plugin.c:add_plugin() Loading deviceinfo plugin
1684:May 31 09:26:55 picake bluetoothd[4572]: src/plugin.c:add_plugin() Loading midi plugin
1685:May 31 09:26:55 picake bluetoothd[4572]: src/plugin.c:add_plugin() Loading battery plugin
The battery plugin is the one trying to get information from a Central (the iPhone), which triggers the reverse pairing (and also explains why my sample agent was prompting for input unexpectedly on the originator). The hostname plugin is the one that sets the name and alias (I think if it gets skipped, then the alias would be left alone by Bluez and there wouldn't be any need to overwrite).
Plugins can be disabled by either recompiling, or via the -P
flag in either the default configuration or a drop-in (what I did):
sudo mkdir -p /etc/systemd/system/bluetooth.service.d
sudo bash -c 'cat > /etc/systemd/system/bluetooth.service.d/bluetooth.conf <<EOF
[Service]
ExecStart=
ExecStart=/usr/lib/bluetooth/bluetoothd -P battery
EOF'
sudo systemctl daemon-reload
sudo systemctl restart bluetooth.service
(I was messing around with files and the service so I might have missed something here).
In my case, I can now see the picake
in the list of devices only while connected to the app, with no pairing requests, and disappearing when disconnecting.
You can also add -d
to the ExecStart to check what is being loaded.
PS: Just run the code on a PiZero and fixed it to run properly.
I think this has been resolved now so I'm going to go ahead and close it. Happy to re-open if it isn't resolved.
When running the cpu_temperature.py example, I try to connect to the BLE peripheral from my iPhone and upon connection I receive a pairing request. From looking at the cpu_temperature.py code, I do not see any secure characteristics which is why I'm confused why a pairing request would be generated. Is there something I'm missing here?
I've been running this example on a Raspberry Pi 4 Model B Rev 1.4 4GB. I've tested this on both the onboard Bluetooth module and a Plugable USB bluetooth dongle.
Upon looking at hcidump during this exchange I see the following "Insufficient Authentication" message followed by the pairing request due to the automatic security level upgrade: