mirror of https://github.com/nymea/nymea.git
baisc functionality of nuimo
parent
0bfd8b27f9
commit
699495dcc0
|
|
@ -27,4 +27,5 @@ SUBDIRS += elro \
|
|||
orderbutton \
|
||||
denon \
|
||||
avahimonitor \
|
||||
senic \
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
Loading…
Reference in New Issue