Search code examples
linuxshellbluetoothraspberry-piexpect

Parse multiple lines in tcl/expect


I'm doing a expect script that executes the bluetoothctl to read some ble devices that are around.

For this i've write the next script:

#!/usr/bin/expect
send_user "\nStarting scanning\n\r"
spawn bluetoothctl
expect -re "#"
expect "Agent registered"
send_user "\nConfiguring scan filter\n\r"
send "menu scan\r"
expect -re "#"
send "uuids 0x1802\r"
expect -re "#"
send "back\r"
expect -re "#"
send_user "\nScanning devices\n\r"
send "scan on\r"
sleep 10
send "devices\r"
expect -re {Device ([0-9A-F:]+)*} {
    expect -re "#"
    set devices $expect_out(1,string)
}
puts "Devices = $devices"
foreach device $devices {
    send "info $device\r"
    expect -re {UUID: Vendor specific           ([0-9A-F-]+)*} {
        expect -re "#"
        set uuid $expect_out(1,string)
    }
    puts "UUID obtained: $uuid"
}

When I execute it i have 2 errors:

ERROR 1 - Multiple returned lines. If the command send "devices\r" returns 2 or more lines I only can read the first returned but i have to save all:

[bluetooth]# devices
Device 4F:BF:9A:F6:77:32 4F-BF-9A-F6-77-32
Device 04:D1:3A:D7:71:5E Redmi
[bluetooth]# Devices = 4F:BF:9A:F6:77:32

ERROR 2 - In the foreach (for each device obtained) I need to parse de info command output to obtaind the UUID of the line "UUID: Vendor specific":

[bluetooth]# info 4F:BF:9A:F6:77:32
Device 4F:BF:9A:F6:77:32 (random)
    Alias: 4F-BF-9A-F6-77-32
    Paired: no
    Trusted: no
    Blocked: no
    Connected: no
    LegacyPairing: no
    UUID: Immediate Alert           (00001802-0000-1000-8000-00805f9b34fb)
    UUID: Vendor specific           (0a4dadab-66d6-42b7-8d01-bc43b618b6aa)

I have to obtain only the next string "0a4dadab-66d6-42b7-8d01-bc43b618b6aa" but i can't reach the solution...

I must save all the UUID (for all the devices obtained in scan) to an array to return them to the parent script.

Someone can help me with this problems?

Thank you!


Solution

  • I don't believe that bluetoothctl was intended to be used in this way. The BlueZ developers are always changing bluetoothctl which will break your script if you get it working.

    The better way to do this is use the D-Bus API that BlueZ provide

    https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/adapter-api.txt

    https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/device-api.txt

    To do the you will need to know:

    1. The BlueZ service is 'org.bluez'
    2. The adapter device has the D-Bus object path of '/org/bluez/hci0' typically
    3. The DBus interface for the adapter is 'org.bluez.Adapter1'