[Solved] Bluetooth list paired devices



  • Sorry for asking such a simple question, but I'm really stuck finding the answer in the documentation.

    How can get a list of paired devices without starting the long discovery process?



  • It seems that the Bluez libraries don't provide that functionality , which may be the cause why QtBluetooth also does not provide it. Searching the web I found out that there should be a DBUS service which provides the list. However, that service is not available in Ubuntu (and maybe also other Linux distributions).

    There is a command-line tool called "bt-device" in the package "bluez-utils" which provides exactly the list that I was searching for. So I use that as long there is no direct support in QtBluetooth.

    @
    QMap<QString,QString> LinuxRfComm::getKnownDevices() {
    QMap<QString,QString> result;

    // Run the external Bluetooth program. Example of the output:
    // HC-06 (20:13:11:15:16:08)
    QProcess command;
    command.start("bt-device -l");
    command.waitForFinished(3000);
    QByteArray output=command.readAllStandardOutput();
    
    // Split the result
    QRegExp regexp("(.*) \\((.*)\\)");
    foreach(QByteArray line, output.split('\n')) {
        if (regexp.indexIn(line)>=0) {
            result.insert(regexp.cap(2),regexp.cap(1));
        }
    }
    
    qDebug("Found %i devices",result.size());
    return result;
    

    }
    @



  • Android does also provide this list, but only in the Java API. We can call it from Qt this way:

    @
    QMap<QString,QString> AndroidRfComm::getKnownDevices() {
    QMap<QString,QString> result;
    QAndroidJniObject pairedDevicesSet=adapter.callObjectMethod("getBondedDevices","()Ljava/util/Set;"); // Set<BluetoothDevice>
    check("BluetoothAdapter.getBondedDevices()",pairedDevicesSet);
    jint size=pairedDevicesSet.callMethod<jint>("size");
    check("Set<BluetoothDevice>.size()");
    qDebug("Found %i paired devices",size);
    if (size>0) {
    QAndroidJniObject iterator=pairedDevicesSet.callObjectMethod("iterator","()Ljava/util/Iterator;"); // Iterator<BluetoothDevice>
    check("Set<BluetoothDevice>.iterator()",iterator);
    for (int i=0; i<size; i++) {
    QAndroidJniObject dev=iterator.callObjectMethod("next","()Ljava/lang/Object;"); // BluetoothDevice
    check("Iterator<BluetoothDevice>.next()",dev);
    QString address=dev.callObjectMethod("getAddress","()Ljava/lang/String;").toString();
    QString name=dev.callObjectMethod("getName","()Ljava/lang/String;").toString();
    result.insert(address,name);
    }
    }
    return result;
    }
    @



  • Hi

    I'd like to use your JNI method in order to find a paired device address from a tablet. The reason is that I cannot figure out how to RFCOMM connect from a Samsung tablet to a COM/bluetooth board (testing device simulating a BT server). Qt Doc example is straitforward but with a paired Galaxy Tab3 ST110 (and same on NEXUS 4):

    _socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol);
    _socket->connectToService(remoteService)
    gives socket error 8 (unsupported protocol) !!!

    Question 1/ Did I miss something in Qt docs ? maybe I had to prepare the remoteService data structure in some way ?

    Question 2/ Qt offers a second way to RFCOMM connect that use the Bluetooth remote address and a UUID. Hence I would like to determine the address of paired device from my tablet. I used JNI long ago so could you please tell me about the following details in your code example

    2a) is the variable adapter declaration should be
    QAndroidJniObject adapter("android/bluetooth/BluetoothAdapter");

    2b) what is the check() method ? some verification ? could it be removed ?

    Thanks
    J



  • QBluetoothSocket has another method to connect with address and UUID instead of a service object. You will need this because the Java Interface returns only the name and address of the device.

    Do it this way:

    QBluetoothAddress("20:13:11:15:16:08");
    QString uuid("00001101-0000-1000-8000-00805F9B34FB");
    QBluetoothSocket* socket=new QBluetoothSocket(); socket->connectToService(QBluetoothAddress(btAddress),QBluetoothUuid(uuid));

    Here is a complete working program using only JNI that might be helpful http://stefanfrings.de/android_qt/AndroidBluetooth.zip

    Or another program that combines JNI with the Qt Bluetooth library: http://stefanfrings.de/avr_io/ioModule.zip

    You need to know the correct UUID. I found it with Google. You could also scan for devices and check out what's stored in the service object. It should always contain the device address and either a UUID or a port number. For my cases it turned out that the UUID is more universal because all devices use the same but different port numbers.

    Some phones/tablets simply don't support RFCOMM protocol. You may try any RFCOMM application from the Play Store to verify that. I can recommend: https://play.google.com/store/apps/details?id=mobi.dzs.android.BluetoothSPP&hl=de (It recommends to upgrade but that newer version doesn't work on my phone).

    I see the example source from my previous post is incomplete, it does not tell how to get the "adapter" object. The check method checks for exceptions as documented in http://qt-project.org/doc/qt-5/qandroidjniobject.html in the chapter Handling Java Exceptions.

    Now this is a more complete example:
    @
    QStringList IoModule::getBluetoothDevices() {
    QStringList result;
    QString fmt("%1 %2");

    #ifdef Q_OS_ANDROID
        // Query via Android Java API.
        QAndroidJniObject adapter=QAndroidJniObject::callStaticObjectMethod("android/bluetooth/BluetoothAdapter","getDefaultAdapter","()Landroid/bluetooth/BluetoothAdapter;"); // returns a BluetoothAdapter
        if (checkException("BluetoothAdapter.getDefaultAdapter()",&adapter)) {
            return result;
        }
        QAndroidJniObject pairedDevicesSet=adapter.callObjectMethod("getBondedDevices","()Ljava/util/Set;"); // returns a Set<BluetoothDevice>
        if (checkException("BluetoothAdapter.getBondedDevices()",&pairedDevicesSet)) {
            return result;
        }
        jint size=pairedDevicesSet.callMethod<jint>("size");
        checkException("Set<BluetoothDevice>.size()");
        if (size>0) {
            QAndroidJniObject iterator=pairedDevicesSet.callObjectMethod("iterator","()Ljava/util/Iterator;"); // returns an Iterator<BluetoothDevice>
            if (checkException("Set<BluetoothDevice>.iterator()",&iterator)) {
                return result;
            }
            for (int i=0; i<size; i++) {
                QAndroidJniObject dev=iterator.callObjectMethod("next","()Ljava/lang/Object;"); // returns a BluetoothDevice
                if (checkException("Iterator<BluetoothDevice>.next()",&dev)) {
                    continue;
                }
                QString address=dev.callObjectMethod("getAddress","()Ljava/lang/String;").toString(); // returns a String
                QString name=dev.callObjectMethod("getName","()Ljava/lang/String;").toString(); // returns a String
                result.append(fmt.arg(address).arg(name));
            }
        }
    
    #elif defined Q_OS_LINUX
        // Query via the Linux command bt-device.
        QProcess command;
        command.start("bt-device -l");
        command.waitForFinished(3000);
        if (command.error()==QProcess::FailedToStart) {
            qWarning("Cannot execute the command 'bt-device': %s",qPrintable(command.errorString()));
        }
        else {
            // Parse the output, example: HC-06 (20:13:11:15:16:08)
            QByteArray output=command.readAllStandardOutput();
            QRegExp regexp("(.*) \\((.*)\\)");
            foreach(QByteArray line, output.split('\n')) {
                if (regexp.indexIn(line)>=0) {
                    result.append(fmt.arg(regexp.cap(2)).arg(regexp.cap(1)));
                }
            }
        }
    #endif
    
    return result;
    

    }

    #ifdef Q_OS_ANDROID
    bool IoModule::checkException(const char* method, const QAndroidJniObject* obj) {
    static QAndroidJniEnvironment env;
    bool result=false;
    if (env->ExceptionCheck()) {
    qCritical("Exception in %s",method);
    env->ExceptionDescribe();
    env->ExceptionClear();
    result=true;
    }
    if (!(obj==NULL || obj->isValid())) {
    qCritical("Invalid object returned by %s",method);
    result=true;
    }
    return result;
    }
    #endif
    @

    If there is still something missing, checkout my two example programs (from above).



  • Hi
    Thanks you very much: I have used your Qt/JNI/Java method for getting the remote address of my paired device and apply strategy 2. As a result
    1/ I (your code) was successfull for retrieving the correct remode address
    2/ With the connectToService(address, sppUuid) strategy the tablet seems to connect (see trace below)

    Not definitly sure that SPP protocol is fully implemented on SAMSUNG Galaxy Tab3 Lite, I have to check in and out data now and I will report to you.

    Something more to note: if my tablet (client) tries to connect to early after remote board (server) power up it can be in Qt that the socket Connected Signal fires as well as Socket error signal and that the trace indicates at the same time "Service Not Found". Perhaps the SDP protocol is establihsed after the socket server at the remote side...

    AGAIN : Thanks you very much for your help !

    J

    D/Qt ( 7868): ..\src\bttalker.cpp:83 (BtTalker::BtTalker(QObject*)): client socket prepared
    D/Qt ( 7868): ..\src\bttalker.cpp:129 (void BtTalker::startClient(const QBluetoothServiceInfo&)): local adapter host mode: 1
    D/Qt ( 7868): ..\src\bttalker.cpp:158 (void BtTalker::startClient(const QBluetoothServiceInfo&)): remote paired device:
    D/Qt ( 7868): ..\src\bttalker.cpp:162 (void BtTalker::startClient(const QBluetoothServiceInfo&)): try to connect to "00:06:66:46:86:00" / "{00001101-0000-1000-8000-00805f9b34fb}"
    D/Qt ( 7868): ..\src\bttalker.cpp:167 (void BtTalker::startClient(const QBluetoothServiceInfo&)): Socket connected to RFCOMM service


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.