FTLab Wireless Smart Geiger — Part 2

Previous post:

With no app to talk to the FTLab Wireless Smart Geiger BSG-001, let’s see if we can manually talk to it from Linux.

Bluetooth

The device is a BLE (Bluetooth Low Energy) connected radiation detector.

So let’s start by installing BlueZ and starting it:

$ sudo apt install bluez
$ sudo systemctl enable --now bluetooth

Check if Bluetooth is turned on:

$ bluetoothctl show | grep -E 'Powered|Name'
        Name: xxx
        Powered: yes
$ rfkill list bluetooth
2: hci0: Bluetooth
        Soft blocked: no
        Hard blocked: no

Find the device

$ bluetoothctl --timeout 10 scan on
Discovery started
[CHG] Controller AC:45:EF:XX:XX:XX Discovering: yes
[NEW] Device 61:F9:F2:XX:XX:XX 61-F9-F2-XX-XX-XX
[NEW] Device B8:2D:28:XX:XX:XX Bouygtel4K
[NEW] Device 53:E2:64:XX:XX:XX 53-E2-64-XX-XX-XX
[NEW] Device DC:97:58:XX:XX:XX MiTV-XXXXX
[NEW] Device 3E:32:E2:XX:XX:XX 3E-32-E2-XX-XX-XX
[NEW] Device F4:C2:33:XX:XX:XX XXXXXXXXXXXXXX
[NEW] Device 50:32:37:XX:XX:XX 50-32-37-XX-XX-XX
[NEW] Device D4:EA:38:XX:XX:XX BLE_Gamma:XXXX
[NEW] Device 47:8F:E5:XX:XX:XX 47-8F-E5-XX-XX-XX
[NEW] Device 90:DD:5D:XX:XX:XX 90-DD-5D-XX-XX-XX

That’s the one named “BLE_Gamma:XXXX”. Quickly after the previous command, run the following one, while the information is still in the cache:

$ bluetoothctl info D4:EA:38:XX:XX:XX
Device D4:EA:38:XX:XX:XX (random)
        Name: BLE_Gamma:XXXX
        Alias: BLE_Gamma:XXXX
        Paired: no
        Bonded: no
        Trusted: no
        Blocked: no
        Connected: no
        LegacyPairing: no
        UUID: Unknown                   (00001523-0000-1000-8000-00805f9b34fb)
        UUID: Vendor specific           (00001523-1212-EFDE-1523-785FEABCD123)

Here, what we learn is that:

That “LED button service” makes me think that FTLab reused an SDK example to develop the BSG-001 firmware, keeping the same UUID base but doing their own implementation. Which in turn makes me think that the firmware will probably not follow standards and will probably contain bugs. Just a regular ship PoC to prod antipattern.

This device can’t be paired: trying to do so on Linux does nothing.

List the services

Note that in this post, I use gatttool which is now deprecated in BlueZ. bluetoothctl replaces it: it’s an interactive CLI where you connect to the device first, then send the commands (menu gatt, select-attribute, read, write, notify on).

$ gatttool -t random -b D4:EA:38:XX:XX:XX --primary
attr handle = 0x0001, end grp handle = 0x0007 uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle = 0x0008, end grp handle = 0x0008 uuid: 00001801-0000-1000-8000-00805f9b34fb
attr handle = 0x0009, end grp handle = 0x0011 uuid: 00001523-1212-efde-1523-785feabcd123
attr handle = 0x0012, end grp handle = 0xffff uuid: 0000180a-0000-1000-8000-00805f9b34fb

So according to the official list of services provided by the Bluetooth SIG:

Let’s dig a bit more:

$ gatttool -t random -b D4:EA:38:XX:XX:XX --characteristics
handle = 0x0002, char properties = 0x0a, char value handle = 0x0003, uuid = 00002a00-0000-1000-8000-00805f9b34fb
handle = 0x0004, char properties = 0x02, char value handle = 0x0005, uuid = 00002a01-0000-1000-8000-00805f9b34fb
handle = 0x0006, char properties = 0x02, char value handle = 0x0007, uuid = 00002a04-0000-1000-8000-00805f9b34fb
handle = 0x000a, char properties = 0x0a, char value handle = 0x000b, uuid = 00001524-1212-efde-1523-785feabcd123
handle = 0x000c, char properties = 0x12, char value handle = 0x000d, uuid = 00001525-1212-efde-1523-785feabcd123
handle = 0x000f, char properties = 0x12, char value handle = 0x0010, uuid = 00001526-1212-efde-1523-785feabcd123
handle = 0x0013, char properties = 0x02, char value handle = 0x0014, uuid = 00002a29-0000-1000-8000-00805f9b34fb

The char properties meaning:

bitmeaning
0x02read
0x04write without response
0x08write
0x10notify
0x20indicate

So:

And with the official list of characteristic UUIDs:

Value handleUUIDPropertiesDescriptionValue (if readable)
0x00032a00read, writeDevice NameBLE_Gamma:XXXX
0x00052a01readAppearance0x0000 = “unknown”
0x00072a04readPeripheral Preferred Connection Parameters06 00 90 01 00 00 90 01 (see below)
0x000b1524read, writeVendor specific
0x000d1525read, notifyVendor specific
0x00101526read, notifyVendor specific
0x00142a29readManufacturer Name StringFTLAB

To read the value of a characteristic, use the gatttool command with the --char-read option and xxd if the raw value needs to be decoded to ASCII. For example:

$ gatttool -t random -b D4:EA:38:XX:XX:XX --char-read -a 0x0014
Characteristic value/descriptor: 46 54 4c 41 42
$ echo "46 54 4c 41 42" | xxd -r -p; echo
FTLAB

For “Peripheral Preferred Connection Parameters”, according to LL_CONNECTION_PARAM_REQ:

The minimum interval is the lowest this legacy format allows (7.5 ms) and the maximum is 500 ms. It’s a wide range, so the device basically lets the phone decide.

The phone app reports the battery level, so why isn’t it exposed using the standard battery level characteristic (2a19)?

More and more things hinting that the firmware was a PoC.

Try the device name characteristic

$ A=D4:EA:38:XX:XX:XX
# Write a new name (ASCII "BLE_Gamma:TEST" in hex):
$ gatttool -t random -b $A --char-write-req -a 0x0003 -n $(printf 'BLE_Gamma:TEST' | xxd -p)
Characteristic value was written successfully
# Read it back:
$ gatttool -t random -b $A --char-read -a 0x0003 | sed 's/.*: //' | xxd -r -p; echo
BLE_Gamma:TEST
# So that was written properly.
# Let’s see if the advertised name has been updated too (remove it first to be sure to not get a cached version):
$ bluetoothctl remove $A
$ bluetoothctl --timeout 10 scan on
Discovery started
[CHG] Controller AC:45:EF:XX:XX:XX Discovering: yes
[NEW] Device D4:EA:38:XX:XX:XX BLE_Gamma:XXXX
# It hasn’t 🫤.
# Reboot the device, then re-read the value:
$ gatttool -t random -b $A --char-read -a 0x0003 | sed 's/.*: //' | xxd -r -p; echo
BLE_Gamma:XXXX
# So the write was not persisted.
# Re-check advertised name:
$ bluetoothctl --timeout 10 scan on
Discovery started
[CHG] Controller AC:45:EF:XX:XX:XX Discovering: yes
[NEW] Device D4:EA:38:XX:XX:XX BLE_Gamma:XXXX
# Same

The device name is writable but mostly ignored… a bit pointless. It should have been marked as read-only then, but I guess that was a copy/paste from Nordic’s example. So the iOS/Android apps probably use a vendor characteristic (that 1524 writable one).

Should we try to poke around 1524 next?

Comments Add one by emailing me.