Reputation: 21
I am trying to use my computer to set up a BLE beacon and using a different computer to detect the advertisement. I am using the following bash script for the beacon set up:
#!/bin/bash
BLE="hci0"
sudo hciconfig $BLE down
sudo hciconfig $BLE up
sudo hciconfig $BLE noleadv
# Start LE advertising (non-connectable)
sudo hciconfig $BLE leadv 3
# Turn scanning off (can sometimes affect advertising)
sudo hciconfig $BLE noscan
# Set the Beacon advertisement data
sudo hcitool -i $BLE cmd 0x08 0x0008 1F 02 01 1A 1B FF 18 01 BE AC E2 0A 39 F4 73 F5 4B C4 A1 2F 17 D1 AD 07 A9 61 11 11 22 33 C5 01
#Set advertising parameters
sudo hcitool -i $BLE cmd 0x08 0x0006 A0 00 A0 00 03 00 00 00 00 00 00 00 00 07 00
#Enable advertising
sudo hcitool -i $BLE cmd 0x08 0x000a 01
This is patched together using earlier stack exchange answers (see e.g. Is there a way to increase BLE advertisement frequency in BlueZ?) and the Bluetooth Core Specification 4.0. According to my understanding, the second to last command should set the advertising interval to 100 ms.
This is the output I get:
< HCI Command: ogf 0x08, ocf 0x0008, plen 32
1F 02 01 1A 1B FF 18 01 BE AC E2 0A 39 F4 73 F5 4B C4 A1 2F
17 D1 AD 07 A9 61 11 11 22 33 C5 01
> HCI Event: 0x0e plen 4
01 08 20 00
< HCI Command: ogf 0x08, ocf 0x0006, plen 15
00 A0 00 A0 03 00 00 00 00 00 00 00 00 07 00
> HCI Event: 0x0e plen 4
01 06 20 12
< HCI Command: ogf 0x08, ocf 0x000a, plen 1
01
> HCI Event: 0x0e plen 4
02 0A 20 00
This sets the advertising data to the specified value, I have checked with btmon.
I am then, on the other computer using bluetoothctl to scan for advertisements using the following python script:
import datetime
import pexpect
import sys
#this is the mac address of the beacon
look_for_mac = "1C:1B:B5:77:54:10"
def scan_for_beacon(look_for_mac):
proc = pexpect.spawn('bluetoothctl', encoding='utf-8')
proc.expect(['bluetooth'])
proc.sendline('menu scan')
proc.sendline('duplicate-data on')
proc.sendline('back')
proc.sendline('scan on')
last_detection = None
while True:
try:
proc.expect('RSSI:', timeout=None) #look for advertisement signal strength
try:
mac = proc.before.split()[-1] #get mac address
if not mac == look_for_mac:
continue
except IndexError:
continue
proc.expect('\\n')
rest_of_line = proc.before.split()
#different versions of bluetoothctl uses a different formatting...
if len(rest_of_line) == 1:
RSSI = int(rest_of_line[0])
elif len(rest_of_line) == 2:
RSSI = rest_of_line[1].replace('(','')
RSSI = rest_of_line[1].replace(')','')
RSSI = int(RSSI)
#time from last advertisement
now = datetime.datetime.now()
try:
diff = now-last_detection
print(mac, RSSI, diff)
except TypeError:
pass
last_detection = now
sys.stdout.flush()
except KeyboardInterrupt: #bluetoothctl runs interactively, this avoids unnessecary error message when killing the process
print()
break
scan_for_beacon(look_for_mac)
I have tried using both computers as beacon and reader respectively, and they run different versions of ubuntu (24.10 and 18.04) with different versions of bluetoothctl (5.77 and 5.48).
Regardless of which computer plays which role, the above python script produces output along the lines of:
mac RSSI time_since_last_adv
5C:F3:70:9C:02:DF -57 0:00:01.280011
5C:F3:70:9C:02:DF -57 0:00:03.849041
5C:F3:70:9C:02:DF -55 0:00:01.291972
5C:F3:70:9C:02:DF -56 0:00:05.139566
5C:F3:70:9C:02:DF -56 0:00:03.859640
5C:F3:70:9C:02:DF -53 0:00:21.822894
5C:F3:70:9C:02:DF -54 0:00:02.564335
5C:F3:70:9C:02:DF -52 0:00:14.134638
5C:F3:70:9C:02:DF -73 0:00:06.430168
5C:F3:70:9C:02:DF -57 0:00:03.844756
5C:F3:70:9C:02:DF -67 0:00:02.565565
As you can see, the smallest time between any two advertisements is around 1.28 sec, which as I've understood it is some kind of default. Any larger difference seems to be approximately a multiple of 1.28. And thus comes my main question:
I also have some additional questions which are of less significance:
Sometimes I get a time difference slightly smaller than 1.28 sec, the smallest 1.207769 s. Why? Is it the computer that's not responsive enough to measure the difference accurately enough, or is there an inherent fluctuation in the advertisements accounting for this? It doesn't matter, I'm just curious. From what I understand fluctuations should be between the set interval and an up to 10 ms random delay.
From the Bluetooth Core Specification 4.0 I find that the first and second octet correspond to the Advertising_Interval_Min and the third and fourth to Advertising_Interval_Max. The first two octets in the command
sudo hcitool -i $BLE cmd 0x08 0x0006 A0 00 A0 00 03 00 00 00 00 00 00 00 00 07 00
are "A0 00". I would have thought this to mean 10*16^3*0.625ms = 25.6 sec (which is larger than the largest possible value according to the specs), but from several examples it is to be understood as 00A0 meaning 10*16*0.625ms = 0.100 sec. Why are these octets to be switched around? (I have tried both, neither changes the advertising interval).
Upvotes: 0
Views: 17