baisc functionality of nuimo
This commit is contained in:
parent
0bfd8b27f9
commit
699495dcc0
@ -27,4 +27,5 @@ SUBDIRS += elro \
|
|||||||
orderbutton \
|
orderbutton \
|
||||||
denon \
|
denon \
|
||||||
avahimonitor \
|
avahimonitor \
|
||||||
|
senic \
|
||||||
|
|
||||||
|
|||||||
332
plugins/deviceplugins/senic/nuimo.cpp
Normal file
332
plugins/deviceplugins/senic/nuimo.cpp
Normal file
@ -0,0 +1,332 @@
|
|||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2016 Simon Stürz <simon.stuerz@guh.guru> *
|
||||||
|
* *
|
||||||
|
* 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/>. *
|
||||||
|
* *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
#ifdef BLUETOOTH_LE
|
||||||
|
|
||||||
|
#include "nuimo.h"
|
||||||
|
#include "extern-plugininfo.h"
|
||||||
|
|
||||||
|
#include <QBitArray>
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
connect(this, SIGNAL(connectionStatusChanged()), this,SLOT(onConnectionStatusChanged()));
|
||||||
|
connect(this, SIGNAL(servicesDiscoveryFinished()), this, SLOT(serviceScanFinished()));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Nuimo::isAvailable()
|
||||||
|
{
|
||||||
|
return m_isAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Nuimo::showGuhLogo()
|
||||||
|
{
|
||||||
|
QByteArray matrix(
|
||||||
|
" "
|
||||||
|
" * "
|
||||||
|
" ** ** "
|
||||||
|
" **** "
|
||||||
|
" ** "
|
||||||
|
" * "
|
||||||
|
" * "
|
||||||
|
" * "
|
||||||
|
" ");
|
||||||
|
|
||||||
|
QBitArray bits;
|
||||||
|
bits.resize(81);
|
||||||
|
for (int i = 0; i < matrix.size(); i++) {
|
||||||
|
if (matrix.at(i) != ' ') {
|
||||||
|
bits[i] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray bytes;
|
||||||
|
bytes.resize(bits.count() / 8+1);
|
||||||
|
bytes.fill(0);
|
||||||
|
// Convert from QBitArray to QByteArray
|
||||||
|
for(int b = 0; b < bits.count(); ++b)
|
||||||
|
bytes[b / 8] = (bytes.at(b / 8) | ((bits[b] ? 1 : 0) << (b % 8)));
|
||||||
|
|
||||||
|
bytes.append(QByteArray::fromHex("FF"));
|
||||||
|
bytes.append(QByteArray::fromHex("AA"));
|
||||||
|
|
||||||
|
m_ledMatrixService->writeCharacteristic(m_ledMatrixCharacteristic, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
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::serviceScanFinished()
|
||||||
|
{
|
||||||
|
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"));
|
||||||
|
|
||||||
|
qCDebug(dcSenic()) << "Service scan finised";
|
||||||
|
|
||||||
|
if (!controller()->services().contains(deviceInfoUuid)) {
|
||||||
|
qCWarning(dcSenic()) << "Device Information service not found for device" << name() << address().toString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!controller()->services().contains(batteryUuid)) {
|
||||||
|
qCWarning(dcSenic()) << "Battery service not found for device" << name() << address().toString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!controller()->services().contains(ledMatrixUuid)) {
|
||||||
|
qCWarning(dcSenic()) << "Led matrix service not found for device" << name() << address().toString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!controller()->services().contains(inputUuid)) {
|
||||||
|
qCWarning(dcSenic()) << "Input service not found for device" << name() << address().toString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_isAvailable = true;
|
||||||
|
emit availableChanged();
|
||||||
|
|
||||||
|
// Device information
|
||||||
|
m_deviceInfoService = controller()->createServiceObject(deviceInfoUuid, this);
|
||||||
|
if (!m_deviceInfoService) {
|
||||||
|
qCWarning(dcSenic()) << "Could not create device information service for device" << name() << address().toString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Battery service
|
||||||
|
m_batteryService = controller()->createServiceObject(batteryUuid, this);
|
||||||
|
if (!m_batteryService) {
|
||||||
|
qCWarning(dcSenic()) << "Could not create battery service for device" << name() << address().toString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input service
|
||||||
|
m_inputService = controller()->createServiceObject(inputUuid, this);
|
||||||
|
if (!m_inputService) {
|
||||||
|
qCWarning(dcSenic()) << "Could not create input service for device" << name() << address().toString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Led Matrix
|
||||||
|
m_ledMatrixService = controller()->createServiceObject(ledMatrixUuid, this);
|
||||||
|
if (!m_ledMatrixService) {
|
||||||
|
qCWarning(dcSenic()) << "Could not create led matrix service for device" << name() << address().toString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerService(m_deviceInfoService);
|
||||||
|
registerService(m_batteryService);
|
||||||
|
registerService(m_inputService);
|
||||||
|
registerService(m_ledMatrixService);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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<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_inputService) {
|
||||||
|
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";
|
||||||
|
m_inputButtonCharacteristic = m_inputService->characteristic(QBluetoothUuid(QUuid("F29B1529-CB19-40F3-BE5C-7241ECB82FD2")));
|
||||||
|
if (!m_inputButtonCharacteristic.isValid()) {
|
||||||
|
qCWarning(dcSenic()) << "Button characteristc not found 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"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input
|
||||||
|
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()) {
|
||||||
|
uint batteryValue = value.toHex().toUInt(0, 16);
|
||||||
|
qCDebug(dcSenic()) << "Battery:" << batteryValue;
|
||||||
|
emit batteryValueChaged(batteryValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (characteristic.uuid() == m_inputButtonCharacteristic.uuid()) {
|
||||||
|
bool pressed = (bool)value.toHex().toUInt(0, 16);
|
||||||
|
qCDebug(dcSenic()) << "Button:" << (pressed ? "pressed": "released");
|
||||||
|
if (pressed) {
|
||||||
|
emit buttonPressed();
|
||||||
|
} else {
|
||||||
|
emit buttonReleased();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(dcSenic()) << "Service characteristic changed" << characteristic.name() << value.toHex();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Nuimo::confirmedCharacteristicWritten(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
|
||||||
|
{
|
||||||
|
qCDebug(dcSenic()) << characteristic.name() << value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Nuimo::confirmedDescriptorWritten(const QLowEnergyDescriptor &descriptor, const QByteArray &value)
|
||||||
|
{
|
||||||
|
qCDebug(dcSenic()) << "Descriptor:" << descriptor.name() << "value:" << value.toHex() << "written successfully";
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
case QLowEnergyService::CharacteristicWriteError:
|
||||||
|
errorString = "Characteristic write error";
|
||||||
|
break;
|
||||||
|
case QLowEnergyService::DescriptorWriteError:
|
||||||
|
errorString = "Descriptor write error";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCWarning(dcSenic()) << "Service of " << name() << address().toString() << ":" << errorString;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // BLUETOOTH_LE
|
||||||
77
plugins/deviceplugins/senic/nuimo.h
Normal file
77
plugins/deviceplugins/senic/nuimo.h
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2016 Simon Stürz <simon.stuerz@guh.guru> *
|
||||||
|
* *
|
||||||
|
* 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 NUIMO_H
|
||||||
|
#define NUIMO_H
|
||||||
|
|
||||||
|
#ifdef BLUETOOTH_LE
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QBluetoothUuid>
|
||||||
|
|
||||||
|
#include "typeutils.h"
|
||||||
|
#include "bluetooth/bluetoothlowenergydevice.h"
|
||||||
|
|
||||||
|
class Nuimo : public BluetoothLowEnergyDevice
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit Nuimo(const QBluetoothDeviceInfo &deviceInfo, const QLowEnergyController::RemoteAddressType &addressType, QObject *parent = 0);
|
||||||
|
|
||||||
|
bool isAvailable();
|
||||||
|
|
||||||
|
void showGuhLogo();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QLowEnergyService *m_deviceInfoService;
|
||||||
|
QLowEnergyService *m_batteryService;
|
||||||
|
QLowEnergyService *m_inputService;
|
||||||
|
QLowEnergyService *m_ledMatrixService;
|
||||||
|
|
||||||
|
QLowEnergyCharacteristic m_deviceInfoCharacteristic;
|
||||||
|
QLowEnergyCharacteristic m_batteryCharacteristic;
|
||||||
|
QLowEnergyCharacteristic m_inputButtonCharacteristic;
|
||||||
|
QLowEnergyCharacteristic m_ledMatrixCharacteristic;
|
||||||
|
|
||||||
|
bool m_isAvailable;
|
||||||
|
|
||||||
|
void registerService(QLowEnergyService *service);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void availableChanged();
|
||||||
|
void buttonPressed();
|
||||||
|
void buttonReleased();
|
||||||
|
void batteryValueChaged(const uint &percentage);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void serviceScanFinished();
|
||||||
|
void onConnectionStatusChanged();
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BLUETOOTH_LE
|
||||||
|
|
||||||
|
#endif // NUIMO_H
|
||||||
Reference in New Issue
Block a user