1
Fork 0
tisch/deskcontrol.cpp

147 lines
5.7 KiB
C++
Raw Normal View History

2024-10-30 22:37:28 -04:00
// 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"