Skip to content
Advertisement

How do i get the debug/return strings out of bluethootctl

How can i retrieve those two lines:

Changing discoverable off succeeded [CHG] Controller 64:6E:69:F4:9E:72 Discoverable: no

Basically grabbing the output or other possible error outputs and discarding the rest of the garbage

enter image description here

I’m attempting to do a fork of a very simple bluethooth dmenu bash script, and I am being somewhat successful at it, but since I’ve considered releasing it to the public, it has to have error handling and be a generally rounded script, etc…

What im trying to now do is when i echo “power off” | bluethothctl i want to get the messages it sends internally like: Changing discoverable off succeeded, org.bluez.something is blocked, etc…

I’ve tried while read -r debug, putting it to a $( ) and then debugging it with notify or echo but i always get either the outside garbage(like Agent registered, [IFROGZ] discoverable off, etc..)

Is there a way i can grab those delicious internal message’s bluetoothctl sends internally to a variable without boogaloo tactics(like outputting everything to a file and then reading it)

I think what i said above is the only thing you hopefully solve this question for me but just because previously i’ve been downvoted for not showing code here’s a part of it

    finalArgs[inc++]=" "
    finalArgs[inc++]=$(echo show | _bluetoothctl | grep -m 1 "Powered:" | cut -c2- | sed -e "s/Powered/Power/")
    finalArgs[inc++]=$(echo show | _bluetoothctl | grep -m 1 "Discoverable:"| cut -c2-)
    finalArgs[inc++]=$(echo show | _bluetoothctl | awk "/Pairable:/{i++}i==2{print; exit}"| cut -c2-)
    name=$(printf '%sn' "${finalArgs[@]}" | dmenu -l ${#finalArgs[@]} -p "btmenu")
    [[ $name ]] || return
    mac=${name:format+2:-1}
    if [[ ${name:1:1} != " " ]]; then
        #avoiding a if here
        #echo $name
        #echo $name
        notify "Changing $name"
        mac=$(echo "$name" | sed -e "s/: yes/ off/")
        if [[ $mac =~ "$name" ]]; then 
            mac=$(echo "$name" | sed -e "s/: no/ on/")
        fi
        debug=$(echo ${mac,,} | _bluetoothctl)
        echo $debug 
        
        #notify $debug
        
        #notify ""
        exit 
    else
    (...)

whats weird is that i use the same tactic for getting the show elements but it doesnt work for those specific “debugging messages”

Advertisement

Answer

I am not sure that bluetoothctl was intended to be used in this way. BlueZ has a documented API that uses DBus bindings available for most languages at:

https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/

This can be done from the bash command line below:

pi@raspberry:~ $ busctl get-property org.bluez /org/bluez/hci0 org.bluez.Adapter1 Discoverable 
b false
pi@raspberry:~ $ busctl set-property org.bluez /org/bluez/hci0 org.bluez.Adapter1 Discoverable b true
pi@raspberry:~ $ busctl get-property org.bluez /org/bluez/hci0 org.bluez.Adapter1 Discoverable 
b true
pi@raspberry:~ $

This can also be done with language bindings. For example using pydbus in Python:

pi@raspberry:~ $ python3
Python 3.7.3 (default, Jul 25 2020, 13:03:44) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pydbus
>>> bus = pydbus.SystemBus()
>>> dongle = bus.get('org.bluez', '/org/bluez/hci0')
>>> dongle.Discoverable
True
>>> dongle.Discoverable = False
>>> dongle.Discoverable
False
>>> 

If you want to catch the changes then you need to connect into the event loop. For example:

from time import sleep
import pydbus
from gi.repository import GLib
bus = pydbus.SystemBus()
dongle = bus.get('org.bluez', '/org/bluez/hci0')

def print_change(iface, prop_changed, prop_removed):
    print('Adapter prop changed:', iface, prop_changed, prop_removed)

def toggle_discoverable(state):
    dongle.Discoverable = state


def toggle_power(state):
    dongle.Powered = state

dongle.onPropertiesChanged = print_change

mainloop = GLib.MainLoop()
GLib.timeout_add_seconds(3, toggle_discoverable, True)
GLib.timeout_add_seconds(5, toggle_discoverable, False)
GLib.timeout_add_seconds(8, toggle_power, False)
GLib.timeout_add_seconds(10, toggle_power, True)

try:
    mainloop.run()
except KeyboardInterrupt:
    mainloop.quit()

Which gives the output:

$ python3 print_bluez_change.py 
Adapter prop changed: org.bluez.Adapter1 {'Discoverable': True} []
Adapter prop changed: org.bluez.Adapter1 {'Discoverable': False} []
Adapter prop changed: org.bluez.Adapter1 {'Powered': False, 'Discovering': False, 'Class': 0} []
Adapter prop changed: org.bluez.Adapter1 {'Class': 4980736} []
Adapter prop changed: org.bluez.Adapter1 {'Powered': True} []
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement