147 lines
5.7 KiB
C++
147 lines
5.7 KiB
C++
|
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
|
||
|
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||
|
|
||
|
#include "deskcontrol.h"
|
||
|
|
||
|
#include <KLocalizedString>
|
||
|
#include <QBluetoothLocalDevice>
|
||
|
|
||
|
const auto DESK_UUID_KEY = QStringLiteral("DeskUUID");
|
||
|
|
||
|
const auto ADV_SVC = QBluetoothUuid("99fa0001-338a-1024-8a49-009c0215f78a");
|
||
|
|
||
|
const auto COMMAND_CHARACTERISTIC = QBluetoothUuid("99fa0002-338a-1024-8a49-009c0215f78a");
|
||
|
const auto POSITION_CHARACTERISTIC = QBluetoothUuid("99fa0021-338a-1024-8a49-009c0215f78a");
|
||
|
|
||
|
const auto upCommand = QByteArray::fromHex("4700");
|
||
|
const auto downCommand = QByteArray::fromHex("4600");
|
||
|
|
||
|
constexpr auto MAX_HEIGHT = 1.27;
|
||
|
constexpr auto MIN_HEIGHT = 0.62;
|
||
|
|
||
|
DeskControl::DeskControl(QObject *parent, const KPluginMetaData &data, const QVariantList &args)
|
||
|
: Applet(parent, data, args) {
|
||
|
m_localDevice.powerOn();
|
||
|
// If we have connected to the desk previously, connect. Otherwise discover one.
|
||
|
if (config().hasKey(DESK_UUID_KEY)) {
|
||
|
connectToDesk();
|
||
|
} else {
|
||
|
searchForDesk();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DeskControl::~DeskControl() = default;
|
||
|
|
||
|
DeskControl::DeskState DeskControl::state() const {
|
||
|
return DeskState::NotFound;
|
||
|
}
|
||
|
|
||
|
void DeskControl::up() const {
|
||
|
Q_ASSERT(m_commandService);
|
||
|
Q_ASSERT(m_commandCharacteristic.isValid());
|
||
|
|
||
|
m_commandService->writeCharacteristic(m_commandCharacteristic, upCommand);
|
||
|
}
|
||
|
|
||
|
void DeskControl::down() const {
|
||
|
Q_ASSERT(m_commandService);
|
||
|
Q_ASSERT(m_commandCharacteristic.isValid());
|
||
|
|
||
|
m_commandService->writeCharacteristic(m_commandCharacteristic, downCommand);
|
||
|
}
|
||
|
|
||
|
void DeskControl::connectToDesk() {
|
||
|
const auto lastDeskUUID = config().readEntry(DESK_UUID_KEY);
|
||
|
qInfo() << "Connecting to desk:" << lastDeskUUID;
|
||
|
|
||
|
m_controller = QLowEnergyController::createCentral(QBluetoothDeviceInfo(QBluetoothAddress(lastDeskUUID), QStringLiteral("Desk"), 0));
|
||
|
|
||
|
connect(m_controller, &QLowEnergyController::connected, this, [this]() {
|
||
|
m_controller->discoverServices();
|
||
|
});
|
||
|
connect(m_controller, &QLowEnergyController::discoveryFinished, this, [this]() {
|
||
|
for (auto service: m_controller->services()) {
|
||
|
if (service.toString() == QStringLiteral("{99fa0001-338a-1024-8a49-009c0215f78a}")) {
|
||
|
m_commandService = m_controller->createServiceObject(service);
|
||
|
m_commandService->discoverDetails();
|
||
|
|
||
|
connect(m_commandService, &QLowEnergyService::stateChanged, this, [this](QLowEnergyService::ServiceState state) {
|
||
|
m_commandCharacteristic = m_commandService->characteristic(COMMAND_CHARACTERISTIC);
|
||
|
});
|
||
|
connect(m_commandService, &QLowEnergyService::errorOccurred, [](QLowEnergyService::ServiceError error) {
|
||
|
qWarning() << error;
|
||
|
});
|
||
|
}
|
||
|
if (service.toString() == QStringLiteral("{99fa0020-338a-1024-8a49-009c0215f78a}")) {
|
||
|
m_positionCommandService = m_controller->createServiceObject(service);
|
||
|
m_positionCommandService->discoverDetails();
|
||
|
|
||
|
connect(m_positionCommandService, &QLowEnergyService::errorOccurred, [](QLowEnergyService::ServiceError error) {
|
||
|
qWarning() << error;
|
||
|
});
|
||
|
connect(m_positionCommandService, &QLowEnergyService::stateChanged, this, [this](QLowEnergyService::ServiceState state) {
|
||
|
QLowEnergyCharacteristic batteryLevel = m_positionCommandService->characteristic(POSITION_CHARACTERISTIC);
|
||
|
if (!batteryLevel.isValid())
|
||
|
return;
|
||
|
|
||
|
QLowEnergyDescriptor notification = batteryLevel.descriptor(
|
||
|
QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
|
||
|
if (!notification.isValid())
|
||
|
return;
|
||
|
|
||
|
m_positionCommandService->writeDescriptor(notification, QByteArray::fromHex("0100"));
|
||
|
});
|
||
|
|
||
|
connect(m_positionCommandService, &QLowEnergyService::characteristicChanged, this, [this](const QLowEnergyCharacteristic &info, const QByteArray &value) {
|
||
|
const int32_t highByte = value.at(1);
|
||
|
const int32_t lowByte = value.at(0);
|
||
|
const int32_t number = (highByte << 8) + lowByte;
|
||
|
|
||
|
m_height = (static_cast<float>(number) / 1000.0) + MIN_HEIGHT;
|
||
|
Q_EMIT heightChanged();
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
m_controller->connectToDevice();
|
||
|
}
|
||
|
|
||
|
void DeskControl::searchForDesk() {
|
||
|
qInfo() << "Searching for desk...";
|
||
|
|
||
|
QList<QBluetoothAddress> remotes = m_localDevice.connectedDevices();
|
||
|
if (remotes.empty()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for (const auto &address : remotes) {
|
||
|
auto controller = QLowEnergyController::createCentral(QBluetoothDeviceInfo(address, QStringLiteral("Desk"), 0));
|
||
|
|
||
|
qInfo() << controller->services();
|
||
|
|
||
|
connect(controller, &QLowEnergyController::connected, this, [this, controller]() {
|
||
|
controller->discoverServices();
|
||
|
});
|
||
|
connect(controller, &QLowEnergyController::discoveryFinished, this, [this, controller, address]() {
|
||
|
controller->deleteLater();
|
||
|
|
||
|
for (auto service: controller->services()) {
|
||
|
if (service == ADV_SVC) {
|
||
|
qInfo() << "Found desk:" << DESK_UUID_KEY;
|
||
|
config().writeEntry(DESK_UUID_KEY, address.toString());
|
||
|
connectToDesk();
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
controller->connectToDevice();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
K_PLUGIN_CLASS(DeskControl)
|
||
|
|
||
|
#include "deskcontrol.moc"
|
||
|
#include "moc_deskcontrol.cpp"
|