python-bluezero icon indicating copy to clipboard operation
python-bluezero copied to clipboard

How to add Flags inside Advertising Data?

Open J0EK3R opened this issue 1 year ago • 7 comments

Thank you @ukBaz for your great work!

In my project I'm trying to send special BT-Advertising-Telegrams to control MouldKing Hubs.

My platform is a Raspberry 4.

I managed to send the required telegrams using the deprecated HCITool:

hcitool -i hci0 cmd 08 0008 3E 02 01 02 1b ff f0 ff 6D B6 43 CF 7E 8F 47 11 88 66 59 38 D1 7A AA 26 49 5E 13 14 15 16 17 18
hcitool -i hci0 cmd 0x08 0x0006 A0 00 A0 00 03 00 00 00 00 00 00 00 00 07 00
hcitool -i hci0 cmd 0x08 0x000a 01

This calls generate the following output - catched by wireshark Inside the "Advertising Data" are two bytes of "Flags", followed by the "Manufacturer Specific" data

Frame 2: 63 bytes on wire (504 bits), 63 bytes captured (504 bits) on interface COM3-4.2, id 0
nRF Sniffer for Bluetooth LE
Bluetooth Low Energy Link Layer
    Access Address: 0x8e89bed6
    Packet Header: 0x2502 (PDU Type: ADV_NONCONN_IND, TxAdd: Public)
    Advertising Address: RaspberryPiT_c2:62:00 (dc:a6:32:c2:62:00)
    Advertising Data
        Flags
            Length: 2
            Type: Flags (0x01)
            000. .... = Reserved: 0x0
            ...0 .... = Simultaneous LE and BR/EDR to Same Device Capable (Host): false (0x0)
            .... 0... = Simultaneous LE and BR/EDR to Same Device Capable (Controller): false (0x0)
            .... .0.. = BR/EDR Not Supported: false (0x0)
            .... ..1. = LE General Discoverable Mode: true (0x1)
            .... ...0 = LE Limited Discoverable Mode: false (0x0)
        Manufacturer Specific
            Length: 27
            Type: Manufacturer Specific (0xff)
            Company ID: Unknown (0xfff0)
            Data: 6db643cf7e8f471188665938d17aaa26495e131415161718
                [Expert Info (Note/Undecoded): Undecoded]
    CRC: 0x0a9130

I'm trying to reproduce the same BT-telegrams by modifying your example "manufacturer_data_beacon.py":

from bluezero import broadcaster

def main():
    alt = broadcaster.Beacon()
    alt.add_manufacturer_data(
        'fff0',  # Manufacturer ID
        b'\x6D\xB6\x43\xCF\x7E\x8F\x47\x11\x88\x66\x59\38\xD1\x7A\xAA\26\x5E\13\x14\x15\x16\x17\x18')

    alt.start_beacon()


if __name__ == '__main__':
    main()

Wireshark's output looks like this - very close to my requirements:

Frame 11872: 60 bytes on wire (480 bits), 60 bytes captured (480 bits) on interface COM3-4.2, id 0
nRF Sniffer for Bluetooth LE
Bluetooth Low Energy Link Layer
    Access Address: 0x8e89bed6
    Packet Header: 0x2200 (PDU Type: ADV_IND, ChSel: #1, TxAdd: Public)
    Advertising Address: RaspberryPiT_c2:62:00 (dc:a6:32:c2:62:00)
    Advertising Data
        Manufacturer Specific
            Length: 27
            Type: Manufacturer Specific (0xff)
            Company ID: Unknown (0xfff0)
            Data: 6db643cf7e8f47118866590338d17aaa165e0b1415161718
                [Expert Info (Note/Undecoded): Undecoded]
    CRC: 0xb3521a

Only the Flags are missing.

Could you please help me to add the missing Flags ? :)

J0EK3R avatar Jun 03 '24 08:06 J0EK3R

I'm not sure I have a good answer for you on this as it is about what BlueZ supports.

Depending what version of BlueZ you have on your RPi, there is the possibility to add more detail to advertisements using the data property but this is hidden behind the experimental flag and so Bluezero doesn't support it. More information at: https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/advertising-api.txt?h=5.65#n64

To access features hidden behind the experimental flag you have to restart bluetoothd with the --experimental command line flag.

If you wanted a command line option that was not deprecated then doing it with bluetoothctl or btmgmt should be possible.

For example:

$ sudo btmgmt add-adv -d 1bfff0ff6DB643CF7E8F471188665938D17AAA26495E131415161718  --general-discov 1
Instance added: 1

seems to be very close to what you are looking for.

To remove the advertisement you use:

$ sudo rm-adv 1

ukBaz avatar Jun 04 '24 08:06 ukBaz

Hi @ukBaz :) Thank you very much for your very quick response! :) I knew you're the right man to ask that stuff! ;)

I still tried to extend some examples for BlueZ for my needs - like adding the Discoverable property (wich adds Flags to the advertisement but behind the manufacturer specific data) and the usage of the Data property. ...but sadly without success.

Now I know why: I did not set the bluetoothd to experimental mode Aaaarggghh :( I'll give it a try with experimental mode set...

And I will add an advertiser-class using the btmgmt tool, thanks for your hint.

Another idea is - to prevent using commandline tools - to do the same as hciool or btmgmt internally do in python. What do you think - is that possible, does it make sense?

J0EK3R avatar Jun 04 '24 09:06 J0EK3R

You might want to take a look at: https://github.com/ukBaz/python-btsocket

I did some experiments to use the Bluez mgmt API. https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/mgmt-api.txt

ukBaz avatar Jun 04 '24 09:06 ukBaz

Thanks a lot - now I have a very good starting point...

J0EK3R avatar Jun 04 '24 14:06 J0EK3R

Hi @ukBaz :)

First I tried your suggestion with btmgmt tool

$ sudo btmgmt add-adv -d 1bfff0ff6DB643CF7E8F471188665938D17AAA26495E131415161718  --general-discov 1
Instance added: 1

and it works like a charm! ;)

I added and removed three instances of different advertisements with success.

Now I have the next problem: The rotation speed of the three advertised instances is to slow - it's about 2 seconds per advertisement (changing output from btmon). So my MouldKing hubs go into timeout. I guess, they need to receive an advertisement telegram every second minimum.

I think I have to set the add_ext_adv_params_options "min-internal" and "max-interval".

I looked everywhere how to set these parameters with btmgmt tool. Without success. Could you please help me to climb this little hill...? ;)

J0EK3R avatar Jun 07 '24 14:06 J0EK3R

looked everywhere how to set these parameters with btmgmt tool. Without success. Could you please help me to climb this little hill...? ;)

I think you are looking for the --duration <duration> and --timeout <timeout> options. Please note that the units are in seconds so I have never tried to go below 1 second.

The full help for the add-adv command can be read with the following:

$ btmgmt add-adv -h
Usage: add-adv [options] <instance_id>
Options:
	 -u, --uuid <uuid>         Service UUID
	 -d, --adv-data <data>     Advertising Data bytes
	 -s, --scan-rsp <data>     Scan Response Data bytes
	 -t, --timeout <timeout>   Timeout in seconds
	 -D, --duration <duration> Duration in seconds
	 -P, --phy <phy>           Phy type, Specify 1M/2M/CODED
	 -c, --connectable         "connectable" flag
	 -g, --general-discov      "general-discoverable" flag
	 -l, --limited-discov      "limited-discoverable" flag
	 -n, --scan-rsp-local-name "local-name" flag
	 -a, --scan-rsp-appearance "appearance" flag
	 -m, --managed-flags       "managed-flags" flag
	 -p, --tx-power            "tx-power" flag
e.g.:
	add-adv -u 180d -u 180f -d 080954657374204C45 1

ukBaz avatar Jun 09 '24 08:06 ukBaz

@ukBaz, dear Barry, it's very kind of you to help me with your quick responses. Thank you :)

$ btmgmt add-adv -h
Usage: add-adv [options] <instance_id>

OK, this will help me in the future! ;)

And I'll try out the timeout und duration options.

At the moment my code switches between the different advertisement in a loop by calling the btmgmt tool about 4 times the second...

J0EK3R avatar Jun 09 '24 15:06 J0EK3R