first working version of avea example plugin for bluetoot le
This commit is contained in:
parent
3348fd18de
commit
6ea0e0c4a9
1
debian/guh-plugins.install
vendored
1
debian/guh-plugins.install
vendored
@ -18,4 +18,5 @@ usr/lib/guh/plugins/libguh_devicepluginleynew.so
|
|||||||
usr/lib/guh/plugins/libguh_deviceplugintune.so
|
usr/lib/guh/plugins/libguh_deviceplugintune.so
|
||||||
usr/lib/guh/plugins/libguh_devicepluginudpcommander.so
|
usr/lib/guh/plugins/libguh_devicepluginudpcommander.so
|
||||||
usr/lib/guh/plugins/libguh_devicepluginkodi.so
|
usr/lib/guh/plugins/libguh_devicepluginkodi.so
|
||||||
|
usr/lib/guh/plugins/libguh_devicepluginelgato.so
|
||||||
|
|
||||||
|
|||||||
7
doc/bluetooth.qdoc
Normal file
7
doc/bluetooth.qdoc
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
/*!
|
||||||
|
\page bluetooth-index.html
|
||||||
|
\title Bluetooth Plugins
|
||||||
|
|
||||||
|
\annotatedlist bluetooth
|
||||||
|
*/
|
||||||
|
|
||||||
@ -23,16 +23,10 @@
|
|||||||
\li \l{RF 433 MHz Plugins}
|
\li \l{RF 433 MHz Plugins}
|
||||||
\li \l{Service Plugins}
|
\li \l{Service Plugins}
|
||||||
\li \l{Network Plugins}
|
\li \l{Network Plugins}
|
||||||
|
\li \l{Bluetooth Plugins}
|
||||||
\endlist
|
\endlist
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
\section1 API's
|
|
||||||
The guh daemon provides two API's:
|
|
||||||
\list
|
|
||||||
\li \l{JSON-RPC API}{JSON-RPC}
|
|
||||||
\li \l{https://github.com/guh/guh/wiki/REST-Api-documentation}{REST}
|
|
||||||
\endlist
|
|
||||||
|
|
||||||
\section1 Write your own plugin
|
\section1 Write your own plugin
|
||||||
Here you can find some tutorials for developing and working with guh:
|
Here you can find some tutorials for developing and working with guh:
|
||||||
\list
|
\list
|
||||||
|
|||||||
@ -13,6 +13,8 @@
|
|||||||
\section2 Network Plugins
|
\section2 Network Plugins
|
||||||
\annotatedlist network
|
\annotatedlist network
|
||||||
|
|
||||||
|
\section1 Bluetooth Plugins
|
||||||
|
\annotatedlist bluetooth
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@ -26,9 +26,8 @@ BluetoothLowEnergyDevice::BluetoothLowEnergyDevice(const QBluetoothDeviceInfo &d
|
|||||||
|
|
||||||
connect(m_controller, &QLowEnergyController::connected, this, &BluetoothLowEnergyDevice::connected);
|
connect(m_controller, &QLowEnergyController::connected, this, &BluetoothLowEnergyDevice::connected);
|
||||||
connect(m_controller, &QLowEnergyController::disconnected, this, &BluetoothLowEnergyDevice::disconnected);
|
connect(m_controller, &QLowEnergyController::disconnected, this, &BluetoothLowEnergyDevice::disconnected);
|
||||||
connect(m_controller, &QLowEnergyController::serviceDiscovered, this, &BluetoothLowEnergyDevice::serviceDiscovered);
|
|
||||||
connect(m_controller, &QLowEnergyController::discoveryFinished, this, &BluetoothLowEnergyDevice::serviceScanFinished);
|
|
||||||
connect(m_controller, SIGNAL(error(QLowEnergyController::Error)), this, SLOT(deviceError(QLowEnergyController::Error)));
|
connect(m_controller, SIGNAL(error(QLowEnergyController::Error)), this, SLOT(deviceError(QLowEnergyController::Error)));
|
||||||
|
connect(m_controller, SIGNAL(discoveryFinished()), this, SIGNAL(servicesDiscoveryFinished()));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString BluetoothLowEnergyDevice::name() const
|
QString BluetoothLowEnergyDevice::name() const
|
||||||
@ -41,14 +40,9 @@ QBluetoothAddress BluetoothLowEnergyDevice::address() const
|
|||||||
return m_deviceInfo.address();
|
return m_deviceInfo.address();
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QLowEnergyService *> BluetoothLowEnergyDevice::services() const
|
QLowEnergyController *BluetoothLowEnergyDevice::controller() const
|
||||||
{
|
{
|
||||||
return m_services;
|
return m_controller;
|
||||||
}
|
|
||||||
|
|
||||||
QList<QLowEnergyCharacteristic> BluetoothLowEnergyDevice::characteristics() const
|
|
||||||
{
|
|
||||||
return m_characteristics;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BluetoothLowEnergyDevice::connectDevice()
|
void BluetoothLowEnergyDevice::connectDevice()
|
||||||
@ -66,90 +60,22 @@ bool BluetoothLowEnergyDevice::isConnected() const
|
|||||||
return m_connected;
|
return m_connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BluetoothLowEnergyDevice::isDiscovered() const
|
|
||||||
{
|
|
||||||
return m_discovered;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BluetoothLowEnergyDevice::discoverService(const QBluetoothUuid &serviceUuid)
|
|
||||||
{
|
|
||||||
Q_UNUSED(serviceUuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BluetoothLowEnergyDevice::connected()
|
void BluetoothLowEnergyDevice::connected()
|
||||||
{
|
{
|
||||||
m_connected = true;
|
m_connected = true;
|
||||||
qDebug() << "connected successfully to" << name() << address().toString();
|
qDebug() << "connected successfully to bluetooth LE device:" << name() << address().toString();
|
||||||
emit connectionStatusChanged(true);
|
emit connectionStatusChanged();
|
||||||
m_controller->discoverServices();
|
m_controller->discoverServices();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BluetoothLowEnergyDevice::disconnected()
|
void BluetoothLowEnergyDevice::disconnected()
|
||||||
{
|
{
|
||||||
m_connected = false;
|
m_connected = false;
|
||||||
qWarning() << "disconnected from" << name() << address().toString();
|
qWarning() << "disconnected from bluetooth LE device:" << name() << address().toString();
|
||||||
emit connectionStatusChanged(false);
|
emit connectionStatusChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BluetoothLowEnergyDevice::deviceError(const QLowEnergyController::Error &error)
|
void BluetoothLowEnergyDevice::deviceError(const QLowEnergyController::Error &error)
|
||||||
{
|
{
|
||||||
qWarning() << "ERROR: Bluetooth device" << name() << address().toString() << ": " << error << m_controller->errorString();
|
qWarning() << "ERROR: Bluetooth LE device:" << name() << address().toString() << ": " << error << m_controller->errorString();
|
||||||
}
|
|
||||||
|
|
||||||
void BluetoothLowEnergyDevice::serviceDiscovered(const QBluetoothUuid &serviceUuid)
|
|
||||||
{
|
|
||||||
QLowEnergyService *service = m_controller->createServiceObject(serviceUuid);
|
|
||||||
|
|
||||||
if (!service) {
|
|
||||||
qWarning() << "Cannot create service for uuid" << serviceUuid;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
connect(service, SIGNAL(characteristicChanged(QLowEnergyCharacteristic,QByteArray)), this, SLOT(serviceCharacteristicChanged(QLowEnergyCharacteristic,QByteArray)));
|
|
||||||
connect(service, SIGNAL(error(QLowEnergyService::ServiceError)), this, SLOT(serviceError(QLowEnergyService::ServiceError)));
|
|
||||||
connect(service, SIGNAL(stateChanged(QLowEnergyService::ServiceState)), this, SLOT(serviceStateChanged(QLowEnergyService::ServiceState)));
|
|
||||||
|
|
||||||
m_services.append(service);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BluetoothLowEnergyDevice::serviceStateChanged(const QLowEnergyService::ServiceState &newState)
|
|
||||||
{
|
|
||||||
if (newState != QLowEnergyService::ServiceDiscovered) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QLowEnergyService *service = qobject_cast<QLowEnergyService *>(sender());
|
|
||||||
foreach (QLowEnergyCharacteristic characteristic, service->characteristics()) {
|
|
||||||
if (!characteristic.descriptors().isEmpty()) {
|
|
||||||
foreach (QLowEnergyDescriptor descriptor, characteristic.descriptors()) {
|
|
||||||
if (descriptor.isValid()) {
|
|
||||||
m_descriptors.append(descriptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_characteristics.append(characteristic);
|
|
||||||
}
|
|
||||||
qDebug() << "details discovered for service " << service->serviceName() << service->serviceUuid().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
void BluetoothLowEnergyDevice::serviceScanFinished()
|
|
||||||
{
|
|
||||||
qDebug() << "service scan finished";
|
|
||||||
emit serviceScanFinished();
|
|
||||||
}
|
|
||||||
|
|
||||||
void BluetoothLowEnergyDevice::serviceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
|
|
||||||
{
|
|
||||||
qDebug() << "characteristic" << characteristic.name() << "changed:" << value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BluetoothLowEnergyDevice::serviceError(const QLowEnergyService::ServiceError &error)
|
|
||||||
{
|
|
||||||
QLowEnergyService *service = qobject_cast<QLowEnergyService *>(sender());
|
|
||||||
qWarning() << "ERROR: Bluetooth service " << service->serviceName() << service->serviceUuid() << ": " << error;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BluetoothLowEnergyDevice::confirmedDescriptorWrite(const QLowEnergyDescriptor &descriptor, const QByteArray &value)
|
|
||||||
{
|
|
||||||
qDebug() << "descriptor" << descriptor.name() << "written successfully " << value;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,8 +33,6 @@ public:
|
|||||||
|
|
||||||
QString name() const;
|
QString name() const;
|
||||||
QBluetoothAddress address() const;
|
QBluetoothAddress address() const;
|
||||||
QList<QLowEnergyService *> services() const;
|
|
||||||
QList<QLowEnergyCharacteristic> characteristics() const;
|
|
||||||
|
|
||||||
void connectDevice();
|
void connectDevice();
|
||||||
void disconnectDevice();
|
void disconnectDevice();
|
||||||
@ -42,35 +40,24 @@ public:
|
|||||||
bool isConnected() const;
|
bool isConnected() const;
|
||||||
bool isDiscovered() const;
|
bool isDiscovered() const;
|
||||||
|
|
||||||
void discoverService(const QBluetoothUuid &serviceUuid);
|
protected:
|
||||||
|
QLowEnergyController *controller() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QBluetoothDeviceInfo m_deviceInfo;
|
QBluetoothDeviceInfo m_deviceInfo;
|
||||||
QLowEnergyController *m_controller;
|
QLowEnergyController *m_controller;
|
||||||
QList<QLowEnergyService *> m_services;
|
|
||||||
QList<QLowEnergyCharacteristic> m_characteristics;
|
|
||||||
QList<QLowEnergyDescriptor> m_descriptors;
|
|
||||||
|
|
||||||
bool m_connected;
|
bool m_connected;
|
||||||
bool m_discovered;
|
bool m_discovered;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void connectionStatusChanged(const bool &connectionStatus);
|
void connectionStatusChanged();
|
||||||
void servicesDiscovered();
|
void servicesDiscoveryFinished();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
// Device
|
|
||||||
void connected();
|
void connected();
|
||||||
void disconnected();
|
void disconnected();
|
||||||
void deviceError(const QLowEnergyController::Error &error);
|
void deviceError(const QLowEnergyController::Error &error);
|
||||||
void serviceDiscovered(const QBluetoothUuid &serviceUuid);
|
|
||||||
void serviceStateChanged(const QLowEnergyService::ServiceState &newState);
|
|
||||||
void serviceScanFinished();
|
|
||||||
|
|
||||||
// Service
|
|
||||||
void serviceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value);
|
|
||||||
void serviceError(const QLowEnergyService::ServiceError &error);
|
|
||||||
void confirmedDescriptorWrite(const QLowEnergyDescriptor &descriptor, const QByteArray &value);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BLUETOOTHLOWENERGYDEVICE_H
|
#endif // BLUETOOTHLOWENERGYDEVICE_H
|
||||||
|
|||||||
@ -23,7 +23,7 @@ BluetoothScanner::BluetoothScanner(QObject *parent) :
|
|||||||
{
|
{
|
||||||
m_timer = new QTimer(this);
|
m_timer = new QTimer(this);
|
||||||
m_timer->setSingleShot(true);
|
m_timer->setSingleShot(true);
|
||||||
m_timer->setInterval(10000);
|
m_timer->setInterval(5000);
|
||||||
connect(m_timer, &QTimer::timeout, this, &BluetoothScanner::discoveryTimeout);
|
connect(m_timer, &QTimer::timeout, this, &BluetoothScanner::discoveryTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ bool BluetoothScanner::discover(const PluginId &pluginId)
|
|||||||
|
|
||||||
void BluetoothScanner::deviceDiscovered(const QBluetoothDeviceInfo &device)
|
void BluetoothScanner::deviceDiscovered(const QBluetoothDeviceInfo &device)
|
||||||
{
|
{
|
||||||
// check if this is LE device
|
// check if this is a LE device
|
||||||
bool bluetoothLE = false;
|
bool bluetoothLE = false;
|
||||||
if (device.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration) {
|
if (device.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration) {
|
||||||
bluetoothLE = true;
|
bluetoothLE = true;
|
||||||
@ -98,14 +98,16 @@ void BluetoothScanner::deviceDiscovered(const QBluetoothDeviceInfo &device)
|
|||||||
|
|
||||||
void BluetoothScanner::onError(QBluetoothDeviceDiscoveryAgent::Error error)
|
void BluetoothScanner::onError(QBluetoothDeviceDiscoveryAgent::Error error)
|
||||||
{
|
{
|
||||||
Q_UNUSED(error);
|
Q_UNUSED(error)
|
||||||
|
|
||||||
m_available = false;
|
m_available = false;
|
||||||
if (m_timer->isActive()) {
|
|
||||||
|
if (m_timer->isActive())
|
||||||
m_timer->stop();
|
m_timer->stop();
|
||||||
}
|
|
||||||
if (isRunning()) {
|
if (isRunning())
|
||||||
m_discoveryAgent->stop();
|
m_discoveryAgent->stop();
|
||||||
}
|
|
||||||
qWarning() << "ERROR: Bluetooth discovery:" << m_discoveryAgent->errorString();
|
qWarning() << "ERROR: Bluetooth discovery:" << m_discoveryAgent->errorString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -98,16 +98,16 @@ bool Radio433::enable()
|
|||||||
if (gpioFile.exists()) {
|
if (gpioFile.exists()) {
|
||||||
// bool receiverAvailable = m_receiver->startReceiver();
|
// bool receiverAvailable = m_receiver->startReceiver();
|
||||||
// if (!receiverAvailable) {
|
// if (!receiverAvailable) {
|
||||||
// //qCWarning(dcHardware) << "ERROR: radio 433 MHz receiver not available on GPIO's";
|
// //qWarning() << "ERROR: radio 433 MHz receiver not available on GPIO's";
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// bool transmitterAvailable = m_transmitter->startTransmitter();
|
// bool transmitterAvailable = m_transmitter->startTransmitter();
|
||||||
// if (!transmitterAvailable) {
|
// if (!transmitterAvailable) {
|
||||||
// //qCWarning(dcHardware) << "ERROR: radio 433 MHz transmitter not available on GPIO's";
|
// //qWarning() << "ERROR: radio 433 MHz transmitter not available on GPIO's";
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// if (!receiverAvailable && !transmitterAvailable) {
|
// if (!receiverAvailable && !transmitterAvailable) {
|
||||||
// qCWarning(dcHardware) << "--> Radio 433 MHz GPIO's not available.";
|
// qWarning() << "--> Radio 433 MHz GPIO's not available.";
|
||||||
// return false;
|
// return false;
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,5 +26,5 @@ boblight {
|
|||||||
}
|
}
|
||||||
|
|
||||||
contains(DEFINES, BLUETOOTH_LE) {
|
contains(DEFINES, BLUETOOTH_LE) {
|
||||||
# bluetooth plugins
|
SUBDIRS += elgato
|
||||||
}
|
}
|
||||||
|
|||||||
146
plugins/deviceplugins/elgato/aveabulb.cpp
Normal file
146
plugins/deviceplugins/elgato/aveabulb.cpp
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
#include "aveabulb.h"
|
||||||
|
|
||||||
|
|
||||||
|
AveaBulb::AveaBulb(const QBluetoothDeviceInfo &deviceInfo, const QLowEnergyController::RemoteAddressType &addressType, QObject *parent) :
|
||||||
|
BluetoothLowEnergyDevice(deviceInfo, addressType, parent),
|
||||||
|
m_colorService(0)
|
||||||
|
{
|
||||||
|
m_colorSeviceUuid = QBluetoothUuid(QUuid("f815e810-456c-6761-746f-4d756e696368"));
|
||||||
|
m_colorCharacteristicUuid = QBluetoothUuid(QUuid("f815e811-456c-6761-746f-4d756e696368"));
|
||||||
|
|
||||||
|
connect(this, SIGNAL(connectionStatusChanged()), this,SLOT(onConnectionStatusChanged()));
|
||||||
|
connect(this, SIGNAL(servicesDiscoveryFinished()), this, SLOT(serviceScanFinished()));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AveaBulb::isAvailable()
|
||||||
|
{
|
||||||
|
return m_isAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AveaBulb::serviceScanFinished()
|
||||||
|
{
|
||||||
|
if (!controller()->services().contains(m_colorSeviceUuid)) {
|
||||||
|
qWarning() << "ERROR: Color service not found for device" << name() << address().toString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_colorService) {
|
||||||
|
qWarning() << "ERROR: Attention! bad implementation of service handling!!";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create color service and discover it
|
||||||
|
m_colorService = controller()->createServiceObject(m_colorSeviceUuid, this);
|
||||||
|
|
||||||
|
if (!m_colorService) {
|
||||||
|
qWarning() << "ERROR: could not create color service for device" << name() << address().toString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(m_colorService, SIGNAL(stateChanged(QLowEnergyService::ServiceState)), this, SLOT(serviceStateChanged(QLowEnergyService::ServiceState)));
|
||||||
|
connect(m_colorService, SIGNAL(characteristicChanged(QLowEnergyCharacteristic,QByteArray)), this, SLOT(serviceCharacteristicChanged(QLowEnergyCharacteristic,QByteArray)));
|
||||||
|
connect(m_colorService, SIGNAL(characteristicWritten(QLowEnergyCharacteristic,QByteArray)), this, SLOT(confirmedCharacteristicWritten(QLowEnergyCharacteristic,QByteArray)));
|
||||||
|
connect(m_colorService, SIGNAL(error(QLowEnergyService::ServiceError)), this, SLOT(serviceError(QLowEnergyService::ServiceError)));
|
||||||
|
|
||||||
|
m_colorService->discoverDetails();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AveaBulb::onConnectionStatusChanged()
|
||||||
|
{
|
||||||
|
if (!isConnected()) {
|
||||||
|
// delete the service, needs to be recreatedand rediscovered once the device will be reconnected
|
||||||
|
delete m_colorService;
|
||||||
|
m_colorService = 0;
|
||||||
|
|
||||||
|
m_isAvailable = false;
|
||||||
|
emit availableChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AveaBulb::serviceStateChanged(const QLowEnergyService::ServiceState &state)
|
||||||
|
{
|
||||||
|
switch (state) {
|
||||||
|
case QLowEnergyService::ServiceDiscovered:
|
||||||
|
m_colorCharacteristic = m_colorService->characteristic(m_colorCharacteristicUuid);
|
||||||
|
|
||||||
|
if (!m_colorCharacteristic.isValid()) {
|
||||||
|
qWarning() << "ERROR: color characteristc not found for device " << name() << address().toString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_isAvailable = true;
|
||||||
|
emit availableChanged();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AveaBulb::serviceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
|
||||||
|
{
|
||||||
|
qDebug() << "service characteristic changed" << characteristic.name() << value.toHex();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AveaBulb::confirmedCharacteristicWritten(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
|
||||||
|
{
|
||||||
|
if (characteristic.handle() == m_colorCharacteristic.handle()) {
|
||||||
|
if (m_actions.contains(value.toHex())) {
|
||||||
|
ActionId actionId = m_actions.take(value.toHex());
|
||||||
|
emit actionExecutionFinished(actionId, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AveaBulb::serviceError(const QLowEnergyService::ServiceError &error)
|
||||||
|
{
|
||||||
|
qWarning() << "ERROR: color service of " << name() << address().toString() << ":" << error;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AveaBulb::enableNotification()
|
||||||
|
{
|
||||||
|
if (!isAvailable())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
qDebug() << "enable notify";
|
||||||
|
QByteArray value = "0100";
|
||||||
|
m_colorService->writeCharacteristic(m_colorCharacteristic, value, QLowEnergyService::WriteWithResponse);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AveaBulb::testMethod()
|
||||||
|
{
|
||||||
|
if (!isAvailable())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QByteArray value = "34";
|
||||||
|
qDebug() << "test" << value;
|
||||||
|
m_colorService->writeCharacteristic(m_colorCharacteristic, QByteArray::fromHex(value), QLowEnergyService::WriteWithResponse);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AveaBulb::actionPowerOff(ActionId actionId)
|
||||||
|
{
|
||||||
|
if (!isAvailable())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QByteArray value = "35f4010a00008000b000a00090";
|
||||||
|
qDebug() << "set" << name() << "power OFF";
|
||||||
|
m_actions.insert(value, actionId);
|
||||||
|
m_colorService->writeCharacteristic(m_colorCharacteristic, QByteArray::fromHex(value), QLowEnergyService::WriteWithResponse);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AveaBulb::setWhite(ActionId actionId)
|
||||||
|
{
|
||||||
|
if (!isAvailable())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QByteArray value = "3532000a00ff0f003000200010";
|
||||||
|
qDebug() << "set" << name() << "white";
|
||||||
|
m_actions.insert(value, actionId);
|
||||||
|
m_colorService->writeCharacteristic(m_colorCharacteristic, QByteArray::fromHex(value), QLowEnergyService::WriteWithResponse);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
51
plugins/deviceplugins/elgato/aveabulb.h
Normal file
51
plugins/deviceplugins/elgato/aveabulb.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#ifndef AVEABULB_H
|
||||||
|
#define AVEABULB_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include "typeutils.h"
|
||||||
|
#include "bluetooth/bluetoothlowenergydevice.h"
|
||||||
|
|
||||||
|
class AveaBulb : public BluetoothLowEnergyDevice
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit AveaBulb(const QBluetoothDeviceInfo &deviceInfo, const QLowEnergyController::RemoteAddressType &addressType, QObject *parent = 0);
|
||||||
|
|
||||||
|
bool isAvailable();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void availableChanged();
|
||||||
|
void actionExecutionFinished(const ActionId &actionId, const bool &success);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QBluetoothUuid m_colorSeviceUuid;
|
||||||
|
QLowEnergyService *m_colorService;
|
||||||
|
|
||||||
|
QBluetoothUuid m_colorCharacteristicUuid;
|
||||||
|
QLowEnergyCharacteristic m_colorCharacteristic;
|
||||||
|
|
||||||
|
bool m_isAvailable;
|
||||||
|
|
||||||
|
QHash<QByteArray, ActionId> m_actions;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void serviceScanFinished();
|
||||||
|
void onConnectionStatusChanged();
|
||||||
|
|
||||||
|
// Color service
|
||||||
|
void serviceStateChanged(const QLowEnergyService::ServiceState &state);
|
||||||
|
void serviceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value);
|
||||||
|
void confirmedCharacteristicWritten(const QLowEnergyCharacteristic &characteristic, const QByteArray &value);
|
||||||
|
void serviceError(const QLowEnergyService::ServiceError &error);
|
||||||
|
|
||||||
|
bool enableNotification();
|
||||||
|
bool testMethod();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
// actions
|
||||||
|
bool actionPowerOff(ActionId actionId);
|
||||||
|
bool setWhite(ActionId actionId);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // AVEABULB_H
|
||||||
526
plugins/deviceplugins/elgato/devicepluginelgato.cpp
Normal file
526
plugins/deviceplugins/elgato/devicepluginelgato.cpp
Normal file
@ -0,0 +1,526 @@
|
|||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* *
|
||||||
|
* This file is part of guh. *
|
||||||
|
* *
|
||||||
|
* Guh is free software: you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation, version 2 of the License. *
|
||||||
|
* *
|
||||||
|
* Guh 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 General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
|
||||||
|
* *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\page elgato.html
|
||||||
|
\title Elgato
|
||||||
|
|
||||||
|
\ingroup plugins
|
||||||
|
\ingroup bluetooth
|
||||||
|
|
||||||
|
This plugin allows to find and controll the Bluetooth Low Energy bulb from \l{https://www.elgato.com/en/smart/avea}{Elgato Avea}.
|
||||||
|
|
||||||
|
\chapter Device Overviw of \tt{Avea_44A9}
|
||||||
|
\section1 Services
|
||||||
|
\code
|
||||||
|
----------------------------------------------------------------
|
||||||
|
name : "Generic Access"
|
||||||
|
type : "<primary>"
|
||||||
|
uuid : "{00001800-0000-1000-8000-00805f9b34fb}"
|
||||||
|
uuid (hex) : "0x1800"
|
||||||
|
----------------------------------------------------------------
|
||||||
|
name : "Generic Attribute"
|
||||||
|
type : "<primary>"
|
||||||
|
uuid : "{00001801-0000-1000-8000-00805f9b34fb}"
|
||||||
|
uuid (hex) : "0x1801"
|
||||||
|
----------------------------------------------------------------
|
||||||
|
name : "Device Information"
|
||||||
|
type : "<primary>"
|
||||||
|
uuid : "{0000180a-0000-1000-8000-00805f9b34fb}"
|
||||||
|
uuid (hex) : "0x180a"
|
||||||
|
----------------------------------------------------------------
|
||||||
|
name : "Unknown Service"
|
||||||
|
type : "<primary>"
|
||||||
|
uuid : "{f815e600-456c-6761-746f-4d756e696368}"
|
||||||
|
uuid (hex) : "f815e600-456c-6761-746f-4d756e696368"
|
||||||
|
----------------------------------------------------------------
|
||||||
|
name : "Unknown Service"
|
||||||
|
type : "<primary>"
|
||||||
|
uuid : "{f815e500-456c-6761-746f-4d756e696368}"
|
||||||
|
uuid (hex) : "f815e500-456c-6761-746f-4d756e696368"
|
||||||
|
----------------------------------------------------------------
|
||||||
|
name : "Unknown Service"
|
||||||
|
type : "<primary>"
|
||||||
|
uuid : "{f815e810-456c-6761-746f-4d756e696368}"
|
||||||
|
uuid (hex) : "f815e810-456c-6761-746f-4d756e696368"
|
||||||
|
----------------------------------------------------------------
|
||||||
|
name : "Unknown Service"
|
||||||
|
type : "<primary>"
|
||||||
|
uuid : "{f815e900-456c-6761-746f-4d756e696368}"
|
||||||
|
uuid (hex) : "f815e900-456c-6761-746f-4d756e696368"
|
||||||
|
----------------------------------------------------------------
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
\section2 Service: "Generic Access" {00001800-0000-1000-8000-00805f9b34fb} details
|
||||||
|
\code
|
||||||
|
----------------------------------------------------------------
|
||||||
|
characteristics:
|
||||||
|
name : "GAP Device Name"
|
||||||
|
uuid : "{00002a00-0000-1000-8000-00805f9b34fb}"
|
||||||
|
uuid (hex) : "0x2a00"
|
||||||
|
handle : "0x3"
|
||||||
|
permission : ("Read")
|
||||||
|
value : "Avea_44A9"
|
||||||
|
value (hex) : "417665615f34344139"
|
||||||
|
---------------------------------------------------------
|
||||||
|
descriptor count: 0
|
||||||
|
---------------------------------------------------------
|
||||||
|
name : "GAP Appearance"
|
||||||
|
uuid : "{00002a01-0000-1000-8000-00805f9b34fb}"
|
||||||
|
uuid (hex) : "0x2a01"
|
||||||
|
handle : "0x5"
|
||||||
|
permission : ("Read")
|
||||||
|
value : "
|
||||||
|
value (hex) : "0000"
|
||||||
|
---------------------------------------------------------
|
||||||
|
descriptor count: 0
|
||||||
|
---------------------------------------------------------
|
||||||
|
name : "GAP Peripheral Privacy Flag"
|
||||||
|
uuid : "{00002a02-0000-1000-8000-00805f9b34fb}"
|
||||||
|
uuid (hex) : "0x2a02"
|
||||||
|
handle : "0x7"
|
||||||
|
permission : ("Read", "Write")
|
||||||
|
value : "
|
||||||
|
value (hex) : "00"
|
||||||
|
---------------------------------------------------------
|
||||||
|
descriptor count: 0
|
||||||
|
---------------------------------------------------------
|
||||||
|
name : "GAP Reconnection Address"
|
||||||
|
uuid : "{00002a03-0000-1000-8000-00805f9b34fb}"
|
||||||
|
uuid (hex) : "0x2a03"
|
||||||
|
handle : "0x9"
|
||||||
|
permission : ("Read", "Write")
|
||||||
|
value : "
|
||||||
|
value (hex) : "000000000000"
|
||||||
|
---------------------------------------------------------
|
||||||
|
descriptor count: 0
|
||||||
|
---------------------------------------------------------
|
||||||
|
name : "GAP Peripheral Preferred Connection Parameters"
|
||||||
|
uuid : "{00002a04-0000-1000-8000-00805f9b34fb}"
|
||||||
|
uuid (hex) : "0x2a04"
|
||||||
|
handle : "0xb"
|
||||||
|
permission : ("Read")
|
||||||
|
value : "P
|
||||||
|
value (hex) : "5000a0000000e803"
|
||||||
|
---------------------------------------------------------
|
||||||
|
descriptor count: 0
|
||||||
|
---------------------------------------------------------
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
\section2 Service: "Generic Attribute" {00001801-0000-1000-8000-00805f9b34fb} details
|
||||||
|
\code
|
||||||
|
----------------------------------------------------------------
|
||||||
|
characteristics:
|
||||||
|
name : "GATT Service Changed"
|
||||||
|
uuid : "{00002a05-0000-1000-8000-00805f9b34fb}"
|
||||||
|
uuid (hex) : "0x2a05"
|
||||||
|
handle : "0xe"
|
||||||
|
permission : ("Indicate")
|
||||||
|
value : ""
|
||||||
|
value (hex) : ""
|
||||||
|
---------------------------------------------------------
|
||||||
|
descriptor count: 1
|
||||||
|
---------------------------------------------------------
|
||||||
|
name : "Client Characteristic Configuration"
|
||||||
|
uuid : "{00002902-0000-1000-8000-00805f9b34fb}"
|
||||||
|
handle : 15
|
||||||
|
value : "
|
||||||
|
value (hex) : "0000"
|
||||||
|
-----------------------------------------------------
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
\section2 Service: "Device Information" {0000180a-0000-1000-8000-00805f9b34fb} details
|
||||||
|
\code
|
||||||
|
----------------------------------------------------------------
|
||||||
|
characteristics:
|
||||||
|
name : "System ID"
|
||||||
|
uuid : "{00002a23-0000-1000-8000-00805f9b34fb}"
|
||||||
|
uuid (hex) : "0x2a23"
|
||||||
|
handle : "0x12"
|
||||||
|
permission : ("Read")
|
||||||
|
value : "D<EFBFBD>j<EFBFBD><EFBFBD><18><>"
|
||||||
|
value (hex) : "44a96afeff18eb84"
|
||||||
|
---------------------------------------------------------
|
||||||
|
descriptor count: 0
|
||||||
|
---------------------------------------------------------
|
||||||
|
name : "Model Number String"
|
||||||
|
uuid : "{00002a24-0000-1000-8000-00805f9b34fb}"
|
||||||
|
uuid (hex) : "0x2a24"
|
||||||
|
handle : "0x14"
|
||||||
|
permission : ("Read")
|
||||||
|
value : "1
|
||||||
|
value (hex) : "3100"
|
||||||
|
---------------------------------------------------------
|
||||||
|
descriptor count: 0
|
||||||
|
---------------------------------------------------------
|
||||||
|
name : "Serial Number String"
|
||||||
|
uuid : "{00002a25-0000-1000-8000-00805f9b34fb}"
|
||||||
|
uuid (hex) : "0x2a25"
|
||||||
|
handle : "0x16"
|
||||||
|
permission : ("Read")
|
||||||
|
value : "44A96A18EB84"
|
||||||
|
value (hex) : "343441393641313845423834"
|
||||||
|
---------------------------------------------------------
|
||||||
|
descriptor count: 0
|
||||||
|
---------------------------------------------------------
|
||||||
|
name : "Firmware Revision String"
|
||||||
|
uuid : "{00002a26-0000-1000-8000-00805f9b34fb}"
|
||||||
|
uuid (hex) : "0x2a26"
|
||||||
|
handle : "0x18"
|
||||||
|
permission : ("Read")
|
||||||
|
value : "1.0.0.296Af
|
||||||
|
value (hex) : "312e302e302e323936416600"
|
||||||
|
---------------------------------------------------------
|
||||||
|
descriptor count: 0
|
||||||
|
---------------------------------------------------------
|
||||||
|
name : "Hardware Revision String"
|
||||||
|
uuid : "{00002a27-0000-1000-8000-00805f9b34fb}"
|
||||||
|
uuid (hex) : "0x2a27"
|
||||||
|
handle : "0x1a"
|
||||||
|
permission : ("Read")
|
||||||
|
value : "Elgato Avea
|
||||||
|
value (hex) : "456c6761746f204176656100"
|
||||||
|
---------------------------------------------------------
|
||||||
|
descriptor count: 0
|
||||||
|
---------------------------------------------------------
|
||||||
|
name : "Software Revision String"
|
||||||
|
uuid : "{00002a28-0000-1000-8000-00805f9b34fb}"
|
||||||
|
uuid (hex) : "0x2a28"
|
||||||
|
handle : "0x1c"
|
||||||
|
permission : ("Read")
|
||||||
|
value : "1.0
|
||||||
|
value (hex) : "312e3000"
|
||||||
|
---------------------------------------------------------
|
||||||
|
descriptor count: 0
|
||||||
|
---------------------------------------------------------
|
||||||
|
name : "Manufacturer Name String"
|
||||||
|
uuid : "{00002a29-0000-1000-8000-00805f9b34fb}"
|
||||||
|
uuid (hex) : "0x2a29"
|
||||||
|
handle : "0x1e"
|
||||||
|
permission : ("Read")
|
||||||
|
value : "Elgato Systems GmbH
|
||||||
|
value (hex) : "456c6761746f2053797374656d7320476d624800"
|
||||||
|
---------------------------------------------------------
|
||||||
|
descriptor count: 0
|
||||||
|
---------------------------------------------------------
|
||||||
|
name : "PnP ID"
|
||||||
|
uuid : "{00002a50-0000-1000-8000-00805f9b34fb}"
|
||||||
|
uuid (hex) : "0x2a50"
|
||||||
|
handle : "0x20"
|
||||||
|
permission : ("Read")
|
||||||
|
value : "<02>
|
||||||
|
value (hex) : "02d90f00000001"
|
||||||
|
---------------------------------------------------------
|
||||||
|
descriptor count: 0
|
||||||
|
---------------------------------------------------------
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
\section2 Service: "Unknown Service" {f815e600-456c-6761-746f-4d756e696368} details
|
||||||
|
\code
|
||||||
|
----------------------------------------------------------------
|
||||||
|
characteristics:
|
||||||
|
name : "Alert"
|
||||||
|
uuid : "{f815e601-456c-6761-746f-4d756e696368}"
|
||||||
|
uuid (hex) : "f815e601-456c-6761-746f-4d756e696368"
|
||||||
|
handle : "0x23"
|
||||||
|
permission : ("Notify")
|
||||||
|
value : ""
|
||||||
|
value (hex) : ""
|
||||||
|
---------------------------------------------------------
|
||||||
|
descriptor count: 2
|
||||||
|
---------------------------------------------------------
|
||||||
|
name : "Client Characteristic Configuration"
|
||||||
|
uuid : "{00002902-0000-1000-8000-00805f9b34fb}"
|
||||||
|
handle : 36
|
||||||
|
value : "
|
||||||
|
value (hex) : "0000"
|
||||||
|
-----------------------------------------------------
|
||||||
|
name : "Characteristic User Description"
|
||||||
|
uuid : "{00002901-0000-1000-8000-00805f9b34fb}"
|
||||||
|
handle : 37
|
||||||
|
value : "Alert"
|
||||||
|
value (hex) : "416c657274"
|
||||||
|
-----------------------------------------------------
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
\section2 Service: "Unknown Service" {f815e500-456c-6761-746f-4d756e696368} details
|
||||||
|
\code
|
||||||
|
----------------------------------------------------------------
|
||||||
|
characteristics:
|
||||||
|
name : "Seq Upload"
|
||||||
|
uuid : "{f815e501-456c-6761-746f-4d756e696368}"
|
||||||
|
uuid (hex) : "f815e501-456c-6761-746f-4d756e696368"
|
||||||
|
handle : "0x28"
|
||||||
|
permission : ("Write", "Notify", "WriteNoResp")
|
||||||
|
value : ""
|
||||||
|
value (hex) : ""
|
||||||
|
---------------------------------------------------------
|
||||||
|
descriptor count: 2
|
||||||
|
---------------------------------------------------------
|
||||||
|
name : "Client Characteristic Configuration"
|
||||||
|
uuid : "{00002902-0000-1000-8000-00805f9b34fb}"
|
||||||
|
handle : 41
|
||||||
|
value : "
|
||||||
|
value (hex) : "0000"
|
||||||
|
-----------------------------------------------------
|
||||||
|
name : "Characteristic User Description"
|
||||||
|
uuid : "{00002901-0000-1000-8000-00805f9b34fb}"
|
||||||
|
handle : 42
|
||||||
|
value : "Seq Upload"
|
||||||
|
value (hex) : "5365712055706c6f6164"
|
||||||
|
-----------------------------------------------------
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
\section2 Service: "Unknown Service" {f815e810-456c-6761-746f-4d756e696368} details
|
||||||
|
|
||||||
|
Tis service will be used to set the color (handle \tt{0x2d}).
|
||||||
|
|
||||||
|
\code
|
||||||
|
----------------------------------------------------------------
|
||||||
|
characteristics:
|
||||||
|
name : "Debug"
|
||||||
|
uuid : "{f815e811-456c-6761-746f-4d756e696368}"
|
||||||
|
uuid (hex) : "f815e811-456c-6761-746f-4d756e696368"
|
||||||
|
handle : "0x2d"
|
||||||
|
permission : ("Write", "Notify")
|
||||||
|
value : ""
|
||||||
|
value (hex) : ""
|
||||||
|
---------------------------------------------------------
|
||||||
|
descriptor count: 2
|
||||||
|
---------------------------------------------------------
|
||||||
|
name : "Client Characteristic Configuration"
|
||||||
|
uuid : "{00002902-0000-1000-8000-00805f9b34fb}"
|
||||||
|
handle : 46
|
||||||
|
value : "
|
||||||
|
value (hex) : "0000"
|
||||||
|
-----------------------------------------------------
|
||||||
|
name : "Characteristic User Description"
|
||||||
|
uuid : "{00002901-0000-1000-8000-00805f9b34fb}"
|
||||||
|
handle : 47
|
||||||
|
value : "Debug"
|
||||||
|
value (hex) : "4465627567"
|
||||||
|
-----------------------------------------------------
|
||||||
|
name : "User Name"
|
||||||
|
uuid : "{f815e812-456c-6761-746f-4d756e696368}"
|
||||||
|
uuid (hex) : "f815e812-456c-6761-746f-4d756e696368"
|
||||||
|
handle : "0x31"
|
||||||
|
permission : ("Read", "Write")
|
||||||
|
value : ""
|
||||||
|
value (hex) : ""
|
||||||
|
---------------------------------------------------------
|
||||||
|
descriptor count: 1
|
||||||
|
---------------------------------------------------------
|
||||||
|
name : "Characteristic User Description"
|
||||||
|
uuid : "{00002901-0000-1000-8000-00805f9b34fb}"
|
||||||
|
handle : 50
|
||||||
|
value : "User Name"
|
||||||
|
value (hex) : "55736572204e616d65"
|
||||||
|
-----------------------------------------------------
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
\section2 Service: "Unknown Service" {f815e900-456c-6761-746f-4d756e696368} details
|
||||||
|
\code
|
||||||
|
----------------------------------------------------------------
|
||||||
|
characteristics:
|
||||||
|
name : "Img Identify"
|
||||||
|
uuid : "{f815e901-456c-6761-746f-4d756e696368}"
|
||||||
|
uuid (hex) : "f815e901-456c-6761-746f-4d756e696368"
|
||||||
|
handle : "0x35"
|
||||||
|
permission : ("Write", "Notify", "WriteNoResp")
|
||||||
|
value : ""
|
||||||
|
value (hex) : ""
|
||||||
|
---------------------------------------------------------
|
||||||
|
descriptor count: 2
|
||||||
|
---------------------------------------------------------
|
||||||
|
name : "Client Characteristic Configuration"
|
||||||
|
uuid : "{00002902-0000-1000-8000-00805f9b34fb}"
|
||||||
|
handle : 54
|
||||||
|
value : "
|
||||||
|
value (hex) : "0000"
|
||||||
|
-----------------------------------------------------
|
||||||
|
name : "Characteristic User Description"
|
||||||
|
uuid : "{00002901-0000-1000-8000-00805f9b34fb}"
|
||||||
|
handle : 55
|
||||||
|
value : "Img Identify"
|
||||||
|
value (hex) : "496d67204964656e74696679"
|
||||||
|
-----------------------------------------------------
|
||||||
|
name : "Img Block"
|
||||||
|
uuid : "{f815e902-456c-6761-746f-4d756e696368}"
|
||||||
|
uuid (hex) : "f815e902-456c-6761-746f-4d756e696368"
|
||||||
|
handle : "0x39"
|
||||||
|
permission : ("Write", "Notify", "WriteNoResp")
|
||||||
|
value : ""
|
||||||
|
value (hex) : ""
|
||||||
|
---------------------------------------------------------
|
||||||
|
descriptor count: 2
|
||||||
|
---------------------------------------------------------
|
||||||
|
name : "Client Characteristic Configuration"
|
||||||
|
uuid : "{00002902-0000-1000-8000-00805f9b34fb}"
|
||||||
|
handle : 58
|
||||||
|
value : "
|
||||||
|
value (hex) : "0000"
|
||||||
|
-----------------------------------------------------
|
||||||
|
name : "Characteristic User Description"
|
||||||
|
uuid : "{00002901-0000-1000-8000-00805f9b34fb}"
|
||||||
|
handle : 59
|
||||||
|
value : "Img Block"
|
||||||
|
value (hex) : "496d6720426c6f636b"
|
||||||
|
-----------------------------------------------------
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
|
||||||
|
\chapter Plugin properties
|
||||||
|
Following JSON file contains the definition and the description of all available \l{DeviceClass}{DeviceClasses}
|
||||||
|
and \l{Vendor}{Vendors} of this \l{DevicePlugin}.
|
||||||
|
|
||||||
|
Each \l{DeviceClass} has a list of \l{ParamType}{paramTypes}, \l{ActionType}{actionTypes}, \l{StateType}{stateTypes}
|
||||||
|
and \l{EventType}{eventTypes}. The \l{DeviceClass::CreateMethod}{createMethods} parameter describes how the \l{Device}
|
||||||
|
will be created in the system. A device can have more than one \l{DeviceClass::CreateMethod}{CreateMethod}.
|
||||||
|
The \l{DeviceClass::SetupMethod}{setupMethod} describes the setup method of the \l{Device}.
|
||||||
|
The detailed implementation of each \l{DeviceClass} can be found in the source code.
|
||||||
|
|
||||||
|
\quotefile plugins/deviceplugins/elgato/devicepluginelgato.json
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "devicepluginelgato.h"
|
||||||
|
|
||||||
|
#include "plugin/device.h"
|
||||||
|
#include "devicemanager.h"
|
||||||
|
#include "plugininfo.h"
|
||||||
|
|
||||||
|
DevicePluginElgato::DevicePluginElgato()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceManager::DeviceError DevicePluginElgato::discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms)
|
||||||
|
{
|
||||||
|
Q_UNUSED(params)
|
||||||
|
|
||||||
|
if (deviceClassId != aveaDeviceClassId)
|
||||||
|
return DeviceManager::DeviceErrorDeviceClassNotFound;
|
||||||
|
|
||||||
|
if (!discoverBluetooth())
|
||||||
|
return DeviceManager::DeviceErrorHardwareNotAvailable;
|
||||||
|
|
||||||
|
return DeviceManager::DeviceErrorAsync;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceManager::DeviceSetupStatus DevicePluginElgato::setupDevice(Device *device)
|
||||||
|
{
|
||||||
|
if (device->deviceClassId() == aveaDeviceClassId) {
|
||||||
|
QBluetoothAddress address = QBluetoothAddress(device->paramValue("mac address").toString());
|
||||||
|
QString name = device->paramValue("name").toString();
|
||||||
|
QBluetoothDeviceInfo deviceInfo = QBluetoothDeviceInfo(address, name, 0);
|
||||||
|
|
||||||
|
AveaBulb *avea = new AveaBulb(deviceInfo, QLowEnergyController::PublicAddress, this);
|
||||||
|
connect(avea, &AveaBulb::availableChanged, this, &DevicePluginElgato::bulbAvailableChanged);
|
||||||
|
connect(avea, &AveaBulb::actionExecutionFinished, this, &DevicePluginElgato::actionFinished);
|
||||||
|
m_bulbs.insert(avea, device);
|
||||||
|
|
||||||
|
avea->connectDevice();
|
||||||
|
|
||||||
|
return DeviceManager::DeviceSetupStatusSuccess;
|
||||||
|
}
|
||||||
|
return DeviceManager::DeviceSetupStatusFailure;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceManager::HardwareResources DevicePluginElgato::requiredHardware() const
|
||||||
|
{
|
||||||
|
return DeviceManager::HardwareResourceBluetoothLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceManager::DeviceError DevicePluginElgato::executeAction(Device *device, const Action &action)
|
||||||
|
{
|
||||||
|
// check deviceClassId
|
||||||
|
if (device->deviceClassId() == aveaDeviceClassId) {
|
||||||
|
AveaBulb *bulb = m_bulbs.key(device);
|
||||||
|
|
||||||
|
if (!bulb->isAvailable())
|
||||||
|
return DeviceManager::DeviceErrorHardwareNotAvailable;
|
||||||
|
|
||||||
|
// check actionTypeId
|
||||||
|
if (action.actionTypeId() == powerOffActionTypeId) {
|
||||||
|
bulb->actionPowerOff(action.id());
|
||||||
|
return DeviceManager::DeviceErrorAsync;
|
||||||
|
} else if (action.actionTypeId() == whiteActionTypeId) {
|
||||||
|
bulb->setWhite(action.id());
|
||||||
|
return DeviceManager::DeviceErrorAsync;
|
||||||
|
}
|
||||||
|
return DeviceManager::DeviceErrorActionTypeNotFound;
|
||||||
|
}
|
||||||
|
return DeviceManager::DeviceErrorDeviceClassNotFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DevicePluginElgato::bluetoothDiscoveryFinished(const QList<QBluetoothDeviceInfo> &deviceInfos)
|
||||||
|
{
|
||||||
|
QList<DeviceDescriptor> deviceDescriptors;
|
||||||
|
foreach (QBluetoothDeviceInfo deviceInfo, deviceInfos) {
|
||||||
|
if (deviceInfo.name().contains("Avea")) {
|
||||||
|
if (!verifyExistingDevices(deviceInfo)) {
|
||||||
|
DeviceDescriptor descriptor(aveaDeviceClassId, "Avea", deviceInfo.address().toString());
|
||||||
|
ParamList params;
|
||||||
|
params.append(Param("name", deviceInfo.name()));
|
||||||
|
params.append(Param("mac address", deviceInfo.address().toString()));
|
||||||
|
descriptor.setParams(params);
|
||||||
|
deviceDescriptors.append(descriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emit devicesDiscovered(aveaDeviceClassId, deviceDescriptors);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DevicePluginElgato::deviceRemoved(Device *device)
|
||||||
|
{
|
||||||
|
if (!m_bulbs.values().contains(device))
|
||||||
|
return;
|
||||||
|
|
||||||
|
AveaBulb *bulb= m_bulbs.key(device);
|
||||||
|
|
||||||
|
m_bulbs.take(bulb);
|
||||||
|
delete bulb;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DevicePluginElgato::verifyExistingDevices(const QBluetoothDeviceInfo &deviceInfo)
|
||||||
|
{
|
||||||
|
foreach (Device *device, myDevices()) {
|
||||||
|
if (device->paramValue("mac address").toString() == deviceInfo.address().toString())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DevicePluginElgato::bulbAvailableChanged()
|
||||||
|
{
|
||||||
|
AveaBulb *bulb =static_cast<AveaBulb *>(sender());
|
||||||
|
Device *device = m_bulbs.value(bulb);
|
||||||
|
device->setStateValue(availableStateTypeId, bulb->isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DevicePluginElgato::actionFinished(const ActionId actionId, const bool &success)
|
||||||
|
{
|
||||||
|
if (success) {
|
||||||
|
emit actionExecutionFinished(actionId, DeviceManager::DeviceErrorNoError);
|
||||||
|
} else {
|
||||||
|
emit actionExecutionFinished(actionId, DeviceManager::DeviceErrorHardwareFailure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
53
plugins/deviceplugins/elgato/devicepluginelgato.h
Normal file
53
plugins/deviceplugins/elgato/devicepluginelgato.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* *
|
||||||
|
* This file is part of guh. *
|
||||||
|
* *
|
||||||
|
* Guh is free software: you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation, version 2 of the License. *
|
||||||
|
* *
|
||||||
|
* Guh 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 General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
|
||||||
|
* *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
#ifndef DEVICEPLUGINELGATO_H
|
||||||
|
#define DEVICEPLUGINELGATO_H
|
||||||
|
|
||||||
|
#include "plugin/deviceplugin.h"
|
||||||
|
#include "bluetooth/bluetoothlowenergydevice.h"
|
||||||
|
#include "aveabulb.h"
|
||||||
|
|
||||||
|
class DevicePluginElgato : public DevicePlugin
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_PLUGIN_METADATA(IID "guru.guh.DevicePlugin" FILE "devicepluginelgato.json")
|
||||||
|
Q_INTERFACES(DevicePlugin)
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DevicePluginElgato();
|
||||||
|
|
||||||
|
DeviceManager::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) override;
|
||||||
|
DeviceManager::DeviceSetupStatus setupDevice(Device *device) override;
|
||||||
|
DeviceManager::HardwareResources requiredHardware() const override;
|
||||||
|
DeviceManager::DeviceError executeAction(Device *device, const Action &action) override;
|
||||||
|
|
||||||
|
void bluetoothDiscoveryFinished(const QList<QBluetoothDeviceInfo> &deviceInfos);
|
||||||
|
void deviceRemoved(Device *device) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QHash<AveaBulb *, Device *> m_bulbs;
|
||||||
|
bool verifyExistingDevices(const QBluetoothDeviceInfo &deviceInfo);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void bulbAvailableChanged();
|
||||||
|
void actionFinished(const ActionId actionId, const bool &success);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DEVICEPLUGINELGATO_H
|
||||||
56
plugins/deviceplugins/elgato/devicepluginelgato.json
Normal file
56
plugins/deviceplugins/elgato/devicepluginelgato.json
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
{
|
||||||
|
"name": "Elgato",
|
||||||
|
"id": "c5c03ad4-bfdb-444a-8eca-2c234c46cc27",
|
||||||
|
"vendors": [
|
||||||
|
{
|
||||||
|
"name": "Elgato",
|
||||||
|
"id": "90a3091d-1053-4f77-8dc3-92e27bbcebe7",
|
||||||
|
"deviceClasses": [
|
||||||
|
{
|
||||||
|
"deviceClassId": "164f9602-90ee-4693-bda3-9cafae37603e",
|
||||||
|
"idName": "avea",
|
||||||
|
"name": "Avea",
|
||||||
|
"createMethods": ["discovery"],
|
||||||
|
"paramTypes": [
|
||||||
|
{
|
||||||
|
"name": "name",
|
||||||
|
"type": "QString",
|
||||||
|
"inputType": "TextLine"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mac address",
|
||||||
|
"type": "QString",
|
||||||
|
"inputType": "MacAddress"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateTypes": [
|
||||||
|
{
|
||||||
|
"id": "6d5e792a-c786-40d2-ae35-a48ac6fafcbc",
|
||||||
|
"idName": "available",
|
||||||
|
"name": "available",
|
||||||
|
"type": "bool",
|
||||||
|
"defaultValue": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"actionTypes": [
|
||||||
|
{
|
||||||
|
"id": "30b6334d-37cd-4b94-a397-3b9b642c762e",
|
||||||
|
"idName": "reconnect",
|
||||||
|
"name": "reconnect"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "7936bd51-7ea3-4df4-9998-7325de85b677",
|
||||||
|
"idName": "white",
|
||||||
|
"name": "white"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "b2f39b7b-dd11-4db4-a82b-dd3d4b973bd5",
|
||||||
|
"idName": "powerOff",
|
||||||
|
"name": "power off"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
16
plugins/deviceplugins/elgato/elgato.pro
Normal file
16
plugins/deviceplugins/elgato/elgato.pro
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
include(../../plugins.pri)
|
||||||
|
|
||||||
|
TARGET = $$qtLibraryTarget(guh_devicepluginelgato)
|
||||||
|
|
||||||
|
QT+= bluetooth
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
devicepluginelgato.cpp \
|
||||||
|
aveabulb.cpp
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
devicepluginelgato.h \
|
||||||
|
aveabulb.h
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -227,7 +227,7 @@ void JsonReply::setCommandId(int commandId)
|
|||||||
|
|
||||||
void JsonReply::startWait()
|
void JsonReply::startWait()
|
||||||
{
|
{
|
||||||
m_timeout.start(5000);
|
m_timeout.start(10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonReply::timeout()
|
void JsonReply::timeout()
|
||||||
|
|||||||
Reference in New Issue
Block a user