Migrate senic plugin

This commit is contained in:
Simon Stürz 2018-01-12 12:46:23 +01:00 committed by Michael Zanetti
parent 413cd748f4
commit cd2289563f
7 changed files with 351 additions and 349 deletions

17
debian/control vendored
View File

@ -446,6 +446,22 @@ Description: guh.io plugin for elgato
This package will install the guh.io plugin for elgato This package will install the guh.io plugin for elgato
Package: guh-plugin-senic
Architecture: any
Depends: ${shlibs:Depends},
${misc:Depends},
guh-plugins-translations,
Description: guh.io plugin for senic
The guh daemon is a plugin based IoT (Internet of Things) server. The
server works like a translator for devices, things and services and
allows them to interact.
With the powerful rule engine you are able to connect any device available
in the system and create individual scenes and behaviors for your environment.
.
This package will install the guh.io plugin for senic
Package: guh-plugins-translations Package: guh-plugins-translations
Section: misc Section: misc
Architecture: all Architecture: all
@ -479,6 +495,7 @@ Depends: guh-plugin-awattar,
guh-plugin-wakeonlan, guh-plugin-wakeonlan,
guh-plugin-wemo, guh-plugin-wemo,
guh-plugin-elgato, guh-plugin-elgato,
guh-plugin-senic
Description: Plugins for guh IoT server - the default plugin collection Description: Plugins for guh IoT server - the default plugin collection
The guh daemon is a plugin based IoT (Internet of Things) server. The The guh daemon is a plugin based IoT (Internet of Things) server. The
server works like a translator for devices, things and services and server works like a translator for devices, things and services and

View File

@ -21,7 +21,7 @@ PLUGIN_DIRS = \
tcpcommander \ tcpcommander \
kodi \ kodi \
elgato \ elgato \
#senic \ senic \
awattar \ awattar \
netatmo \ netatmo \
plantcare \ plantcare \

View File

@ -37,18 +37,23 @@
\quotefile plugins/deviceplugins/senic/devicepluginsenic.json \quotefile plugins/deviceplugins/senic/devicepluginsenic.json
*/ */
#ifdef BLUETOOTH_LE
#include "devicepluginsenic.h" #include "devicepluginsenic.h"
#include "plugin/device.h" #include "plugin/device.h"
#include "devicemanager.h" #include "devicemanager.h"
#include "plugininfo.h" #include "plugininfo.h"
#include "hardware/bluetoothlowenergy/bluetoothlowenergymanager.h"
DevicePluginSenic::DevicePluginSenic() DevicePluginSenic::DevicePluginSenic()
{ {
} }
void DevicePluginSenic::init()
{
m_reconnectTimer = hardwareManager()->pluginTimerManager()->registerTimer(10);
connect(m_reconnectTimer, &PluginTimer::timeout, this, &DevicePluginSenic::onReconnectTimeout);
}
DeviceManager::DeviceError DevicePluginSenic::discoverDevices(const DeviceClassId &deviceClassId, const ParamList &params) DeviceManager::DeviceError DevicePluginSenic::discoverDevices(const DeviceClassId &deviceClassId, const ParamList &params)
{ {
Q_UNUSED(params) Q_UNUSED(params)
@ -56,55 +61,46 @@ DeviceManager::DeviceError DevicePluginSenic::discoverDevices(const DeviceClassI
if (deviceClassId != nuimoDeviceClassId) if (deviceClassId != nuimoDeviceClassId)
return DeviceManager::DeviceErrorDeviceClassNotFound; return DeviceManager::DeviceErrorDeviceClassNotFound;
if (!discoverBluetooth()) if (!hardwareManager()->bluetoothLowEnergyManager()->available())
return DeviceManager::DeviceErrorHardwareNotAvailable; return DeviceManager::DeviceErrorHardwareNotAvailable;
if (!hardwareManager()->bluetoothLowEnergyManager()->enabled())
return DeviceManager::DeviceErrorHardwareNotAvailable;
BluetoothDiscoveryReply *reply = hardwareManager()->bluetoothLowEnergyManager()->discoverDevices();
connect(reply, &BluetoothDiscoveryReply::finished, this, &DevicePluginSenic::onBluetoothDiscoveryFinished);
return DeviceManager::DeviceErrorAsync; return DeviceManager::DeviceErrorAsync;
} }
DeviceManager::DeviceSetupStatus DevicePluginSenic::setupDevice(Device *device) DeviceManager::DeviceSetupStatus DevicePluginSenic::setupDevice(Device *device)
{ {
qCDebug(dcSenic()) << "Setup device" << device->name() << device->params();
QString name = device->paramValue(nameParamTypeId).toString(); QString name = device->paramValue(nameParamTypeId).toString();
QBluetoothAddress address = QBluetoothAddress(device->paramValue(macParamTypeId).toString()); QBluetoothAddress address = QBluetoothAddress(device->paramValue(macParamTypeId).toString());
QBluetoothDeviceInfo deviceInfo = QBluetoothDeviceInfo(address, name, 0); QBluetoothDeviceInfo deviceInfo = QBluetoothDeviceInfo(address, name, 0);
Nuimo *nuimo = new Nuimo(deviceInfo, QLowEnergyController::RandomAddress, this); BluetoothLowEnergyDevice *bluetoothDevice = hardwareManager()->bluetoothLowEnergyManager()->registerDevice(deviceInfo, QLowEnergyController::RandomAddress);
connect(nuimo, &Nuimo::availableChanged, this, &DevicePluginSenic::connectionAvailableChanged);
connect(nuimo, &Nuimo::batteryValueChaged, this, &DevicePluginSenic::onBatteryValueChanged); Nuimo *nuimo = new Nuimo(device, bluetoothDevice, this);
connect(nuimo, &Nuimo::buttonPressed, this, &DevicePluginSenic::onButtonPressed); connect(nuimo, &Nuimo::buttonPressed, this, &DevicePluginSenic::onButtonPressed);
connect(nuimo, &Nuimo::buttonReleased, this, &DevicePluginSenic::onButtonReleased); connect(nuimo, &Nuimo::buttonReleased, this, &DevicePluginSenic::onButtonReleased);
connect(nuimo, &Nuimo::swipeDetected, this, &DevicePluginSenic::onSwipeDetected); connect(nuimo, &Nuimo::swipeDetected, this, &DevicePluginSenic::onSwipeDetected);
connect(nuimo, &Nuimo::rotationValueChanged, this, &DevicePluginSenic::onRotationValueChanged); connect(nuimo, &Nuimo::rotationValueChanged, this, &DevicePluginSenic::onRotationValueChanged);
m_nuimos.insert(nuimo, device); m_nuimos.insert(nuimo, device);
nuimo->bluetoothDevice()->connectDevice();
nuimo->connectDevice();
return DeviceManager::DeviceSetupStatusSuccess; return DeviceManager::DeviceSetupStatusSuccess;
} }
DeviceManager::HardwareResources DevicePluginSenic::requiredHardware() const
{
return DeviceManager::HardwareResourceBluetoothLE;
}
DeviceManager::DeviceError DevicePluginSenic::executeAction(Device *device, const Action &action) DeviceManager::DeviceError DevicePluginSenic::executeAction(Device *device, const Action &action)
{ {
QPointer<Nuimo> nuimo = m_nuimos.key(device); QPointer<Nuimo> nuimo = m_nuimos.key(device);
if (nuimo.isNull()) if (nuimo.isNull())
return DeviceManager::DeviceErrorHardwareFailure; return DeviceManager::DeviceErrorHardwareFailure;
// reconnect action does not need available true
if (action.actionTypeId() == connectActionTypeId) {
nuimo->reconnectDevice();
return DeviceManager::DeviceErrorNoError;
}
if (action.actionTypeId() == disconnectActionTypeId) {
nuimo->disconnectDevice();
return DeviceManager::DeviceErrorNoError;
}
if (action.actionTypeId() == showLogoActionTypeId) { if (action.actionTypeId() == showLogoActionTypeId) {
if (action.param(logoParamTypeId).value().toString() == "Guh") if (action.param(logoParamTypeId).value().toString() == "Guh")
@ -122,25 +118,6 @@ DeviceManager::DeviceError DevicePluginSenic::executeAction(Device *device, cons
return DeviceManager::DeviceErrorActionTypeNotFound; return DeviceManager::DeviceErrorActionTypeNotFound;
} }
void DevicePluginSenic::bluetoothDiscoveryFinished(const QList<QBluetoothDeviceInfo> &deviceInfos)
{
QList<DeviceDescriptor> deviceDescriptors;
foreach (QBluetoothDeviceInfo deviceInfo, deviceInfos) {
if (deviceInfo.name().contains("Nuimo")) {
if (!verifyExistingDevices(deviceInfo)) {
DeviceDescriptor descriptor(nuimoDeviceClassId, "Nuimo", deviceInfo.address().toString());
ParamList params;
params.append(Param(nameParamTypeId, deviceInfo.name()));
params.append(Param(macParamTypeId, deviceInfo.address().toString()));
descriptor.setParams(params);
deviceDescriptors.append(descriptor);
}
}
}
emit devicesDiscovered(nuimoDeviceClassId, deviceDescriptors);
}
void DevicePluginSenic::deviceRemoved(Device *device) void DevicePluginSenic::deviceRemoved(Device *device)
{ {
if (!m_nuimos.values().contains(device)) if (!m_nuimos.values().contains(device))
@ -161,20 +138,45 @@ bool DevicePluginSenic::verifyExistingDevices(const QBluetoothDeviceInfo &device
return false; return false;
} }
void DevicePluginSenic::connectionAvailableChanged() void DevicePluginSenic::onReconnectTimeout()
{ {
Nuimo *nuimo = static_cast<Nuimo *>(sender()); foreach (Nuimo *nuimo, m_nuimos.keys()) {
Device *device = m_nuimos.value(nuimo); if (!nuimo->bluetoothDevice()->connected()) {
device->setStateValue(availableStateTypeId, nuimo->isAvailable()); nuimo->bluetoothDevice()->connectDevice();
}
}
} }
void DevicePluginSenic::onBatteryValueChanged(const uint &percentage) void DevicePluginSenic::onBluetoothDiscoveryFinished()
{ {
Nuimo *nuimo = static_cast<Nuimo *>(sender()); BluetoothDiscoveryReply *reply = static_cast<BluetoothDiscoveryReply *>(sender());
Device *device = m_nuimos.value(nuimo); if (reply->error() != BluetoothDiscoveryReply::BluetoothDiscoveryReplyErrorNoError) {
device->setStateValue(batteryStateTypeId, percentage); qCWarning(dcSenic()) << "Bluetooth discovery error:" << reply->error();
reply->deleteLater();
emit devicesDiscovered(nuimoDeviceClassId, QList<DeviceDescriptor>());
return;
}
QList<DeviceDescriptor> deviceDescriptors;
foreach (const QBluetoothDeviceInfo &deviceInfo, reply->discoveredDevices()) {
if (deviceInfo.name().contains("Nuimo")) {
if (!verifyExistingDevices(deviceInfo)) {
DeviceDescriptor descriptor(nuimoDeviceClassId, "Nuimo", deviceInfo.address().toString());
ParamList params;
params.append(Param(nameParamTypeId, deviceInfo.name()));
params.append(Param(macParamTypeId, deviceInfo.address().toString()));
descriptor.setParams(params);
deviceDescriptors.append(descriptor);
}
}
}
reply->deleteLater();
emit devicesDiscovered(nuimoDeviceClassId, deviceDescriptors);
} }
void DevicePluginSenic::onButtonPressed() void DevicePluginSenic::onButtonPressed()
{ {
Nuimo *nuimo = static_cast<Nuimo *>(sender()); Nuimo *nuimo = static_cast<Nuimo *>(sender());
@ -218,6 +220,3 @@ void DevicePluginSenic::onRotationValueChanged(const uint &value)
} }
#endif // BLUETOOTH_LE

View File

@ -23,10 +23,9 @@
#ifndef DEVICEPLUGINELGATO_H #ifndef DEVICEPLUGINELGATO_H
#define DEVICEPLUGINELGATO_H #define DEVICEPLUGINELGATO_H
#ifdef BLUETOOTH_LE #include "plugintimer.h"
#include "plugin/deviceplugin.h" #include "plugin/deviceplugin.h"
#include "bluetooth/bluetoothlowenergydevice.h" #include "hardware/bluetoothlowenergy/bluetoothlowenergydevice.h"
#include "nuimo.h" #include "nuimo.h"
@ -40,21 +39,23 @@ class DevicePluginSenic : public DevicePlugin
public: public:
explicit DevicePluginSenic(); explicit DevicePluginSenic();
void init() override;
DeviceManager::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const ParamList &params) override; DeviceManager::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const ParamList &params) override;
DeviceManager::DeviceSetupStatus setupDevice(Device *device) override; DeviceManager::DeviceSetupStatus setupDevice(Device *device) override;
DeviceManager::HardwareResources requiredHardware() const override;
DeviceManager::DeviceError executeAction(Device *device, const Action &action) override; DeviceManager::DeviceError executeAction(Device *device, const Action &action) override;
void bluetoothDiscoveryFinished(const QList<QBluetoothDeviceInfo> &deviceInfos);
void deviceRemoved(Device *device) override; void deviceRemoved(Device *device) override;
private: private:
QHash<Nuimo *, Device *> m_nuimos; QHash<Nuimo *, Device *> m_nuimos;
PluginTimer *m_reconnectTimer = nullptr;
bool verifyExistingDevices(const QBluetoothDeviceInfo &deviceInfo); bool verifyExistingDevices(const QBluetoothDeviceInfo &deviceInfo);
private slots: private slots:
void connectionAvailableChanged(); void onReconnectTimeout();
void onBatteryValueChanged(const uint &percentage); void onBluetoothDiscoveryFinished();
void onButtonPressed(); void onButtonPressed();
void onButtonReleased(); void onButtonReleased();
void onSwipeDetected(const Nuimo::SwipeDirection &direction); void onSwipeDetected(const Nuimo::SwipeDirection &direction);
@ -62,6 +63,4 @@ private slots:
}; };
#endif // BLUETOOTH_LE
#endif // DEVICEPLUGINELGATO_H #endif // DEVICEPLUGINELGATO_H

View File

@ -37,12 +37,36 @@
"stateTypes": [ "stateTypes": [
{ {
"id": "5286976a-f5dc-4662-872a-438ac5d491cb", "id": "5286976a-f5dc-4662-872a-438ac5d491cb",
"idName": "available", "idName": "connected",
"name": "available", "name": "Connected",
"eventTypeName": "available changed", "eventTypeName": "Connected changed",
"type": "bool", "type": "bool",
"defaultValue": false "defaultValue": false
}, },
{
"id": "5c400da4-a14e-4e0a-be9f-c82ffe7e1972",
"idName": "hardwareRevision",
"name": "Hardware revision",
"eventTypeName": "Hardware revision changed",
"type": "QString",
"defaultValue": "-"
},
{
"id": "edcf76c6-9fed-4c26-9853-c284cf887adb",
"idName": "firmwareRevision",
"name": "Firmware revision",
"eventTypeName": "Firmware revision changed",
"type": "QString",
"defaultValue": "-"
},
{
"id": "be42cbd3-12e9-44ec-8f9d-141e10d9573a",
"idName": "softwareRevision",
"name": "Software revision",
"eventTypeName": "Software revision changed",
"type": "QString",
"defaultValue": "-"
},
{ {
"id": "b5ee2465-7fa1-450b-8073-f115537d3409", "id": "b5ee2465-7fa1-450b-8073-f115537d3409",
"idName": "battery", "idName": "battery",
@ -67,16 +91,6 @@
} }
], ],
"actionTypes": [ "actionTypes": [
{
"id": "bb1c46fe-5dfb-4fa3-ad89-0ba576ac780e",
"idName": "connect",
"name": "connect"
},
{
"id": "11bf3143-34f8-42ab-9750-073040c1a7fc",
"idName": "disconnect",
"name": "disconnect"
},
{ {
"id": "d44ca5b7-f8d6-4413-9d2e-cef89282c039", "id": "d44ca5b7-f8d6-4413-9d2e-cef89282c039",
"idName": "showLogo", "idName": "showLogo",

View File

@ -20,29 +20,38 @@
* * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifdef BLUETOOTH_LE
#include "nuimo.h" #include "nuimo.h"
#include "extern-plugininfo.h" #include "extern-plugininfo.h"
#include <QBitArray> #include <QBitArray>
#include <QtEndian> #include <QtEndian>
Nuimo::Nuimo(const QBluetoothDeviceInfo &deviceInfo, const QLowEnergyController::RemoteAddressType &addressType, QObject *parent) : static QBluetoothUuid ledMatrinxServiceUuid = QBluetoothUuid(QUuid("f29b1523-cb19-40f3-be5c-7241ecb82fd1"));
BluetoothLowEnergyDevice(deviceInfo, addressType, parent), static QBluetoothUuid ledMatrixCharacteristicUuid = QBluetoothUuid(QUuid("f29b1524-cb19-40f3-be5c-7241ecb82fd1"));
m_deviceInfoService(NULL),
m_batteryService(NULL), static QBluetoothUuid inputServiceUuid = QBluetoothUuid(QUuid("f29b1525-cb19-40f3-be5c-7241ecb82fd2"));
m_inputService(NULL), static QBluetoothUuid inputSwipeCharacteristicUuid = QBluetoothUuid(QUuid("f29b1527-cb19-40f3-be5c-7241ecb82fd2"));
m_ledMatrixService(NULL), static QBluetoothUuid inputRotationCharacteristicUuid = QBluetoothUuid(QUuid("f29b1528-cb19-40f3-be5c-7241ecb82fd2"));
m_isAvailable(false) static QBluetoothUuid inputButtonCharacteristicUuid = QBluetoothUuid(QUuid("f29b1529-cb19-40f3-be5c-7241ecb82fd2"));
Nuimo::Nuimo(Device *device, BluetoothLowEnergyDevice *bluetoothDevice, QObject *parent) :
QObject(parent),
m_device(device),
m_bluetoothDevice(bluetoothDevice)
{ {
connect(this, SIGNAL(connectionStatusChanged()), this,SLOT(onConnectionStatusChanged())); connect(m_bluetoothDevice, &BluetoothLowEnergyDevice::connectedChanged, this, &Nuimo::onConnectedChanged);
connect(this, SIGNAL(servicesDiscoveryFinished()), this, SLOT(serviceScanFinished())); connect(m_bluetoothDevice, &BluetoothLowEnergyDevice::servicesDiscoveryFinished, this, &Nuimo::onServiceDiscoveryFinished);
} }
bool Nuimo::isAvailable() Device *Nuimo::device()
{ {
return m_isAvailable; return m_device;
}
BluetoothLowEnergyDevice *Nuimo::bluetoothDevice()
{
return m_bluetoothDevice;
} }
void Nuimo::showGuhLogo() void Nuimo::showGuhLogo()
@ -93,19 +102,11 @@ void Nuimo::showArrowDown()
showMatrix(matrix, 3); showMatrix(matrix, 3);
} }
void Nuimo::registerService(QLowEnergyService *service)
{
connect(service, SIGNAL(stateChanged(QLowEnergyService::ServiceState)), this, SLOT(serviceStateChanged(QLowEnergyService::ServiceState)));
connect(service, SIGNAL(characteristicChanged(QLowEnergyCharacteristic, QByteArray)), this, SLOT(serviceCharacteristicChanged(QLowEnergyCharacteristic, QByteArray)));
connect(service, SIGNAL(characteristicWritten(QLowEnergyCharacteristic, QByteArray)), this, SLOT(confirmedCharacteristicWritten(QLowEnergyCharacteristic, QByteArray)));
connect(service, SIGNAL(descriptorWritten(QLowEnergyDescriptor, QByteArray)), this, SLOT(confirmedDescriptorWritten(QLowEnergyDescriptor, QByteArray)));
connect(service, SIGNAL(error(QLowEnergyService::ServiceError)), this, SLOT(serviceError(QLowEnergyService::ServiceError)));
service->discoverDetails();
}
void Nuimo::showMatrix(const QByteArray &matrix, const int &seconds) void Nuimo::showMatrix(const QByteArray &matrix, const int &seconds)
{ {
if (!m_ledMatrixService)
return;
QBitArray bits; QBitArray bits;
bits.resize(81); bits.resize(81);
for (int i = 0; i < matrix.size(); i++) { for (int i = 0; i < matrix.size(); i++) {
@ -127,225 +128,223 @@ void Nuimo::showMatrix(const QByteArray &matrix, const int &seconds)
m_ledMatrixService->writeCharacteristic(m_ledMatrixCharacteristic, bytes); m_ledMatrixService->writeCharacteristic(m_ledMatrixCharacteristic, bytes);
} }
void Nuimo::printService(QLowEnergyService *service)
void Nuimo::serviceScanFinished()
{ {
QBluetoothUuid deviceInfoUuid(QUuid("0000180A-0000-1000-8000-00805F9B34FB")); foreach (const QLowEnergyCharacteristic &characteristic, service->characteristics()) {
QBluetoothUuid batteryUuid(QUuid("0000180F-0000-1000-8000-00805F9B34FB")); qCDebug(dcSenic()) << " -->" << characteristic.name() << characteristic.uuid().toString() << characteristic.value();
QBluetoothUuid inputUuid(QUuid("F29B1525-CB19-40F3-BE5C-7241ECB82FD2")); foreach (const QLowEnergyDescriptor &desciptor, characteristic.descriptors()) {
QBluetoothUuid ledMatrixUuid(QUuid("F29B1523-CB19-40F3-BE5C-7241ECB82FD1")); qCDebug(dcSenic()) << " -->" << desciptor.name() << desciptor.uuid().toString() << desciptor.value();
}
}
}
void Nuimo::setBatteryValue(const QByteArray &data)
{
int batteryPercentage = data.toHex().toUInt(0, 16);
qCDebug(dcSenic()) << "Battery:" << batteryPercentage << "%";
device()->setStateValue(batteryStateTypeId, batteryPercentage);
}
void Nuimo::onConnectedChanged(const bool &connected)
{
qCDebug(dcSenic()) << m_bluetoothDevice->name() << m_bluetoothDevice->address().toString() << (connected ? "connected" : "disconnected");
m_device->setStateValue(connectedStateTypeId, connected);
if (!connected) {
// Clean up services
m_deviceInfoService->deleteLater();
m_batteryService->deleteLater();
m_ledMatrixService->deleteLater();
m_inputService->deleteLater();
m_deviceInfoService = nullptr;
m_batteryService = nullptr;
m_ledMatrixService = nullptr;
m_inputService = nullptr;
}
}
void Nuimo::onServiceDiscoveryFinished()
{
qCDebug(dcSenic()) << "Service scan finised"; qCDebug(dcSenic()) << "Service scan finised";
if (!controller()->services().contains(deviceInfoUuid)) { if (!m_bluetoothDevice->serviceUuids().contains(QBluetoothUuid::DeviceInformation)) {
qCWarning(dcSenic()) << "Device Information service not found for device" << name() << address().toString(); qCWarning(dcSenic()) << "Device Information service not found for device" << bluetoothDevice()->name() << bluetoothDevice()->address().toString();
return; return;
} }
if (!controller()->services().contains(batteryUuid)) { if (!m_bluetoothDevice->serviceUuids().contains(QBluetoothUuid::BatteryService)) {
qCWarning(dcSenic()) << "Battery service not found for device" << name() << address().toString(); qCWarning(dcSenic()) << "Battery service not found for device" << bluetoothDevice()->name() << bluetoothDevice()->address().toString();
return; return;
} }
if (!controller()->services().contains(ledMatrixUuid)) { if (!m_bluetoothDevice->serviceUuids().contains(ledMatrinxServiceUuid)) {
qCWarning(dcSenic()) << "Led matrix service not found for device" << name() << address().toString(); qCWarning(dcSenic()) << "Led matrix service not found for device" << bluetoothDevice()->name() << bluetoothDevice()->address().toString();
return; return;
} }
if (!controller()->services().contains(inputUuid)) { if (!m_bluetoothDevice->serviceUuids().contains(inputServiceUuid)) {
qCWarning(dcSenic()) << "Input service not found for device" << name() << address().toString(); qCWarning(dcSenic()) << "Input service not found for device" << bluetoothDevice()->name() << bluetoothDevice()->address().toString();
return; return;
} }
m_isAvailable = true; // Device info service
emit availableChanged();
// Device information
m_deviceInfoService = controller()->createServiceObject(deviceInfoUuid, this);
if (!m_deviceInfoService) { if (!m_deviceInfoService) {
qCWarning(dcSenic()) << "Could not create device information service for device" << name() << address().toString(); m_deviceInfoService = m_bluetoothDevice->controller()->createServiceObject(QBluetoothUuid::DeviceInformation, this);
return; if (!m_deviceInfoService) {
qCWarning(dcSenic()) << "Could not create device info service.";
return;
}
connect(m_deviceInfoService, &QLowEnergyService::stateChanged, this, &Nuimo::onDeviceInfoServiceStateChanged);
if (m_deviceInfoService->state() == QLowEnergyService::DiscoveryRequired) {
m_deviceInfoService->discoverDetails();
}
} }
// Battery service // Battery service
m_batteryService = controller()->createServiceObject(batteryUuid, this);
if (!m_batteryService) { if (!m_batteryService) {
qCWarning(dcSenic()) << "Could not create battery service for device" << name() << address().toString(); m_batteryService = m_bluetoothDevice->controller()->createServiceObject(QBluetoothUuid::BatteryService, this);
return; if (!m_batteryService) {
qCWarning(dcSenic()) << "Could not create battery service.";
return;
}
connect(m_batteryService, &QLowEnergyService::stateChanged, this, &Nuimo::onBatteryServiceStateChanged);
connect(m_batteryService, &QLowEnergyService::characteristicChanged, this, &Nuimo::onBatteryCharacteristicChanged);
if (m_batteryService->state() == QLowEnergyService::DiscoveryRequired) {
m_batteryService->discoverDetails();
}
} }
// Input service // Input service
m_inputService = controller()->createServiceObject(inputUuid, this);
if (!m_inputService) { if (!m_inputService) {
qCWarning(dcSenic()) << "Could not create input service for device" << name() << address().toString(); m_inputService = m_bluetoothDevice->controller()->createServiceObject(inputServiceUuid, this);
return; if (!m_inputService) {
qCWarning(dcSenic()) << "Could not create input service.";
return;
}
connect(m_inputService, &QLowEnergyService::stateChanged, this, &Nuimo::onInputServiceStateChanged);
connect(m_inputService, &QLowEnergyService::characteristicChanged, this, &Nuimo::onInputCharacteristicChanged);
if (m_inputService->state() == QLowEnergyService::DiscoveryRequired) {
m_inputService->discoverDetails();
}
} }
// Led Matrix // Input service
m_ledMatrixService = controller()->createServiceObject(ledMatrixUuid, this);
if (!m_ledMatrixService) { if (!m_ledMatrixService) {
qCWarning(dcSenic()) << "Could not create led matrix service for device" << name() << address().toString(); m_ledMatrixService = m_bluetoothDevice->controller()->createServiceObject(ledMatrinxServiceUuid, this);
if (!m_ledMatrixService) {
qCWarning(dcSenic()) << "Could not create led matrix service.";
return;
}
connect(m_ledMatrixService, &QLowEnergyService::stateChanged, this, &Nuimo::onLedMatrixServiceStateChanged);
if (m_ledMatrixService->state() == QLowEnergyService::DiscoveryRequired) {
m_ledMatrixService->discoverDetails();
}
}
}
void Nuimo::onDeviceInfoServiceStateChanged(const QLowEnergyService::ServiceState &state)
{
// Only continue if discovered
if (state != QLowEnergyService::ServiceDiscovered)
return;
qCDebug(dcSenic()) << "Device info service discovered.";
printService(m_deviceInfoService);
device()->setStateValue(firmwareRevisionStateTypeId, QString::fromUtf8(m_deviceInfoService->characteristic(QBluetoothUuid::FirmwareRevisionString).value()));
device()->setStateValue(hardwareRevisionStateTypeId, QString::fromUtf8(m_deviceInfoService->characteristic(QBluetoothUuid::HardwareRevisionString).value()));
device()->setStateValue(softwareRevisionStateTypeId, QString::fromUtf8(m_deviceInfoService->characteristic(QBluetoothUuid::SoftwareRevisionString).value()));
}
void Nuimo::onBatteryServiceStateChanged(const QLowEnergyService::ServiceState &state)
{
// Only continue if discovered
if (state != QLowEnergyService::ServiceDiscovered)
return;
qCDebug(dcSenic()) << "Battery service discovered.";
printService(m_batteryService);
m_batteryCharacteristic = m_batteryService->characteristic(QBluetoothUuid::BatteryLevel);
if (!m_batteryCharacteristic.isValid()) {
qCWarning(dcSenic()) << "Battery characteristc not found for device " << bluetoothDevice()->name() << bluetoothDevice()->address().toString();
return; return;
} }
registerService(m_deviceInfoService); // Enable notifications
registerService(m_batteryService); QLowEnergyDescriptor notificationDescriptor = m_batteryCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
registerService(m_inputService); m_batteryService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100"));
registerService(m_ledMatrixService);
setBatteryValue(m_batteryCharacteristic.value());
} }
void Nuimo::onConnectionStatusChanged() void Nuimo::onBatteryCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
{
if (!isConnected()) {
// delete the services, they need to be recreated and
// rediscovered once the device will be reconnected
if (m_deviceInfoService) {
delete m_deviceInfoService;
m_deviceInfoService = 0;
}
if (m_batteryService) {
delete m_batteryService;
m_batteryService = 0;
}
if (m_inputService) {
delete m_inputService;
m_inputService = 0;
}
if (m_ledMatrixService) {
delete m_ledMatrixService;
m_ledMatrixService = 0;
}
m_isAvailable = false;
emit availableChanged();
}
}
void Nuimo::serviceStateChanged(const QLowEnergyService::ServiceState &state)
{
QLowEnergyService *service =static_cast<QLowEnergyService *>(sender());
switch (state) {
case QLowEnergyService::DiscoveringServices:
if (service == m_batteryService)
qCDebug(dcSenic()) << "Start discovering battery service...";
if (service == m_deviceInfoService)
qCDebug(dcSenic()) << "Start discovering device information service...";
if (service == m_inputService)
qCDebug(dcSenic()) << "Start discovering input service...";
if (service == m_ledMatrixService)
qCDebug(dcSenic()) << "Start discovering led matrix service...";
break;
case QLowEnergyService::ServiceDiscovered:
// Device information
if (service == m_deviceInfoService) {
qCDebug(dcSenic()) << "Device information service discovered";
m_deviceInfoCharacteristic = m_deviceInfoService->characteristic(QBluetoothUuid(QUuid("00002A29-0000-1000-8000-00805F9B34FB")));
if (!m_deviceInfoCharacteristic.isValid()) {
qCWarning(dcSenic()) << "Device information characteristc not found for device " << name() << address().toString();
return;
}
qCDebug(dcSenic()) << "Device information:" << m_deviceInfoCharacteristic.value();
}
// Battery
if (service == m_batteryService) {
qCDebug(dcSenic()) << "Battery service discovered";
m_batteryCharacteristic = m_batteryService->characteristic(QBluetoothUuid(QUuid("00002A19-0000-1000-8000-00805F9B34FB")));
if (!m_batteryCharacteristic.isValid()) {
qCWarning(dcSenic()) << "Battery characteristc not found for device " << name() << address().toString();
return;
}
int batteryPercentage = m_batteryCharacteristic.value().toHex().toUInt(0, 16);
qCDebug(dcSenic()) << "Battery:" << batteryPercentage << "%";
// Enable notification
foreach (const QLowEnergyDescriptor &descriptor, m_batteryCharacteristic.descriptors()) {
qCDebug(dcSenic()) << descriptor.name() << descriptor.uuid().toString();
m_batteryService->writeDescriptor(descriptor, QByteArray::fromHex("0100"));
}
emit batteryValueChaged(batteryPercentage);
}
// Input
if (service == m_inputService) {
qCDebug(dcSenic()) << "Input service discovered";
// Button
m_inputButtonCharacteristic = m_inputService->characteristic(QBluetoothUuid(QUuid("F29B1529-CB19-40F3-BE5C-7241ECB82FD2")));
if (!m_inputButtonCharacteristic.isValid()) {
qCWarning(dcSenic()) << "Button characteristc not valid for device " << name() << address().toString();
return;
}
foreach (const QLowEnergyDescriptor &descriptor, m_inputButtonCharacteristic.descriptors()) {
qCDebug(dcSenic()) << descriptor.name() << descriptor.uuid().toString();
m_inputService->writeDescriptor(descriptor, QByteArray::fromHex("0100"));
}
// Swipe
m_inputSwipeCharacteristic = m_inputService->characteristic(QBluetoothUuid(QUuid("F29B1527-CB19-40F3-BE5C-7241ECB82FD2")));
if (!m_inputSwipeCharacteristic.isValid()) {
qCWarning(dcSenic()) << "Swipe characteristc not valid for device " << name() << address().toString();
return;
}
foreach (const QLowEnergyDescriptor &descriptor, m_inputSwipeCharacteristic.descriptors()) {
qCDebug(dcSenic()) << descriptor.name() << descriptor.uuid().toString();
m_inputService->writeDescriptor(descriptor, QByteArray::fromHex("0100"));
}
// Swipe
m_inputRotationCharacteristic = m_inputService->characteristic(QBluetoothUuid(QUuid("F29B1528-CB19-40F3-BE5C-7241ECB82FD2")));
if (!m_inputRotationCharacteristic.isValid()) {
qCWarning(dcSenic()) << "Rotation characteristc not valid for device " << name() << address().toString();
return;
}
foreach (const QLowEnergyDescriptor &descriptor, m_inputRotationCharacteristic.descriptors()) {
qCDebug(dcSenic()) << descriptor.name() << descriptor.uuid().toString();
m_inputService->writeDescriptor(descriptor, QByteArray::fromHex("0100"));
}
}
// Led Matrix
if (service == m_ledMatrixService) {
qCDebug(dcSenic()) << "Led matrix service discovered";
m_ledMatrixCharacteristic = m_ledMatrixService->characteristic(QBluetoothUuid(QUuid("F29B1524-CB19-40F3-BE5C-7241ECB82FD1")));
if (!m_ledMatrixCharacteristic.isValid()) {
qCWarning(dcSenic()) << "Led matrix characteristc not found for device " << name() << address().toString();
return;
}
showGuhLogo();
}
break;
default:
break;
}
}
void Nuimo::serviceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
{ {
if (characteristic.uuid() == m_batteryCharacteristic.uuid()) { if (characteristic.uuid() == m_batteryCharacteristic.uuid()) {
uint batteryValue = value.toHex().toUInt(0, 16); setBatteryValue(value);
qCDebug(dcSenic()) << "Battery:" << batteryValue; }
emit batteryValueChaged(batteryValue); }
void Nuimo::onInputServiceStateChanged(const QLowEnergyService::ServiceState &state)
{
// Only continue if discovered
if (state != QLowEnergyService::ServiceDiscovered)
return;
qCDebug(dcSenic()) << "Input service discovered.";
printService(m_inputService);
// Button
m_inputButtonCharacteristic = m_inputService->characteristic(inputButtonCharacteristicUuid);
if (!m_inputButtonCharacteristic.isValid()) {
qCWarning(dcSenic()) << "Input button characteristc not found for device " << bluetoothDevice()->name() << bluetoothDevice()->address().toString();
return; return;
} }
// Enable notifications
QLowEnergyDescriptor notificationDescriptor = m_inputButtonCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
m_inputService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100"));
// Swipe
m_inputSwipeCharacteristic = m_inputService->characteristic(inputSwipeCharacteristicUuid);
if (!m_inputSwipeCharacteristic.isValid()) {
qCWarning(dcSenic()) << "Input swipe characteristc not found for device " << bluetoothDevice()->name() << bluetoothDevice()->address().toString();
return;
}
// Enable notifications
notificationDescriptor = m_inputSwipeCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
m_inputService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100"));
// Rotation
m_inputRotationCharacteristic = m_inputService->characteristic(inputRotationCharacteristicUuid);
if (!m_inputRotationCharacteristic.isValid()) {
qCWarning(dcSenic()) << "Input rotation characteristc not found for device " << bluetoothDevice()->name() << bluetoothDevice()->address().toString();
return;
}
// Enable notifications
notificationDescriptor = m_inputRotationCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
m_inputService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100"));
}
void Nuimo::onInputCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
{
if (characteristic.uuid() == m_inputButtonCharacteristic.uuid()) { if (characteristic.uuid() == m_inputButtonCharacteristic.uuid()) {
bool pressed = (bool)value.toHex().toUInt(0, 16); bool pressed = (bool)value.toHex().toUInt(0, 16);
qCDebug(dcSenic()) << "Button:" << (pressed ? "pressed": "released"); qCDebug(dcSenic()) << "Button:" << (pressed ? "pressed": "released");
@ -397,57 +396,23 @@ void Nuimo::serviceCharacteristicChanged(const QLowEnergyCharacteristic &charact
return; return;
} }
qCDebug(dcSenic()) << "Service characteristic changed" << characteristic.name() << value.toHex(); qCDebug(dcSenic()) << "Service characteristic changed" << characteristic.name() << value.toHex();
} }
void Nuimo::confirmedCharacteristicWritten(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) void Nuimo::onLedMatrixServiceStateChanged(const QLowEnergyService::ServiceState &state)
{ {
qCDebug(dcSenic()) << characteristic.name() << value; // Only continue if discovered
} if (state != QLowEnergyService::ServiceDiscovered)
return;
void Nuimo::confirmedDescriptorWritten(const QLowEnergyDescriptor &descriptor, const QByteArray &value) qCDebug(dcSenic()) << "Led matrix service discovered.";
{
qCDebug(dcSenic()) << "Descriptor:" << descriptor.name() << "value:" << value.toHex() << "written successfully";
}
void Nuimo::serviceError(const QLowEnergyService::ServiceError &error) printService(m_ledMatrixService);
{
QString errorString; // Led matrix
switch (error) { m_ledMatrixCharacteristic = m_ledMatrixService->characteristic(ledMatrixCharacteristicUuid);
case QLowEnergyService::NoError: if (!m_ledMatrixCharacteristic.isValid()) {
errorString = "No error"; qCWarning(dcSenic()) << "Led matrix characteristc not found for device " << bluetoothDevice()->name() << bluetoothDevice()->address().toString();
break; return;
case QLowEnergyService::OperationError:
errorString = "Operation error";
break;
#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
case QLowEnergyService::CharacteristicReadError:
errorString = "Characteristic read error";
break;
#endif
case QLowEnergyService::CharacteristicWriteError:
errorString = "Characteristic write error";
break;
#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
case QLowEnergyService::DescriptorReadError:
errorString = "Descriptor read error";
break;
#endif
case QLowEnergyService::DescriptorWriteError:
errorString = "Descriptor write error";
break;
#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
case QLowEnergyService::UnknownError:
errorString = "Unknown error";
break;
#endif
default:
errorString = "Unknown error";
break;
} }
qCWarning(dcSenic()) << "Service error of" << name() << address().toString() << ":" << errorString;
} }
#endif // BLUETOOTH_LE

View File

@ -23,15 +23,14 @@
#ifndef NUIMO_H #ifndef NUIMO_H
#define NUIMO_H #define NUIMO_H
#ifdef BLUETOOTH_LE
#include <QObject> #include <QObject>
#include <QBluetoothUuid> #include <QBluetoothUuid>
#include "typeutils.h" #include "typeutils.h"
#include "bluetooth/bluetoothlowenergydevice.h" #include "plugin/device.h"
#include "hardware/bluetoothlowenergy/bluetoothlowenergydevice.h"
class Nuimo : public BluetoothLowEnergyDevice class Nuimo : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
@ -42,19 +41,23 @@ public:
SwipeDirectionDown SwipeDirectionDown
}; };
explicit Nuimo(const QBluetoothDeviceInfo &deviceInfo, const QLowEnergyController::RemoteAddressType &addressType, QObject *parent = 0); explicit Nuimo(Device *device, BluetoothLowEnergyDevice *bluetoothDevice, QObject *parent = nullptr);
bool isAvailable(); Device *device();
BluetoothLowEnergyDevice *bluetoothDevice();
void showGuhLogo(); void showGuhLogo();
void showArrowUp(); void showArrowUp();
void showArrowDown(); void showArrowDown();
private: private:
QLowEnergyService *m_deviceInfoService; Device *m_device = nullptr;
QLowEnergyService *m_batteryService; BluetoothLowEnergyDevice *m_bluetoothDevice = nullptr;
QLowEnergyService *m_inputService;
QLowEnergyService *m_ledMatrixService; QLowEnergyService *m_deviceInfoService = nullptr;
QLowEnergyService *m_batteryService = nullptr;
QLowEnergyService *m_inputService = nullptr;
QLowEnergyService *m_ledMatrixService = nullptr;
QLowEnergyCharacteristic m_deviceInfoCharacteristic; QLowEnergyCharacteristic m_deviceInfoCharacteristic;
QLowEnergyCharacteristic m_batteryCharacteristic; QLowEnergyCharacteristic m_batteryCharacteristic;
@ -63,12 +66,15 @@ private:
QLowEnergyCharacteristic m_inputSwipeCharacteristic; QLowEnergyCharacteristic m_inputSwipeCharacteristic;
QLowEnergyCharacteristic m_inputRotationCharacteristic; QLowEnergyCharacteristic m_inputRotationCharacteristic;
bool m_isAvailable;
uint m_rotationValue; uint m_rotationValue;
void registerService(QLowEnergyService *service);
void showMatrix(const QByteArray &matrix, const int &seconds); void showMatrix(const QByteArray &matrix, const int &seconds);
void printService(QLowEnergyService *service);
// Set states
void setBatteryValue(const QByteArray &data);
signals: signals:
void availableChanged(); void availableChanged();
void buttonPressed(); void buttonPressed();
@ -78,17 +84,19 @@ signals:
void rotationValueChanged(const uint &value); void rotationValueChanged(const uint &value);
private slots: private slots:
void serviceScanFinished(); void onConnectedChanged(const bool &connected);
void onConnectionStatusChanged(); void onServiceDiscoveryFinished();
void serviceStateChanged(const QLowEnergyService::ServiceState &state); void onDeviceInfoServiceStateChanged(const QLowEnergyService::ServiceState &state);
void serviceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value);
void confirmedCharacteristicWritten(const QLowEnergyCharacteristic &characteristic, const QByteArray &value); void onBatteryServiceStateChanged(const QLowEnergyService::ServiceState &state);
void confirmedDescriptorWritten(const QLowEnergyDescriptor &descriptor, const QByteArray &value); void onBatteryCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value);
void serviceError(const QLowEnergyService::ServiceError &error);
void onInputServiceStateChanged(const QLowEnergyService::ServiceState &state);
void onInputCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value);
void onLedMatrixServiceStateChanged(const QLowEnergyService::ServiceState &state);
}; };
#endif // BLUETOOTH_LE
#endif // NUIMO_H #endif // NUIMO_H