nymea-plugins/nuki/bluez/bluetoothadapter.cpp

425 lines
12 KiB
C++

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "bluetoothadapter.h"
#include "blueztypes.h"
#include <QDBusPendingReply>
QString BluetoothAdapter::name() const
{
return m_name;
}
QString BluetoothAdapter::alias() const
{
return m_alias;
}
bool BluetoothAdapter::setAlias(const QString &alias)
{
if (!m_adapterInterface->isValid())
return false;
return m_adapterInterface->setProperty("Alias", QVariant(alias));
}
QString BluetoothAdapter::address() const
{
return m_address;
}
QString BluetoothAdapter::modalias() const
{
return m_modalias;
}
bool BluetoothAdapter::discovering() const
{
return m_discovering;
}
bool BluetoothAdapter::discoverable() const
{
return m_discoverable;
}
bool BluetoothAdapter::setDiscoverable(const bool &discoverable)
{
if (!m_adapterInterface->isValid())
return false;
return m_adapterInterface->setProperty("Discoverable", QVariant(discoverable));
}
uint BluetoothAdapter::discoverableTimeout() const
{
return m_discoverableTimeout;
}
bool BluetoothAdapter::setDiscoverableTimeout(const uint &seconds)
{
if (!m_adapterInterface->isValid())
return false;
return m_adapterInterface->setProperty("DiscoverableTimeout", QVariant(seconds));
}
bool BluetoothAdapter::pairable() const
{
return m_pairable;
}
bool BluetoothAdapter::setPairable(const bool &pairable)
{
if (!m_adapterInterface->isValid())
return false;
return m_adapterInterface->setProperty("Pairable", QVariant(pairable));
}
uint BluetoothAdapter::pairableTimeout() const
{
return m_pairableTimeout;
}
bool BluetoothAdapter::setPairableTimeout(const uint &seconds)
{
if (!m_adapterInterface->isValid())
return false;
return m_adapterInterface->setProperty("PairableTimeout", QVariant(seconds));
}
uint BluetoothAdapter::adapterClass() const
{
return m_adapterClass;
}
QString BluetoothAdapter::adapterClassString() const
{
QString adapterClassString;
switch (m_adapterClass) {
// TODO: get thing type from class
default:
break;
}
return adapterClassString;
}
bool BluetoothAdapter::powered() const
{
return m_powered;
}
bool BluetoothAdapter::setPower(const bool &power)
{
if (!m_adapterInterface->isValid())
return false;
return m_adapterInterface->setProperty("Powered", QVariant(power));
}
QStringList BluetoothAdapter::uuids() const
{
return m_uuids;
}
QList<BluetoothDevice *> BluetoothAdapter::devices() const
{
return m_devices;
}
bool BluetoothAdapter::hasDevice(const QBluetoothAddress &address)
{
foreach (BluetoothDevice *thing, m_devices) {
if (thing->address() == address) {
return true;
}
}
return false;
}
BluetoothDevice *BluetoothAdapter::getDevice(const QBluetoothAddress &address)
{
foreach (BluetoothDevice *thing, m_devices) {
if (thing->address() == address) {
return thing;
}
}
return nullptr;
}
bool BluetoothAdapter::removeDevice(const QBluetoothAddress &address)
{
foreach (BluetoothDevice *thing, m_devices) {
if (thing->address() == address) {
return removeDevice(thing->m_path);
}
}
return false;
}
bool BluetoothAdapter::isValid() const
{
return m_adapterInterface->isValid();
}
BluetoothAdapter::BluetoothAdapter(const QDBusObjectPath &path, const QVariantMap &properties, QObject *parent) :
QObject(parent),
m_path(path),
m_discovering(false),
m_discoverable(false),
m_discoverableTimeout(0),
m_pairable(false),
m_pairableTimeout(0),
m_adapterClass(0),
m_powered(false)
{
// Check DBus connection
if (!QDBusConnection::systemBus().isConnected()) {
qCWarning(dcBluez()) << "System DBus not connected.";
return;
}
m_adapterInterface = new QDBusInterface(orgBluez, m_path.path(), orgBluezAdapter1, QDBusConnection::systemBus(), this);
if (!m_adapterInterface->isValid()) {
qCWarning(dcBluez()) << "Invalid DBus adapter interface for" << m_path.path();
return;
}
QDBusConnection::systemBus().connect(orgBluez, m_path.path(), "org.freedesktop.DBus.Properties", "PropertiesChanged", this, SLOT(onPropertiesChanged(QString,QVariantMap,QStringList)));
processProperties(properties);
}
BluetoothAdapter::~BluetoothAdapter()
{
}
void BluetoothAdapter::processProperties(const QVariantMap &properties)
{
foreach (const QString &propertyName, properties.keys()) {
if (propertyName == "Name") {
m_name = properties.value(propertyName).toString();
} else if (propertyName == "Alias") {
setAliasInternally(properties.value(propertyName).toString());
} else if (propertyName == "Address") {
m_address = properties.value(propertyName).toString();
} else if (propertyName == "Modalias") {
m_modalias = properties.value(propertyName).toString();
} else if (propertyName == "Discovering") {
setDiscoveringInternally(properties.value(propertyName).toBool());
} else if (propertyName == "Discoverable") {
setDiscoverableInernally(properties.value(propertyName).toBool());
} else if (propertyName == "DiscoverableTimeout") {
setDiscoverableTimeoutInternally(properties.value(propertyName).toUInt());
} else if (propertyName == "Pairable") {
setPairableInternally(properties.value(propertyName).toBool());
} else if (propertyName == "PairableTimeout") {
setPairableTimeoutInternally(properties.value(propertyName).toUInt());
} else if (propertyName == "Class") {
m_adapterClass = properties.value(propertyName).toUInt();
} else if (propertyName == "Powered") {
setPoweredInternally(properties.value(propertyName).toBool());
} else if (propertyName == "UUIDs") {
m_uuids = properties.value(propertyName).toStringList();
}
}
}
void BluetoothAdapter::addDeviceInternally(const QDBusObjectPath &path, const QVariantMap &properties)
{
// Check if thing already added
if (hasDevice(path))
return;
BluetoothDevice *thing = new BluetoothDevice(path, properties, this);
m_devices.append(thing);
qCDebug(dcBluez()) << "[+]" << thing;
emit deviceAdded(thing);
}
void BluetoothAdapter::removeDeviceInternally(const QDBusObjectPath &path)
{
foreach (BluetoothDevice *thing, m_devices) {
if (thing->m_path == path) {
m_devices.removeOne(thing);
emit deviceRemoved(thing);
thing->deleteLater();
}
}
}
bool BluetoothAdapter::hasDevice(const QDBusObjectPath &path)
{
foreach (BluetoothDevice *thing, m_devices) {
if (thing->m_path == path)
return true;
}
return false;
}
bool BluetoothAdapter::removeDevice(const QDBusObjectPath &path)
{
if (!m_adapterInterface->isValid()) {
qCWarning(dcBluez()) << "Invalid DBus adapter interface for" << m_path.path();
return false;
}
qCDebug(dcBluez()) << "Remove and unpair device" << path.path();
QDBusPendingCall removeCall = m_adapterInterface->asyncCall("RemoveDevice", QVariant::fromValue(path));
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(removeCall, this);
connect(watcher, &QDBusPendingCallWatcher::finished, this, &BluetoothAdapter::onRemoveDeviceFinished);
return true;
}
void BluetoothAdapter::setAliasInternally(const QString &alias)
{
if (m_alias != alias) {
m_alias = alias;
emit aliasChanged(m_alias);
}
}
void BluetoothAdapter::setDiscoveringInternally(const bool &discovering)
{
if (m_discovering != discovering) {
m_discovering = discovering;
emit discoveringChanged(m_discovering);
}
}
void BluetoothAdapter::setDiscoverableInernally(const bool &discoverable)
{
if (m_discoverable != discoverable) {
m_discoverable = discoverable;
emit discoverableChanged(m_discoverable);
}
}
void BluetoothAdapter::setDiscoverableTimeoutInternally(const uint &discoverableTimeout)
{
if (m_discoverableTimeout != discoverableTimeout) {
m_discoverableTimeout = discoverableTimeout;
emit discoverableTimeoutChanged(m_discoverableTimeout);
}
}
void BluetoothAdapter::setPairableInternally(const bool &pairable)
{
if (m_pairable != pairable) {
m_pairable = pairable;
emit pairableChanged(m_pairable);
}
}
void BluetoothAdapter::setPairableTimeoutInternally(const uint &pairableTimeout)
{
if (m_pairableTimeout != pairableTimeout) {
m_pairableTimeout = pairableTimeout;
emit pairableTimeoutChanged(m_pairableTimeout);
}
}
void BluetoothAdapter::setPoweredInternally(const bool &powered)
{
if (m_powered != powered) {
m_powered = powered;
emit poweredChanged(m_powered);
}
}
void BluetoothAdapter::onPropertiesChanged(const QString &interface, const QVariantMap &changedProperties, const QStringList &invalidatedProperties)
{
if (interface != orgBluezAdapter1)
return;
qCDebug(dcBluez()) << "BluetoothAdapter:" << m_name << m_address << "properties changed" << interface << changedProperties << invalidatedProperties;
processProperties(changedProperties);
}
void BluetoothAdapter::onRemoveDeviceFinished(QDBusPendingCallWatcher *call)
{
QDBusPendingReply<void> reply = *call;
if (reply.isError())
qCWarning(dcBluez()) << "Could not remove device" << m_address << reply.error().name() << reply.error().message();
call->deleteLater();
}
void BluetoothAdapter::startDiscovering()
{
if (!m_adapterInterface->isValid()) {
qCWarning(dcBluez()) << "Invalid DBus adapter interface for" << m_path.path();
return;
}
if (discovering())
return;
QDBusMessage query = m_adapterInterface->call("StartDiscovery");
if(query.type() != QDBusMessage::ReplyMessage) {
qCWarning(dcBluez()) << "Could not start discovery" << m_name << ":" << query.errorName() << query.errorMessage();
return;
}
}
void BluetoothAdapter::stopDiscovering()
{
if (!m_adapterInterface->isValid()) {
qCWarning(dcBluez()) << "Invalid DBus adapter interface for" << m_path.path();
return;
}
QDBusMessage query = m_adapterInterface->call("StopDiscovery");
if(query.type() != QDBusMessage::ReplyMessage) {
qCWarning(dcBluez()) << "Could not start discovery" << m_name << ":" << query.errorName() << query.errorMessage();
return;
}
}
QDebug operator<<(QDebug debug, BluetoothAdapter *adapter)
{
debug.noquote().nospace() << "BluetoothAdapter(" << adapter->name() << ", " << adapter->address();
debug.noquote().nospace() << ", powered: " << adapter->powered();
debug.noquote().nospace() << ", pairable: " << adapter->pairable();
debug.noquote().nospace() << ", visible: " << adapter->discoverable();
debug.noquote().nospace() << ") ";
return debug;
}