From cd2289563f87c723479d3c385027d3dc929738c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 12 Jan 2018 12:46:23 +0100 Subject: [PATCH] Migrate senic plugin --- debian/control | 17 ++ guh-plugins.pro | 2 +- senic/devicepluginsenic.cpp | 107 ++++---- senic/devicepluginsenic.h | 17 +- senic/devicepluginsenic.json | 40 ++- senic/nuimo.cpp | 467 ++++++++++++++++------------------- senic/nuimo.h | 50 ++-- 7 files changed, 351 insertions(+), 349 deletions(-) diff --git a/debian/control b/debian/control index d76907be..5be8fc63 100644 --- a/debian/control +++ b/debian/control @@ -446,6 +446,22 @@ Description: 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 Section: misc Architecture: all @@ -479,6 +495,7 @@ Depends: guh-plugin-awattar, guh-plugin-wakeonlan, guh-plugin-wemo, guh-plugin-elgato, + guh-plugin-senic Description: Plugins for guh IoT server - the default plugin collection The guh daemon is a plugin based IoT (Internet of Things) server. The server works like a translator for devices, things and services and diff --git a/guh-plugins.pro b/guh-plugins.pro index d9673735..2540de02 100644 --- a/guh-plugins.pro +++ b/guh-plugins.pro @@ -21,7 +21,7 @@ PLUGIN_DIRS = \ tcpcommander \ kodi \ elgato \ - #senic \ + senic \ awattar \ netatmo \ plantcare \ diff --git a/senic/devicepluginsenic.cpp b/senic/devicepluginsenic.cpp index 7e75fc21..d09d848e 100644 --- a/senic/devicepluginsenic.cpp +++ b/senic/devicepluginsenic.cpp @@ -37,18 +37,23 @@ \quotefile plugins/deviceplugins/senic/devicepluginsenic.json */ -#ifdef BLUETOOTH_LE - #include "devicepluginsenic.h" #include "plugin/device.h" #include "devicemanager.h" #include "plugininfo.h" +#include "hardware/bluetoothlowenergy/bluetoothlowenergymanager.h" 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 ¶ms) { Q_UNUSED(params) @@ -56,55 +61,46 @@ DeviceManager::DeviceError DevicePluginSenic::discoverDevices(const DeviceClassI if (deviceClassId != nuimoDeviceClassId) return DeviceManager::DeviceErrorDeviceClassNotFound; - if (!discoverBluetooth()) + if (!hardwareManager()->bluetoothLowEnergyManager()->available()) 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; } DeviceManager::DeviceSetupStatus DevicePluginSenic::setupDevice(Device *device) { + qCDebug(dcSenic()) << "Setup device" << device->name() << device->params(); + QString name = device->paramValue(nameParamTypeId).toString(); QBluetoothAddress address = QBluetoothAddress(device->paramValue(macParamTypeId).toString()); QBluetoothDeviceInfo deviceInfo = QBluetoothDeviceInfo(address, name, 0); - Nuimo *nuimo = new Nuimo(deviceInfo, QLowEnergyController::RandomAddress, this); - connect(nuimo, &Nuimo::availableChanged, this, &DevicePluginSenic::connectionAvailableChanged); - connect(nuimo, &Nuimo::batteryValueChaged, this, &DevicePluginSenic::onBatteryValueChanged); + BluetoothLowEnergyDevice *bluetoothDevice = hardwareManager()->bluetoothLowEnergyManager()->registerDevice(deviceInfo, QLowEnergyController::RandomAddress); + + Nuimo *nuimo = new Nuimo(device, bluetoothDevice, this); connect(nuimo, &Nuimo::buttonPressed, this, &DevicePluginSenic::onButtonPressed); connect(nuimo, &Nuimo::buttonReleased, this, &DevicePluginSenic::onButtonReleased); connect(nuimo, &Nuimo::swipeDetected, this, &DevicePluginSenic::onSwipeDetected); connect(nuimo, &Nuimo::rotationValueChanged, this, &DevicePluginSenic::onRotationValueChanged); m_nuimos.insert(nuimo, device); - - nuimo->connectDevice(); + nuimo->bluetoothDevice()->connectDevice(); return DeviceManager::DeviceSetupStatusSuccess; } -DeviceManager::HardwareResources DevicePluginSenic::requiredHardware() const -{ - return DeviceManager::HardwareResourceBluetoothLE; -} - DeviceManager::DeviceError DevicePluginSenic::executeAction(Device *device, const Action &action) { QPointer nuimo = m_nuimos.key(device); if (nuimo.isNull()) 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.param(logoParamTypeId).value().toString() == "Guh") @@ -122,25 +118,6 @@ DeviceManager::DeviceError DevicePluginSenic::executeAction(Device *device, cons return DeviceManager::DeviceErrorActionTypeNotFound; } -void DevicePluginSenic::bluetoothDiscoveryFinished(const QList &deviceInfos) -{ - QList 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) { if (!m_nuimos.values().contains(device)) @@ -161,20 +138,45 @@ bool DevicePluginSenic::verifyExistingDevices(const QBluetoothDeviceInfo &device return false; } -void DevicePluginSenic::connectionAvailableChanged() +void DevicePluginSenic::onReconnectTimeout() { - Nuimo *nuimo = static_cast(sender()); - Device *device = m_nuimos.value(nuimo); - device->setStateValue(availableStateTypeId, nuimo->isAvailable()); + foreach (Nuimo *nuimo, m_nuimos.keys()) { + if (!nuimo->bluetoothDevice()->connected()) { + nuimo->bluetoothDevice()->connectDevice(); + } + } } -void DevicePluginSenic::onBatteryValueChanged(const uint &percentage) +void DevicePluginSenic::onBluetoothDiscoveryFinished() { - Nuimo *nuimo = static_cast(sender()); - Device *device = m_nuimos.value(nuimo); - device->setStateValue(batteryStateTypeId, percentage); + BluetoothDiscoveryReply *reply = static_cast(sender()); + if (reply->error() != BluetoothDiscoveryReply::BluetoothDiscoveryReplyErrorNoError) { + qCWarning(dcSenic()) << "Bluetooth discovery error:" << reply->error(); + reply->deleteLater(); + emit devicesDiscovered(nuimoDeviceClassId, QList()); + return; + } + + + QList 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() { Nuimo *nuimo = static_cast(sender()); @@ -218,6 +220,3 @@ void DevicePluginSenic::onRotationValueChanged(const uint &value) } -#endif // BLUETOOTH_LE - - diff --git a/senic/devicepluginsenic.h b/senic/devicepluginsenic.h index 30f63e05..7ec1d49a 100644 --- a/senic/devicepluginsenic.h +++ b/senic/devicepluginsenic.h @@ -23,10 +23,9 @@ #ifndef DEVICEPLUGINELGATO_H #define DEVICEPLUGINELGATO_H -#ifdef BLUETOOTH_LE - +#include "plugintimer.h" #include "plugin/deviceplugin.h" -#include "bluetooth/bluetoothlowenergydevice.h" +#include "hardware/bluetoothlowenergy/bluetoothlowenergydevice.h" #include "nuimo.h" @@ -40,21 +39,23 @@ class DevicePluginSenic : public DevicePlugin public: explicit DevicePluginSenic(); + void init() override; 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 &deviceInfos); void deviceRemoved(Device *device) override; private: QHash m_nuimos; + PluginTimer *m_reconnectTimer = nullptr; + bool verifyExistingDevices(const QBluetoothDeviceInfo &deviceInfo); private slots: - void connectionAvailableChanged(); - void onBatteryValueChanged(const uint &percentage); + void onReconnectTimeout(); + void onBluetoothDiscoveryFinished(); + void onButtonPressed(); void onButtonReleased(); void onSwipeDetected(const Nuimo::SwipeDirection &direction); @@ -62,6 +63,4 @@ private slots: }; -#endif // BLUETOOTH_LE - #endif // DEVICEPLUGINELGATO_H diff --git a/senic/devicepluginsenic.json b/senic/devicepluginsenic.json index 8212d464..3a99e4d5 100644 --- a/senic/devicepluginsenic.json +++ b/senic/devicepluginsenic.json @@ -37,12 +37,36 @@ "stateTypes": [ { "id": "5286976a-f5dc-4662-872a-438ac5d491cb", - "idName": "available", - "name": "available", - "eventTypeName": "available changed", + "idName": "connected", + "name": "Connected", + "eventTypeName": "Connected changed", "type": "bool", "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", "idName": "battery", @@ -67,16 +91,6 @@ } ], "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", "idName": "showLogo", diff --git a/senic/nuimo.cpp b/senic/nuimo.cpp index 3f2c4d72..89a51d06 100644 --- a/senic/nuimo.cpp +++ b/senic/nuimo.cpp @@ -20,29 +20,38 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifdef BLUETOOTH_LE - #include "nuimo.h" #include "extern-plugininfo.h" #include -#include +#include -Nuimo::Nuimo(const QBluetoothDeviceInfo &deviceInfo, const QLowEnergyController::RemoteAddressType &addressType, QObject *parent) : - BluetoothLowEnergyDevice(deviceInfo, addressType, parent), - m_deviceInfoService(NULL), - m_batteryService(NULL), - m_inputService(NULL), - m_ledMatrixService(NULL), - m_isAvailable(false) +static QBluetoothUuid ledMatrinxServiceUuid = QBluetoothUuid(QUuid("f29b1523-cb19-40f3-be5c-7241ecb82fd1")); +static QBluetoothUuid ledMatrixCharacteristicUuid = QBluetoothUuid(QUuid("f29b1524-cb19-40f3-be5c-7241ecb82fd1")); + +static QBluetoothUuid inputServiceUuid = QBluetoothUuid(QUuid("f29b1525-cb19-40f3-be5c-7241ecb82fd2")); +static QBluetoothUuid inputSwipeCharacteristicUuid = QBluetoothUuid(QUuid("f29b1527-cb19-40f3-be5c-7241ecb82fd2")); +static QBluetoothUuid inputRotationCharacteristicUuid = QBluetoothUuid(QUuid("f29b1528-cb19-40f3-be5c-7241ecb82fd2")); +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(this, SIGNAL(servicesDiscoveryFinished()), this, SLOT(serviceScanFinished())); + connect(m_bluetoothDevice, &BluetoothLowEnergyDevice::connectedChanged, this, &Nuimo::onConnectedChanged); + 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() @@ -93,19 +102,11 @@ void Nuimo::showArrowDown() 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) { + if (!m_ledMatrixService) + return; + QBitArray bits; bits.resize(81); 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); } - -void Nuimo::serviceScanFinished() +void Nuimo::printService(QLowEnergyService *service) { - QBluetoothUuid deviceInfoUuid(QUuid("0000180A-0000-1000-8000-00805F9B34FB")); - QBluetoothUuid batteryUuid(QUuid("0000180F-0000-1000-8000-00805F9B34FB")); - QBluetoothUuid inputUuid(QUuid("F29B1525-CB19-40F3-BE5C-7241ECB82FD2")); - QBluetoothUuid ledMatrixUuid(QUuid("F29B1523-CB19-40F3-BE5C-7241ECB82FD1")); + foreach (const QLowEnergyCharacteristic &characteristic, service->characteristics()) { + qCDebug(dcSenic()) << " -->" << characteristic.name() << characteristic.uuid().toString() << characteristic.value(); + foreach (const QLowEnergyDescriptor &desciptor, characteristic.descriptors()) { + 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"; - if (!controller()->services().contains(deviceInfoUuid)) { - qCWarning(dcSenic()) << "Device Information service not found for device" << name() << address().toString(); + if (!m_bluetoothDevice->serviceUuids().contains(QBluetoothUuid::DeviceInformation)) { + qCWarning(dcSenic()) << "Device Information service not found for device" << bluetoothDevice()->name() << bluetoothDevice()->address().toString(); return; } - if (!controller()->services().contains(batteryUuid)) { - qCWarning(dcSenic()) << "Battery service not found for device" << name() << address().toString(); + if (!m_bluetoothDevice->serviceUuids().contains(QBluetoothUuid::BatteryService)) { + qCWarning(dcSenic()) << "Battery service not found for device" << bluetoothDevice()->name() << bluetoothDevice()->address().toString(); return; } - if (!controller()->services().contains(ledMatrixUuid)) { - qCWarning(dcSenic()) << "Led matrix service not found for device" << name() << address().toString(); + if (!m_bluetoothDevice->serviceUuids().contains(ledMatrinxServiceUuid)) { + qCWarning(dcSenic()) << "Led matrix service not found for device" << bluetoothDevice()->name() << bluetoothDevice()->address().toString(); return; } - if (!controller()->services().contains(inputUuid)) { - qCWarning(dcSenic()) << "Input service not found for device" << name() << address().toString(); + if (!m_bluetoothDevice->serviceUuids().contains(inputServiceUuid)) { + qCWarning(dcSenic()) << "Input service not found for device" << bluetoothDevice()->name() << bluetoothDevice()->address().toString(); return; } - m_isAvailable = true; - emit availableChanged(); - - // Device information - m_deviceInfoService = controller()->createServiceObject(deviceInfoUuid, this); + // Device info service if (!m_deviceInfoService) { - qCWarning(dcSenic()) << "Could not create device information service for device" << name() << address().toString(); - return; + m_deviceInfoService = m_bluetoothDevice->controller()->createServiceObject(QBluetoothUuid::DeviceInformation, this); + 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 - m_batteryService = controller()->createServiceObject(batteryUuid, this); if (!m_batteryService) { - qCWarning(dcSenic()) << "Could not create battery service for device" << name() << address().toString(); - return; + m_batteryService = m_bluetoothDevice->controller()->createServiceObject(QBluetoothUuid::BatteryService, this); + 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 - m_inputService = controller()->createServiceObject(inputUuid, this); if (!m_inputService) { - qCWarning(dcSenic()) << "Could not create input service for device" << name() << address().toString(); - return; + m_inputService = m_bluetoothDevice->controller()->createServiceObject(inputServiceUuid, this); + 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 - m_ledMatrixService = controller()->createServiceObject(ledMatrixUuid, this); + // Input service 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; } - registerService(m_deviceInfoService); - registerService(m_batteryService); - registerService(m_inputService); - registerService(m_ledMatrixService); + // Enable notifications + QLowEnergyDescriptor notificationDescriptor = m_batteryCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration); + m_batteryService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100")); + setBatteryValue(m_batteryCharacteristic.value()); } -void Nuimo::onConnectionStatusChanged() -{ - 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(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) +void Nuimo::onBatteryCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) { if (characteristic.uuid() == m_batteryCharacteristic.uuid()) { - uint batteryValue = value.toHex().toUInt(0, 16); - qCDebug(dcSenic()) << "Battery:" << batteryValue; - emit batteryValueChaged(batteryValue); + setBatteryValue(value); + } +} + +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; } + // 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()) { bool pressed = (bool)value.toHex().toUInt(0, 16); qCDebug(dcSenic()) << "Button:" << (pressed ? "pressed": "released"); @@ -397,57 +396,23 @@ void Nuimo::serviceCharacteristicChanged(const QLowEnergyCharacteristic &charact return; } - 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()) << "Descriptor:" << descriptor.name() << "value:" << value.toHex() << "written successfully"; -} + qCDebug(dcSenic()) << "Led matrix service discovered."; -void Nuimo::serviceError(const QLowEnergyService::ServiceError &error) -{ - QString errorString; - switch (error) { - case QLowEnergyService::NoError: - errorString = "No error"; - break; - 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; + printService(m_ledMatrixService); + + // Led matrix + m_ledMatrixCharacteristic = m_ledMatrixService->characteristic(ledMatrixCharacteristicUuid); + if (!m_ledMatrixCharacteristic.isValid()) { + qCWarning(dcSenic()) << "Led matrix characteristc not found for device " << bluetoothDevice()->name() << bluetoothDevice()->address().toString(); + return; } - - qCWarning(dcSenic()) << "Service error of" << name() << address().toString() << ":" << errorString; } - -#endif // BLUETOOTH_LE diff --git a/senic/nuimo.h b/senic/nuimo.h index 59e5613b..6f003417 100644 --- a/senic/nuimo.h +++ b/senic/nuimo.h @@ -23,15 +23,14 @@ #ifndef NUIMO_H #define NUIMO_H -#ifdef BLUETOOTH_LE - #include #include #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 public: @@ -42,19 +41,23 @@ public: 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 showArrowUp(); void showArrowDown(); private: - QLowEnergyService *m_deviceInfoService; - QLowEnergyService *m_batteryService; - QLowEnergyService *m_inputService; - QLowEnergyService *m_ledMatrixService; + Device *m_device = nullptr; + BluetoothLowEnergyDevice *m_bluetoothDevice = nullptr; + + QLowEnergyService *m_deviceInfoService = nullptr; + QLowEnergyService *m_batteryService = nullptr; + QLowEnergyService *m_inputService = nullptr; + QLowEnergyService *m_ledMatrixService = nullptr; QLowEnergyCharacteristic m_deviceInfoCharacteristic; QLowEnergyCharacteristic m_batteryCharacteristic; @@ -63,12 +66,15 @@ private: QLowEnergyCharacteristic m_inputSwipeCharacteristic; QLowEnergyCharacteristic m_inputRotationCharacteristic; - bool m_isAvailable; uint m_rotationValue; - void registerService(QLowEnergyService *service); void showMatrix(const QByteArray &matrix, const int &seconds); + void printService(QLowEnergyService *service); + + // Set states + void setBatteryValue(const QByteArray &data); + signals: void availableChanged(); void buttonPressed(); @@ -78,17 +84,19 @@ signals: void rotationValueChanged(const uint &value); private slots: - void serviceScanFinished(); - void onConnectionStatusChanged(); + void onConnectedChanged(const bool &connected); + void onServiceDiscoveryFinished(); - void serviceStateChanged(const QLowEnergyService::ServiceState &state); - void serviceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value); - void confirmedCharacteristicWritten(const QLowEnergyCharacteristic &characteristic, const QByteArray &value); - void confirmedDescriptorWritten(const QLowEnergyDescriptor &descriptor, const QByteArray &value); - void serviceError(const QLowEnergyService::ServiceError &error); + void onDeviceInfoServiceStateChanged(const QLowEnergyService::ServiceState &state); + + void onBatteryServiceStateChanged(const QLowEnergyService::ServiceState &state); + void onBatteryCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value); + + 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