etm-powersync-plugins/elgato/aveabulb.cpp

165 lines
6.5 KiB
C++

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* This file is part of guh. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "aveabulb.h"
#include "extern-plugininfo.h"
AveaBulb::AveaBulb(Device *device, BluetoothLowEnergyDevice *bluetoothDevice, QObject *parent) :
QObject(parent),
m_device(device),
m_bluetoothDevice(bluetoothDevice)
{
connect(m_bluetoothDevice, &BluetoothLowEnergyDevice::connectedChanged, this, &AveaBulb::onConnectedChanged);
connect(m_bluetoothDevice, &BluetoothLowEnergyDevice::servicesDiscoveryFinished, this, &AveaBulb::onServiceDiscoveryFinished);
}
Device *AveaBulb::device()
{
return m_device;
}
BluetoothLowEnergyDevice *AveaBulb::bluetoothDevice()
{
return m_bluetoothDevice;
}
bool AveaBulb::setColor(const QColor &color)
{
if (!m_bluetoothDevice->connected())
return false;
if (!m_colorService)
return false;
// Convert rgb to wrgb
QByteArray command;
command.append(QByteArray::fromHex("35"));
qCDebug(dcElgato()) << color << command;
return true;
}
void AveaBulb::onConnectedChanged(const bool &connected)
{
qCDebug(dcElgato()) << "Bulb" << m_bluetoothDevice->name() << m_bluetoothDevice->address().toString() << (connected ? "connected" : "disconnected");
m_device->setStateValue(connectedStateTypeId, connected);
if (!connected) {
// Clean up services
m_colorService->deleteLater();
//m_imageService->deleteLater();
m_colorService = nullptr;
m_imageService = nullptr;
}
}
void AveaBulb::onServiceDiscoveryFinished()
{
qCDebug(dcElgato()) << "Service discovery finished";
if (!m_bluetoothDevice->serviceUuids().contains(colorServiceUuid)) {
qCWarning(dcElgato()) << "Could not find color service";
return;
}
if (!m_bluetoothDevice->serviceUuids().contains(imageServiceUuid)) {
qCWarning(dcElgato()) << "Could not find image service";
return;
}
// Color service
if (!m_colorService) {
m_colorService = m_bluetoothDevice->controller()->createServiceObject(colorServiceUuid, this);
if (!m_colorService) {
qCWarning(dcElgato()) << "Could not create color service.";
return;
}
connect(m_colorService, &QLowEnergyService::stateChanged, this, &AveaBulb::onColorServiceStateChanged);
connect(m_colorService, &QLowEnergyService::characteristicChanged, this, &AveaBulb::onColorServiceCharacteristicChanged);
m_colorService->discoverDetails();
}
}
void AveaBulb::onColorServiceStateChanged(const QLowEnergyService::ServiceState &state)
{
// Only continue if discovered
if (state != QLowEnergyService::ServiceDiscovered)
return;
qCDebug(dcElgato()) << "Color service discovered.";
foreach (const QLowEnergyCharacteristic &characteristic, m_colorService->characteristics()) {
qCDebug(dcElgato()) << " -->" << characteristic.name() << characteristic.uuid().toString() << characteristic.value();
foreach (const QLowEnergyDescriptor &desciptor, characteristic.descriptors()) {
qCDebug(dcElgato()) << " -->" << desciptor.name() << desciptor.uuid().toString() << desciptor.value();
}
}
// Data characteristic
m_colorCharacteristic = m_colorService->characteristic(QBluetoothUuid(QUuid("f815e811-456c-6761-746f-4d756e696368")));
if (!m_colorCharacteristic.isValid()) {
qCWarning(dcElgato()) << "Invalid color data characteristic.";
}
// Enable notifications
QLowEnergyDescriptor notificationDescriptor = m_colorCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
m_colorService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100"));
// Get current configuration
// Color
m_colorService->writeCharacteristic(m_colorCharacteristic, QByteArray::fromHex("35"));
// Brightness
m_colorService->writeCharacteristic(m_colorCharacteristic, QByteArray::fromHex("57"));
// Name
m_colorService->writeCharacteristic(m_colorCharacteristic, QByteArray::fromHex("58"));
}
void AveaBulb::onColorServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
{
qCDebug(dcElgato()) << "Color characteristic changed" << characteristic.uuid().toString() << value;
if (value.startsWith(QByteArray::fromHex("35"))) {
qCDebug(dcElgato()) << "Received color notification";
qCDebug(dcElgato()) << " Fade" << value.mid(1, 2);
qCDebug(dcElgato()) << " Fixed value" << value.mid(3, 2);
qCDebug(dcElgato()) << " White" << value.mid(5, 2);
qCDebug(dcElgato()) << " Red" << value.mid(7, 2);
qCDebug(dcElgato()) << " Green" << value.mid(9, 2);
qCDebug(dcElgato()) << " Blue" << value.mid(11, 2);
} else if (value.startsWith(QByteArray::fromHex("57"))) {
qCDebug(dcElgato()) << "Received brightness notification";
qCDebug(dcElgato()) << " Fade" << value.mid(1, 2);
} else if (value.startsWith(QByteArray::fromHex("58"))) {
qCDebug(dcElgato()) << "Received name notification";
qCDebug(dcElgato()) << " Name" << value.mid(1, value.count() - 2);
}
}