Add support for Bluetooth pairing during thing setup

This commit is contained in:
Michael Zanetti 2023-11-23 23:08:04 +01:00
parent b868035bf5
commit cc26006a83
14 changed files with 402 additions and 17 deletions

View File

@ -50,7 +50,7 @@ BluetoothDiscoveryReplyImplementation::BluetoothDiscoveryReplyError BluetoothDis
return m_error;
}
QList<QBluetoothDeviceInfo> BluetoothDiscoveryReplyImplementation::discoveredDevices() const
QList<QPair<QBluetoothDeviceInfo, QBluetoothHostInfo>> BluetoothDiscoveryReplyImplementation::discoveredDevices() const
{
return m_discoveredDevices;
}
@ -63,14 +63,14 @@ void BluetoothDiscoveryReplyImplementation::setError(const BluetoothDiscoveryRep
}
}
void BluetoothDiscoveryReplyImplementation::setDiscoveredDevices(const QList<QBluetoothDeviceInfo> &discoveredDevices)
void BluetoothDiscoveryReplyImplementation::setDiscoveredDevices(const QList<QPair<QBluetoothDeviceInfo, QBluetoothHostInfo>> &discoveredDevices)
{
m_discoveredDevices = discoveredDevices;
}
void BluetoothDiscoveryReplyImplementation::addDiscoveredDevice(const QBluetoothDeviceInfo &info)
void BluetoothDiscoveryReplyImplementation::addDiscoveredDevice(const QBluetoothDeviceInfo &info, const QBluetoothHostInfo &hostInfo)
{
m_discoveredDevices.append(info);
m_discoveredDevices.append(qMakePair<QBluetoothDeviceInfo, QBluetoothHostInfo>(info, hostInfo));
}
void BluetoothDiscoveryReplyImplementation::setFinished()

View File

@ -33,6 +33,7 @@
#include <QObject>
#include <QBluetoothDeviceInfo>
#include <QBluetoothLocalDevice>
#include "hardware/bluetoothlowenergy/bluetoothdiscoveryreply.h"
@ -49,16 +50,16 @@ public:
bool isFinished() const override;
BluetoothDiscoveryReplyError error() const override;
QList<QBluetoothDeviceInfo> discoveredDevices() const override;
QList<QPair<QBluetoothDeviceInfo, QBluetoothHostInfo> > discoveredDevices() const override;
private:
bool m_finished = false;
BluetoothDiscoveryReplyError m_error = BluetoothDiscoveryReplyErrorNoError;
QList<QBluetoothDeviceInfo> m_discoveredDevices;
QList<QPair<QBluetoothDeviceInfo, QBluetoothHostInfo>> m_discoveredDevices;
void setError(const BluetoothDiscoveryReplyError &error);
void setDiscoveredDevices(const QList<QBluetoothDeviceInfo> &discoveredDevices);
void addDiscoveredDevice(const QBluetoothDeviceInfo &info);
void setDiscoveredDevices(const QList<QPair<QBluetoothDeviceInfo, QBluetoothHostInfo> > &discoveredDevices);
void addDiscoveredDevice(const QBluetoothDeviceInfo &info, const QBluetoothHostInfo &hostInfo);
void setFinished();
};

View File

@ -30,10 +30,13 @@
#include "bluetoothlowenergymanagerimplementation.h"
#include "loggingcategories.h"
#include "nymeabluetoothagent.h"
#include "bluetoothpairingjobimplementation.h"
#include <QDBusConnection>
#include <QDBusConnectionInterface>
#include <QDBusReply>
#include <QDBusInterface>
namespace nymeaserver {
@ -54,8 +57,10 @@ BluetoothLowEnergyManagerImplementation::BluetoothLowEnergyManagerImplementation
return;
}
m_agent = new NymeaBluetoothAgent(this);
foreach (const QBluetoothHostInfo &hostInfo, QBluetoothLocalDevice::allDevices()) {
qCDebug(dcBluetooth()) << "Enalbing bluetooth adapter:" << hostInfo.name() << hostInfo.address().toString();
qCDebug(dcBluetooth()) << "Enabling bluetooth adapter:" << hostInfo.name() << hostInfo.address().toString();
QBluetoothLocalDevice localDevice(hostInfo.address());
localDevice.powerOn();
localDevice.setHostMode(QBluetoothLocalDevice::HostDiscoverable);
@ -81,6 +86,13 @@ BluetoothDiscoveryReply *BluetoothLowEnergyManagerImplementation::discoverDevice
return reply;
}
if (QBluetoothLocalDevice::allDevices().isEmpty()) {
qCWarning(dcBluetooth()) << "No Bluetooth adapter available.";
reply->setError(BluetoothDiscoveryReplyImplementation::BluetoothDiscoveryReplyErrorNotAvailable);
reply->setFinished();
return reply;
}
// Create a scanner for each adapter
foreach (const QBluetoothHostInfo &hostInfo, QBluetoothLocalDevice::allDevices()) {
qCDebug(dcBluetooth()) << "Starting discovery on adapter:" << hostInfo.name() << hostInfo.address().toString();
@ -93,7 +105,7 @@ BluetoothDiscoveryReply *BluetoothLowEnergyManagerImplementation::discoverDevice
// Note: only show low energy devices
if (info.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration) {
qCDebug(dcBluetooth()) << "device discovered" << info.name() << info.address().toString();
reply->addDiscoveredDevice(info);
reply->addDiscoveredDevice(info, hostInfo);
}
});
connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished, reply, [=](){
@ -108,6 +120,53 @@ BluetoothDiscoveryReply *BluetoothLowEnergyManagerImplementation::discoverDevice
return reply;
}
BluetoothPairingJob *BluetoothLowEnergyManagerImplementation::pairDevice(const QBluetoothAddress &device, const QBluetoothAddress &adapter)
{
qCDebug(dcBluetooth()) << "pairDevice";
BluetoothPairingJobImplementation *job = new BluetoothPairingJobImplementation(m_agent, device, this);
QBluetoothLocalDevice *localDevice = nullptr;
if (adapter.isNull()) {
localDevice = new QBluetoothLocalDevice(this);
} else {
localDevice = new QBluetoothLocalDevice(adapter, this);
}
if (!localDevice->isValid()) {
qCWarning(dcBluetooth()) << "Local device" << adapter.toString() << "is not valid";
job->finish(false);
return job;
}
localDevice->requestPairing(device, QBluetoothLocalDevice::AuthorizedPaired);
connect(localDevice, &QBluetoothLocalDevice::error, job, [=](QBluetoothLocalDevice::Error error){
qCDebug(dcBluetooth()) << "Pairing error" << error;
job->finish(false);
localDevice->deleteLater();
});
connect(localDevice, &QBluetoothLocalDevice::pairingFinished, job, [=](const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing){
qCDebug(dcBluetooth()) << "Pairing finished" << address.toString() << pairing;
job->finish(true);
localDevice->deleteLater();
});
return job;
}
void BluetoothLowEnergyManagerImplementation::unpairDevice(const QBluetoothAddress &device, const QBluetoothAddress &adapter)
{
QBluetoothLocalDevice *localDevice = nullptr;
if (adapter.isNull()) {
localDevice = new QBluetoothLocalDevice(this);
} else {
localDevice = new QBluetoothLocalDevice(adapter, this);
}
if (!localDevice->isValid()) {
qCWarning(dcBluetooth()) << "Local device" << adapter.toString() << "is not valid";
return;
}
localDevice->requestPairing(device, QBluetoothLocalDevice::Unpaired);
}
BluetoothLowEnergyDevice *BluetoothLowEnergyManagerImplementation::registerDevice(const QBluetoothDeviceInfo &deviceInfo, const QLowEnergyController::RemoteAddressType &addressType)
{
QPointer<BluetoothLowEnergyDeviceImplementation> bluetoothDevice = new BluetoothLowEnergyDeviceImplementation(deviceInfo, addressType, this);

View File

@ -46,6 +46,8 @@
namespace nymeaserver {
class NymeaBluetoothAgent;
class BluetoothLowEnergyManagerImplementation : public BluetoothLowEnergyManager
{
Q_OBJECT
@ -58,13 +60,14 @@ public:
BluetoothDiscoveryReply *discoverDevices(int timeout = 5000) override;
// Bluetooth device registration methods
BluetoothPairingJob *pairDevice(const QBluetoothAddress &device, const QBluetoothAddress &adapter) override;
void unpairDevice(const QBluetoothAddress &device, const QBluetoothAddress &adapter) override;
BluetoothLowEnergyDevice *registerDevice(const QBluetoothDeviceInfo &deviceInfo, const QLowEnergyController::RemoteAddressType &addressType = QLowEnergyController::RandomAddress) override;
void unregisterDevice(BluetoothLowEnergyDevice *bluetoothDevice) override;
bool available() const override;
bool enabled() const override;
protected:
void setEnabled(bool enabled) override;
@ -78,8 +81,8 @@ private:
bool m_available = false;
bool m_enabled = false;
NymeaBluetoothAgent *m_agent = nullptr;
QPointer<BluetoothDiscoveryReplyImplementation> m_currentReply;
};

View File

@ -0,0 +1,52 @@
#include "bluetoothpairingjobimplementation.h"
#include "nymeabluetoothagent.h"
namespace nymeaserver
{
BluetoothPairingJobImplementation::BluetoothPairingJobImplementation(NymeaBluetoothAgent *agent, const QBluetoothAddress &address, QObject *parent)
: BluetoothPairingJob{address, parent},
m_agent{agent},
m_address{address}
{
connect(m_agent, &NymeaBluetoothAgent::passKeyRequested, this, [address, this](const QBluetoothAddress &addr){
if (address != addr) {
// Not for us...
return;
}
emit passKeyRequested();
});
connect(m_agent, &NymeaBluetoothAgent::displayPinCode, this, [address, this](const QBluetoothAddress &addr, const QString &pinCode){
if (address != addr) {
// Not for us...
return;
}
emit displayPinCode(pinCode);
});
}
bool BluetoothPairingJobImplementation::isFinished() const
{
return m_finished;
}
bool BluetoothPairingJobImplementation::success() const
{
return m_success;
}
void BluetoothPairingJobImplementation::passKeyEntered(const QString passKey)
{
m_agent->passKeyEntered(m_address, passKey);
}
void BluetoothPairingJobImplementation::finish(bool success)
{
m_finished = true;
m_success = success;
QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection, Q_ARG(bool, success));
}
}

View File

@ -0,0 +1,38 @@
#ifndef BLUETOOTHPAIRINGJOBIMPLEMENTATION_H
#define BLUETOOTHPAIRINGJOBIMPLEMENTATION_H
#include "hardware/bluetoothlowenergy/bluetoothlowenergymanager.h"
#include <QObject>
namespace nymeaserver
{
class NymeaBluetoothAgent;
class BluetoothLowEnergyManagerImplementation;
class BluetoothPairingJobImplementation : public BluetoothPairingJob
{
Q_OBJECT
public:
explicit BluetoothPairingJobImplementation(NymeaBluetoothAgent *agent, const QBluetoothAddress &address, QObject *parent = nullptr);
bool isFinished() const override;
bool success() const override;
void passKeyEntered(const QString passKey) override;
private:
friend BluetoothLowEnergyManagerImplementation;
void finish(bool success);
private:
bool m_finished = false;
bool m_success = false;
NymeaBluetoothAgent *m_agent = nullptr;
QBluetoothAddress m_address;
};
}
#endif // BLUETOOTHPAIRINGJOBIMPLEMENTATION_H

View File

@ -1,7 +1,146 @@
#include "nymeabluetoothagent.h"
#include <QDBusConnection>
#include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(dcBluetooth)
namespace nymeaserver
{
NymeaBluetoothAgentAdapter::NymeaBluetoothAgentAdapter(NymeaBluetoothAgent *agent, QObject *parent):
QObject{parent},
m_agent{agent}
{
}
QString NymeaBluetoothAgentAdapter::RequestPinCode(const QDBusObjectPath &device, const QDBusMessage &message)
{
qCDebug(dcBluetooth) << "RequestPinCode" << device.path() << message.arguments();
message.setDelayedReply(true);
m_agent->onRequestPassKey(device, message);
return 0;
}
void NymeaBluetoothAgentAdapter::DisplayPinCode(const QDBusObjectPath &device, const QString &pinCode)
{
qCDebug(dcBluetooth) << "DisplayPinCode" << device.path() << pinCode;
m_agent->onDisplayPinCode(device, pinCode);
}
quint32 NymeaBluetoothAgentAdapter::RequestPasskey(const QDBusObjectPath &device, const QDBusMessage &message)
{
qCDebug(dcBluetooth) << "RequestPasskey" << device.path() << message.arguments();
message.setDelayedReply(true);
m_agent->onRequestPassKey(device, message);
return 0;
}
void NymeaBluetoothAgentAdapter::DisplayPasskey(const QDBusObjectPath &device, quint32 passKey, quint16 entered)
{
qCDebug(dcBluetooth) << "DisplayPasskey" << device.path() << passKey << entered;
// Not using "entered" value which would update whenever the user enters a (wrong) pin on the other end...
m_agent->onDisplayPinCode(device, QString("%1").arg(passKey, 6, QChar('0')));
}
void NymeaBluetoothAgentAdapter::RequestConfirmation(const QDBusObjectPath &device, quint32 passKey, const QDBusMessage &message)
{
qCDebug(dcBluetooth) << "RequestConfirmation" << device.path() << passKey << message.arguments();
// TODO: Not implemented
qCWarning(dcBluetooth()) << "Request confirmation pairing mechanism is not implemented.";
}
void NymeaBluetoothAgentAdapter::RequestAuthorization(const QDBusObjectPath &device, const QDBusMessage &message)
{
qCDebug(dcBluetooth) << "RequestAuthorization" << device.path() << message.arguments();
// TODO: Not implemented
qCWarning(dcBluetooth()) << "RequestAuthorization mechanism is not implemented.";
}
void NymeaBluetoothAgentAdapter::AuthorizeService(const QDBusObjectPath &device, const QString &uuid, const QDBusMessage &message)
{
qCDebug(dcBluetooth) << "AuthorizeService" << device.path() << uuid << message.arguments();
// TODO: Not implemented
qCWarning(dcBluetooth()) << "AuthorizeService mechanism is not implemented.";
}
void NymeaBluetoothAgentAdapter::Cancel()
{
qCDebug(dcBluetooth()) << "Cancel called on bluetooth agent";
}
void NymeaBluetoothAgentAdapter::Release()
{
qCDebug(dcBluetooth()) << "Release called on bluetooth agent";
}
NymeaBluetoothAgent::NymeaBluetoothAgent(QObject *parent)
: QObject{parent}
{
m_adapter = new NymeaBluetoothAgentAdapter(this);
bool success = QDBusConnection::systemBus().registerObject("/nymea/bluetoothagent", m_adapter, QDBusConnection::ExportScriptableContents);
qCInfo(dcBluetooth) << "Registered Bluetooth pairing agent" << success;
QDBusMessage message = QDBusMessage::createMethodCall("org.bluez", "/org/bluez", "org.bluez.AgentManager1", "RegisterAgent");
message << QVariant::fromValue(QDBusObjectPath("/nymea/bluetoothagent"));
message << "KeyboardDisplay";
QDBusMessage registerReply = QDBusConnection::systemBus().call(message);
if (!registerReply.errorName().isEmpty()) {
qCWarning(dcBluetooth()) << "Error registering pairing agent:" << registerReply.errorMessage();
} else {
qCDebug(dcBluetooth()) << "Pairing agent registered.";
}
}
void NymeaBluetoothAgent::passKeyEntered(const QBluetoothAddress &address, const QString passKey)
{
if (!m_pendingPairings.contains(address.toString())) {
qCWarning(dcBluetooth()) << "No ongoing pairing process for" << address.toString();
return;
}
qCInfo(dcBluetooth()) << "Providing passkey to" << address.toString() << passKey;
QDBusMessage message = m_pendingPairings.take(address.toString());
message << static_cast<quint32>(passKey.toUInt());
QDBusConnection::systemBus().send(message);
}
QBluetoothAddress NymeaBluetoothAgent::deviceForPath(const QDBusObjectPath &path)
{
// qdbus --system org.bluez /org/bluez/hci0/dev_00_1A_22_0B_12_EB org.freedesktop.DBus.Properties.Get org.bluez.Device1 Address
QDBusMessage message = QDBusMessage::createMethodCall("org.bluez", path.path(), "org.freedesktop.DBus.Properties", "Get");
message << "org.bluez.Device1" << "Address";
QDBusMessage reply = QDBusConnection::systemBus().call(message);
if (!reply.errorName().isEmpty()) {
qCWarning(dcBluetooth()) << "Error reading Address property for" << path.path() << reply.errorMessage();
return QBluetoothAddress();
}
if (reply.arguments().count() != 1) {
qCWarning(dcBluetooth) << "Read property reply received an unexpected argument count";
return QBluetoothAddress();
}
return QBluetoothAddress(reply.arguments().at(0).value<QDBusVariant>().variant().toString());
}
void NymeaBluetoothAgent::onRequestPassKey(const QDBusObjectPath &path, const QDBusMessage &message)
{
QBluetoothAddress address = deviceForPath(path);
qCDebug(dcBluetooth()) << "RequestPassKey" << path.path() << address;
m_pendingPairings[address.toString()] = message.createReply();
emit passKeyRequested(address);
}
void NymeaBluetoothAgent::onDisplayPinCode(const QDBusObjectPath &path, const QString &pinCode)
{
QBluetoothAddress address = deviceForPath(path);
qCDebug(dcBluetooth()) << "RequestPassKey" << path.path() << address;
emit displayPinCode(address, pinCode);
}
}

View File

@ -2,15 +2,63 @@
#define NYMEABLUETOOTHAGENT_H
#include <QObject>
#include <QDBusObjectPath>
#include <QDBusMessage>
#include <QBluetoothAddress>
namespace nymeaserver
{
class NymeaBluetoothAgent;
class NymeaBluetoothAgentAdapter: public QObject
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.bluez.Agent1")
public:
explicit NymeaBluetoothAgentAdapter(NymeaBluetoothAgent *agent, QObject *parent = nullptr);
public slots:
Q_SCRIPTABLE QString RequestPinCode(const QDBusObjectPath &device, const QDBusMessage &message);
Q_SCRIPTABLE void DisplayPinCode(const QDBusObjectPath &device, const QString &pinCode);
Q_SCRIPTABLE quint32 RequestPasskey(const QDBusObjectPath &device, const QDBusMessage &message);
Q_SCRIPTABLE void DisplayPasskey(const QDBusObjectPath &device, quint32 passKey, quint16 entered);
Q_SCRIPTABLE void RequestConfirmation(const QDBusObjectPath &device, quint32 passKey, const QDBusMessage &message);
Q_SCRIPTABLE void RequestAuthorization(const QDBusObjectPath &device, const QDBusMessage &message);
Q_SCRIPTABLE void AuthorizeService(const QDBusObjectPath &device, const QString &uuid, const QDBusMessage &message);
Q_SCRIPTABLE void Cancel();
Q_SCRIPTABLE void Release();
private:
NymeaBluetoothAgent *m_agent = nullptr;
};
class NymeaBluetoothAgent : public QObject
{
Q_OBJECT
public:
explicit NymeaBluetoothAgent(QObject *parent = nullptr);
signals:
void passKeyEntered(const QBluetoothAddress &address, const QString passKey);
signals:
void passKeyRequested(const QBluetoothAddress &address);
void displayPinCode(const QBluetoothAddress &address, const QString &pinCode);
private:
friend class NymeaBluetoothAgentAdapter;
QBluetoothAddress deviceForPath(const QDBusObjectPath &path);
void onRequestPassKey(const QDBusObjectPath &path, const QDBusMessage &message);
void onDisplayPinCode(const QDBusObjectPath &path, const QString &pinCode);
NymeaBluetoothAgentAdapter *m_adapter = nullptr;
QHash<QString, QDBusMessage> m_pendingPairings;
};
}
#endif // NYMEABLUETOOTHAGENT_H

View File

@ -58,6 +58,7 @@ RESOURCES += $$top_srcdir/icons.qrc \
$$top_srcdir/data/debug-interface/debug-interface.qrc
HEADERS += nymeacore.h \
hardware/bluetoothlowenergy/bluetoothpairingjobimplementation.h \
hardware/bluetoothlowenergy/nymeabluetoothagent.h \
hardware/network/macaddressdatabasereplyimpl.h \
hardware/serialport/serialportmonitor.h \
@ -166,6 +167,7 @@ HEADERS += nymeacore.h \
SOURCES += nymeacore.cpp \
hardware/bluetoothlowenergy/bluetoothpairingjobimplementation.cpp \
hardware/bluetoothlowenergy/nymeabluetoothagent.cpp \
hardware/network/macaddressdatabasereplyimpl.cpp \
hardware/serialport/serialportmonitor.cpp \

View File

@ -33,6 +33,7 @@
#include <QObject>
#include <QBluetoothDeviceInfo>
#include <QBluetoothHostInfo>
#include "libnymea.h"
@ -54,7 +55,7 @@ public:
virtual bool isFinished() const = 0;
virtual BluetoothDiscoveryReplyError error() const = 0;
virtual QList<QBluetoothDeviceInfo> discoveredDevices() const = 0;
virtual QList<QPair<QBluetoothDeviceInfo, QBluetoothHostInfo>> discoveredDevices() const = 0;
signals:
void finished();

View File

@ -66,6 +66,7 @@ BluetoothLowEnergyManager::BluetoothLowEnergyManager(QObject *parent) :
{
}
/*! This method enables / disables this hardwareresource for all plugins. This method is available on the D-Bus. This can be useful if a Bluetooth LE server
needs access to the hardware. By disabling the bluetooth support, nymea will not allow to use the hardware until it gets reenabled.
*/
@ -73,3 +74,16 @@ void BluetoothLowEnergyManager::EnableBluetooth(bool enabled)
{
setEnabled(enabled);
}
BluetoothPairingJob::BluetoothPairingJob(const QBluetoothAddress &address, QObject *parent):
QObject(parent),
m_address(address)
{
}
QBluetoothAddress BluetoothPairingJob::address() const
{
return m_address;
}

View File

@ -45,6 +45,31 @@
#include "libnymea.h"
class NymeaBluetoothAgent;
class LIBNYMEA_EXPORT BluetoothPairingJob: public QObject
{
Q_OBJECT
public:
explicit BluetoothPairingJob(const QBluetoothAddress &address, QObject *parent = nullptr);
virtual ~BluetoothPairingJob() = default;
QBluetoothAddress address() const;
virtual bool isFinished() const = 0;
virtual bool success() const = 0;
virtual void passKeyEntered(const QString passKey) = 0;
signals:
void finished(bool success);
void passKeyRequested();
void displayPinCode(const QString &pinCode);
private:
QBluetoothAddress m_address;
};
class LIBNYMEA_EXPORT BluetoothLowEnergyManager : public HardwareResource
{
Q_OBJECT
@ -57,11 +82,14 @@ public:
virtual BluetoothDiscoveryReply *discoverDevices(int interval = 5000) = 0;
// Bluetooth device registration methods
virtual BluetoothPairingJob *pairDevice(const QBluetoothAddress &device, const QBluetoothAddress &adapter) = 0;
virtual void unpairDevice(const QBluetoothAddress &device, const QBluetoothAddress &adapter) = 0;
virtual BluetoothLowEnergyDevice *registerDevice(const QBluetoothDeviceInfo &deviceInfo, const QLowEnergyController::RemoteAddressType &addressType = QLowEnergyController::RandomAddress) = 0;
virtual void unregisterDevice(BluetoothLowEnergyDevice *bluetoothDevice) = 0;
public slots:
Q_SCRIPTABLE void EnableBluetooth(bool enabled);
};
#endif // BLUETOOTHLOWENERGYMANAGER_H

View File

@ -7,8 +7,8 @@ NYMEA_VERSION_STRING=$$system('dpkg-parsechangelog | sed -n -e "s/^Version: //p"
JSON_PROTOCOL_VERSION_MAJOR=8
JSON_PROTOCOL_VERSION_MINOR=0
JSON_PROTOCOL_VERSION="$${JSON_PROTOCOL_VERSION_MAJOR}.$${JSON_PROTOCOL_VERSION_MINOR}"
LIBNYMEA_API_VERSION_MAJOR=7
LIBNYMEA_API_VERSION_MINOR=4
LIBNYMEA_API_VERSION_MAJOR=8
LIBNYMEA_API_VERSION_MINOR=0
LIBNYMEA_API_VERSION_PATCH=0
LIBNYMEA_API_VERSION="$${LIBNYMEA_API_VERSION_MAJOR}.$${LIBNYMEA_API_VERSION_MINOR}.$${LIBNYMEA_API_VERSION_PATCH}"

View File

@ -14,7 +14,7 @@
#include <QLoggingCategory>
#include <QObject>
extern "C" const QString libnymea_api_version() { return QString("7.4.0");}
extern "C" const QString libnymea_api_version() { return QString("8.0.0");}
Q_DECLARE_LOGGING_CATEGORY(dcMock)
Q_LOGGING_CATEGORY(dcMock, "Mock")