I'm trying to build a Qt application for pairing / connecting bluetooth devices on a Linux device. I'm using the BlueZ API (https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc) over D-Bus as descibed in the BlueZ official site (http://www.bluez.org/page/8/).
The general procedure is described in here: https://www.kynetics.com/docs/2018/pairing_agents_bluez/
At the moment, I can use the APIs for pairing/connecting devices without problems.
BUT I cannot figure out how to use the pairing agent.
I'm trying to follow the direction pointed out here: How can i set the bluetooth pin number in linux C/C++
QDBusAbstractAdaptor object does not export implemented dbus interface
I searched a lot on the web and there are tons of code:
https://github.com/sdemario/qt-bluez-demos
https://github.com/KDE/bluez-qt
https://android.googlesource.com/platform/external/bluetooth/bluez/+/froyo-release/test/agent.c
https://github.com/pauloborges/bluez/blob/master/client/agent.c
https://www.linumiz.com/bluetooth-connectdevice-without-scanning/
but, still, I can't understand how this works. There are also a lot of scripts in python out there, but I'm working with C++.
My (pseudo)-code is the following:
agentManager = new QDBusInterface("org.bluez","/org/bluez","org.bluez.AgentManager1",QDBusConnection::systemBus(),this);
agent = new QDBusInterface("org.bluez","/org/bluez/agent","org.bluez.Agent1",QDBusConnection::systemBus(),this);
QDBusReply<void> reply;
reply = agentManager->call("RegisterAgent", QVariant::fromValue(QDBusObjectPath(path)), capability);
if (!reply.isValid()) {
qDebug() << reply.error().message() << reply.error().name();
}
reply = agentManager->call("RequestDefaultAgent", QVariant::fromValue(QDBusObjectPath(path)));
if (!reply.isValid()) {
qDebug() << reply.error().message() << reply.error().name();
}
QDBusReply<QString> reply_str = agent->call("RequestPinCode", QVariant::fromValue(QDBusObjectPath(path)));
if (reply_str.isValid()) {
pincode = reply_str.value();
} else {
qDebug() << reply_str.error().message() << reply.error().name();
}
The "RegisterAgent" and "RequestDefaultAgent" calls give a valid reply, while, the "RequestPinCode" gives an error:
"Method "RequestPinCode" with signature "o" on interface "org.bluez.Agent1" doesn't exist " "org.freedesktop.DBus.Error.UnknownObject"
Why? What I'm doing wrong?
Thanks
EDIT
I implemented a brand new service on D-Bus, which implements the org.bluez.Agent1 interface (at leat a part of it). Now, the code looks like this:
MyObject* myObject = new MyObject();
MyAdaptor* myAdaptor = new MyQDusAdaptor(myObject);
if (QDBusConnection::systemBus().registerService("org.test")) {
qDebug() << "registerService was Succesfull!";
} else {
qDebug() << "registerService was not Succesfull!";
}
if(QDBusConnection::systemBus().registerObject("/pairing/agent",myObject)){
qDebug() << "registerObject was Succesfull!";
} else {
qDebug() << "registerObject was not Succesfull!";
}
agentManager->RegisterAgent(QDBusObjectPath("/pairing/agent"),"NoInputNoOutput");
agentManager->RequestDefaultAgent(QDBusObjectPath("/pairing/agent"));
where the MyObject is
class MyObject : public QObject
{
Q_OBJECT
public:
MyObject();
public Q_SLOTS:
QString RequestPinCode(const QDBusObjectPath &in0);
};
MyObject::MyObject() {
}
QString MyObject::RequestPinCode(const QDBusObjectPath& in0)
{
qDebug() << "MyObject" << in0.path();
QString str = "2974";
return str;
}
and the adaptor is
class MyQDusAdaptor: public QDBusAbstractAdaptor
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.bluez.Agent1")
Q_CLASSINFO("D-Bus Introspection", ""
" <interface name=\"org.bluez.Agent1\">\n"
" <method name=\"RequestPinCode\">\n"
" <arg direction=\"in\" type=\"o\"/>\n"
" <arg direction=\"out\" type=\"s\"/>\n"
" </method>\n"
" </interface>\n"
"")
public:
MyQDusAdaptor(QObject *parent);
virtual ~MyQDusAdaptor();
public: // PROPERTIES
public Q_SLOTS: // METHODS
QString RequestPinCode(const QDBusObjectPath &in0);
};
MyQDusAdaptor::MyQDusAdaptor(QObject* parent) : QDBusAbstractAdaptor(parent) {
setAutoRelaySignals(true);
}
MyQDusAdaptor::~MyQDusAdaptor() {
}
QString MyQDusAdaptor::RequestPinCode(const QDBusObjectPath& in0)
{
qDebug() << "MyQDusAdaptor" << in0.path();
QString out0;
QMetaObject::invokeMethod(parent(), "RequestPinCode", Q_RETURN_ARG(QString, out0), Q_ARG(QDBusObjectPath, in0));
return out0;
}
When I try to pair a smartphone, the application freezes for ca 30s, I recieve the following error message:
"Did not receive a reply. Possible causes include: the remote application did not send a reply, the message bus security policy blocked the reply, the reply timeout expired, or the network connection was broken." "org.freedesktop.DBus.Error.NoReply"
and only after that the smartphone ask to insert a PIN.
I think that has to be done asynchronously. Any tips?