Rework multisensor plugin

This commit is contained in:
Simon Stürz 2017-11-28 20:23:23 +01:00
parent 3e7d72c0d3
commit 0198bc91c1
9 changed files with 874 additions and 394 deletions

View File

@ -32,7 +32,7 @@ PLUGIN_DIRS = \
pushbullet \
usbwde \
#senic \
#multisensor \
multisensor \
gpio \

View File

@ -44,17 +44,20 @@
#include "plugininfo.h"
#include "devicemanager.h"
#include "bluetooth/bluetoothlowenergydevice.h"
#include "bluetooth/bluetoothlowenergymanager.h"
#include "devicepluginmultisensor.h"
// http://processors.wiki.ti.com/index.php/SensorTag_User_Guide
DevicePluginMultiSensor::DevicePluginMultiSensor()
{
}
DeviceManager::HardwareResources DevicePluginMultiSensor::requiredHardware() const
void DevicePluginMultiSensor::init()
{
return DeviceManager::HardwareResourceBluetoothLE;
m_measureTimer = hardwareManager()->pluginTimerManager()->registerTimer(60);
connect(m_measureTimer, &PluginTimer::timeout, this, &DevicePluginMultiSensor::onPluginTimer);
}
DeviceManager::DeviceError DevicePluginMultiSensor::discoverDevices(const DeviceClassId &deviceClassId, const ParamList &params)
@ -64,48 +67,35 @@ DeviceManager::DeviceError DevicePluginMultiSensor::discoverDevices(const Device
if (deviceClassId != sensortagDeviceClassId)
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, &DevicePluginMultiSensor::onBluetoothDiscoveryFinished);
return DeviceManager::DeviceErrorAsync;
}
void DevicePluginMultiSensor::bluetoothDiscoveryFinished(const QList<QBluetoothDeviceInfo> &deviceInfos)
{
QList<DeviceDescriptor> deviceDescriptors;
foreach (auto deviceInfo, deviceInfos) {
if (deviceInfo.name().contains("SensorTag")) {
if (!verifyExistingDevices(deviceInfo)) {
DeviceDescriptor descriptor(sensortagDeviceClassId, "SensorTag", 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(sensortagDeviceClassId, deviceDescriptors);
}
DeviceManager::DeviceSetupStatus DevicePluginMultiSensor::setupDevice(Device *device)
{
qCDebug(dcMultiSensor) << "Setting up MultiSensor" << device->name() << device->params();
qCDebug(dcMultiSensor) << "Setting up Multi Sensor" << device->name() << device->params();
if (device->deviceClassId() == sensortagDeviceClassId) {
auto address = QBluetoothAddress(device->paramValue(macParamTypeId).toString());
auto name = device->paramValue(nameParamTypeId).toString();
auto deviceInfo = QBluetoothDeviceInfo(address, name, 0);
QSharedPointer<SensorTag> tag{new SensorTag(deviceInfo, QLowEnergyController::PublicAddress, this)};
connect(tag.data(), &SensorTag::valueChanged, this,
[device, this](StateTypeId state, QVariant value) { device->setStateValue(state, value); });
connect(tag.data(), &SensorTag::event, this,
[device, this](EventTypeId event) { emit emitEvent(Event(event, device->id())); });
m_tags.insert(tag, device);
QBluetoothAddress address = QBluetoothAddress(device->paramValue(macParamTypeId).toString());
QString name = device->paramValue(nameParamTypeId).toString();
QBluetoothDeviceInfo deviceInfo = QBluetoothDeviceInfo(address, name, 0);
tag->connectDevice();
BluetoothLowEnergyDevice *bluetoothDevice = hardwareManager()->bluetoothLowEnergyManager()->registerDevice(deviceInfo, QLowEnergyController::PublicAddress);
SensorTag *sensor = new SensorTag(device, bluetoothDevice, this);
connect(sensor, &SensorTag::leftKeyPressed, this, &DevicePluginMultiSensor::onSensorLeftButtonPressed);
connect(sensor, &SensorTag::rightKeyPressed, this, &DevicePluginMultiSensor::onSensorRightButtonPressed);
m_sensors.insert(device, sensor);
sensor->bluetoothDevice()->connectDevice();
return DeviceManager::DeviceSetupStatusSuccess;
}
@ -115,16 +105,18 @@ DeviceManager::DeviceSetupStatus DevicePluginMultiSensor::setupDevice(Device *de
void DevicePluginMultiSensor::deviceRemoved(Device *device)
{
if (!m_tags.values().contains(device))
if (!m_sensors.contains(device))
return;
auto tag= m_tags.key(device);
m_tags.remove(tag);
SensorTag *sensor = m_sensors.value(device);
m_sensors.remove(device);
hardwareManager()->bluetoothLowEnergyManager()->unregisterDevice(sensor->bluetoothDevice());
sensor->deleteLater();
}
bool DevicePluginMultiSensor::verifyExistingDevices(const QBluetoothDeviceInfo &deviceInfo)
{
foreach (Device *device, myDevices()) {
foreach (Device *device, m_sensors.keys()) {
if (device->paramValue(macParamTypeId).toString() == deviceInfo.address().toString())
return true;
}
@ -132,4 +124,51 @@ bool DevicePluginMultiSensor::verifyExistingDevices(const QBluetoothDeviceInfo &
return false;
}
void DevicePluginMultiSensor::onPluginTimer()
{
foreach (SensorTag *sensor, m_sensors) {
sensor->measure();
}
}
void DevicePluginMultiSensor::onSensorLeftButtonPressed()
{
SensorTag *sensor = static_cast<SensorTag *>(sender());
emit emitEvent(Event(leftKeyEventTypeId, sensor->device()->id()));
}
void DevicePluginMultiSensor::onSensorRightButtonPressed()
{
SensorTag *sensor = static_cast<SensorTag *>(sender());
emit emitEvent(Event(rightKeyEventTypeId, sensor->device()->id()));
}
void DevicePluginMultiSensor::onBluetoothDiscoveryFinished()
{
BluetoothDiscoveryReply *reply = static_cast<BluetoothDiscoveryReply *>(sender());
if (reply->error() != BluetoothDiscoveryReply::BluetoothDiscoveryReplyErrorNoError) {
qCWarning(dcMultiSensor()) << "Bluetooth discovery error:" << reply->error();
reply->deleteLater();
emit devicesDiscovered(sensortagDeviceClassId, QList<DeviceDescriptor>());
return;
}
QList<DeviceDescriptor> deviceDescriptors;
foreach (const QBluetoothDeviceInfo &deviceInfo, reply->discoveredDevices()) {
if (deviceInfo.name().contains("SensorTag")) {
if (!verifyExistingDevices(deviceInfo)) {
DeviceDescriptor descriptor(sensortagDeviceClassId, "Sensor Tag", 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(sensortagDeviceClassId, deviceDescriptors);
}
#endif // BLUETOOTH_LE

View File

@ -30,6 +30,7 @@
#include <QHash>
#include "plugin/deviceplugin.h"
#include "devicemanager.h"
#include "plugintimer.h"
#include "bluetooth/bluetoothlowenergydevice.h"
#include "sensortag.h"
@ -42,16 +43,24 @@ class DevicePluginMultiSensor : public DevicePlugin
public:
explicit DevicePluginMultiSensor();
DeviceManager::HardwareResources requiredHardware() const override;
void init() override;
DeviceManager::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const ParamList &params) override;
void bluetoothDiscoveryFinished(const QList<QBluetoothDeviceInfo> &deviceInfos) override;
DeviceManager::DeviceSetupStatus setupDevice(Device *device) override;
void deviceRemoved(Device *device) override;
private:
PluginTimer *m_measureTimer = nullptr;
QHash<Device *, SensorTag *> m_sensors;
bool verifyExistingDevices(const QBluetoothDeviceInfo &deviceInfo);
QHash<QSharedPointer<SensorTag>,QPointer<Device>> m_tags;
private slots:
void onPluginTimer();
void onSensorLeftButtonPressed();
void onSensorRightButtonPressed();
void onBluetoothDiscoveryFinished();
};
#endif // BLUETOOTH_LE

View File

@ -8,8 +8,10 @@ TARGET = $$qtLibraryTarget(guh_devicepluginmultisensor)
SOURCES += \
devicepluginmultisensor.cpp \
#sensortag-old.cpp \
sensortag.cpp
HEADERS += \
devicepluginmultisensor.h \
#sensortag-old.h \
sensortag.h

View File

@ -0,0 +1,337 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stürz <simon.stuerz@guh.io> *
* Copyright (C) 2016 nicc *
* *
* This file is part of guh. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifdef BLUETOOTH_LE
#include <QPointer>
#include <QLowEnergyService>
#include <QtMath>
#include "extern-plugininfo.h"
#include "sensortag-old.h"
SensorTag::SensorTag(const QBluetoothDeviceInfo &deviceInfo, const QLowEnergyController::RemoteAddressType &addressType, QObject *parent) :
BluetoothLowEnergyDevice(deviceInfo, addressType, parent)
{
connect(this, SIGNAL(connectionStatusChanged()), this,SLOT(onConnectionStatusChanged()));
connect(this, SIGNAL(servicesDiscoveryFinished()), this, SLOT(setupServices()));
}
double SensorTag::calculateMeanValue(const QList<double> &list)
{
double sum = 0;
foreach (const double &value, list)
sum += value;
return sum / list.count();
}
void SensorTag::setupServices()
{
foreach (auto id, m_services.keys()) {
if (!controller()->services().contains(id)) {
qCWarning(dcMultiSensor) << "Service not found for device" << name() << address().toString();
return;
}
if (m_services.value(id)) {
qCWarning(dcMultiSensor) << "Attention! bad implementation of service handling!!";
return;
}
qCDebug(dcMultiSensor) << "Setup service";
// service for temperature
QSharedPointer<QLowEnergyService> service{controller()->createServiceObject(id, this)};
if (service.isNull()) {
qCWarning(dcMultiSensor) << "Could not create service for device" << name() << address().toString();
return;
}
m_services.insert(id, service);
connect(service.data(), SIGNAL(error(QLowEnergyService::ServiceError)), this, SLOT(onServiceError(QLowEnergyService::ServiceError)));
connect(service.data(), &QLowEnergyService::stateChanged, this, &SensorTag::onServiceStateChanged);
connect(service.data(), &QLowEnergyService::characteristicChanged, this, &SensorTag::onServiceCharacteristicChanged);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
connect(service.data(), &QLowEnergyService::characteristicRead, this, &SensorTag::onServiceCharacteristicChanged);
#endif
service->discoverDetails();
}
}
void SensorTag::onConnectionStatusChanged()
{
if (!isConnected()) {
// delete the services, they need to be recreated and
// rediscovered once the device will be reconnected
foreach (QSharedPointer<QLowEnergyService> service, m_services)
service->deleteLater();
emit valueChanged(connectedStateTypeId, false);
} else {
emit valueChanged(connectedStateTypeId, true);
}
}
void SensorTag::onServiceStateChanged(const QLowEnergyService::ServiceState &state)
{
QPointer<QLowEnergyService> service = qobject_cast<QLowEnergyService *>(sender());
switch (state) {
case QLowEnergyService::DiscoveringServices:
qCDebug(dcMultiSensor) << "Start discovering service" << service->serviceUuid();
break;
case QLowEnergyService::ServiceDiscovered:
if (m_services.contains(service->serviceUuid())) {
qCDebug(dcMultiSensor) << "... service discovered.";
auto dataId = service->serviceUuid();
dataId.data1 += 1;
auto sensorCharacteristic = service->characteristic(dataId);
if (!sensorCharacteristic.isValid()) {
qCWarning(dcMultiSensor) << "Characteristic not found for device " << name() << address().toString();
break;
}
const auto notificationDescriptor = sensorCharacteristic.descriptor(
QBluetoothUuid::ClientCharacteristicConfiguration);
if (notificationDescriptor.isValid()) {
service->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100"));
qCDebug(dcMultiSensor) << "Measuring";
}
if (service->serviceUuid().data1 == 0xffe0)
break;
auto configId = service->serviceUuid();
configId.data1 += 2;
auto sensorConfig = service->characteristic(configId);
if (!sensorConfig.isValid()) {
qCWarning(dcMultiSensor) << "Characteristic not found for device " << name() << address().toString();
break;
}
if (service->serviceUuid().data1 == 0xf000aa50) {
service->writeCharacteristic(sensorConfig, QByteArray::fromHex("07"));
} else {
service->writeCharacteristic(sensorConfig, QByteArray::fromHex("01"));
}
if (service->serviceUuid().data1 == 0xf000aa40) {
service->writeCharacteristic(sensorConfig, QByteArray::fromHex("02"));
auto calibId = service->serviceUuid();
calibId.data1 += 3;
#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
service->readCharacteristic(service->characteristic(calibId));
#endif
}
// TODO: initialize the states with the current value
}
break;
default:
break;
}
}
inline quint16 buildUINT16(quint8 loByte, quint8 hiByte) {
return ((quint16)(((loByte) & 0x00FF) + (((hiByte) & 0x00FF) << 8)));
}
void SensorTag::onServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
{
qCDebug(dcMultiSensor) << "Service characteristic changed" << characteristic.uuid().toString() << value.toHex();
auto id = characteristic.uuid();
id.data1 -= 1;
switch (characteristic.uuid().data1) {
case 0xf000aa01: {
const quint16 *data = reinterpret_cast<const quint16 *>(value.constData());
qint16 rawTamb = data[1];
m_temperatureValues.append((double)rawTamb / 128);
if (m_temperatureValues.count() % 60 == 0) {
emit valueChanged(temperatureStateTypeId, calculateMeanValue(m_temperatureValues));
m_temperatureValues.clear();
}
qint16 Vobj2 = (double)data[0];
Vobj2 *= 0.00000015625;
double Tdie2 = ((double)rawTamb / 128) + 273.15;
const double S0 = 6.4E-14; // Calibration factor
const double a1 = 1.75E-3;
const double a2 = -1.678E-5;
const double b0 = -2.94E-5;
const double b1 = -5.7E-7;
const double b2 = 4.63E-9;
const double c2 = 13.4;
const double Tref = 298.15;
double S = S0*(1+a1*(Tdie2 - Tref)+a2*qPow((Tdie2 - Tref),2));
double Vos = b0 + b1*(Tdie2 - Tref) + b2*qPow((Tdie2 - Tref),2);
double fObj = (Vobj2 - Vos) + c2*qPow((Vobj2 - Vos),2);
double tObj = qPow(qPow(Tdie2,4) + (fObj/S),.25);
m_irTemperatureValues.append(tObj - 273.15);
if (m_irTemperatureValues.count() % 60 == 0) {
emit valueChanged(IRtemperatureStateTypeId, calculateMeanValue(m_irTemperatureValues));
m_irTemperatureValues.clear();
}
break;
}
case 0xf000aa11: {
// TODO: evaluate movement
// const qint8 *data = reinterpret_cast<const qint8 *>(value.constData());
// emit valueChanged(accelerationXStateTypeId, (double)data[0] / 64);
// emit valueChanged(accelerationYStateTypeId, (double)data[1] / 64);
// emit valueChanged(accelerationZStateTypeId, (double)data[2] / 64);
break;
}
case 0xf000aa21: {
const quint16 *data = reinterpret_cast<const quint16 *>(value.constData());
quint16 rawH = data[1];
rawH &= ~0x0003;
m_humidityValues.append(-6.0 + 125.0/65536 * (double)rawH);
if (m_humidityValues.count() % 60 == 0) {
emit valueChanged(humidityStateTypeId, calculateMeanValue(m_humidityValues));
m_humidityValues.clear();
}
break;
}
case 0xf000aa31: {
// TODO: evaluate movement
// const qint16 *data = reinterpret_cast<const qint16 *>(value.constData());
// emit valueChanged(magneticFieldXStateTypeId, (double)data[0] / 32.768);
// emit valueChanged(magneticFieldYStateTypeId, (double)data[1] / 32.768);
// emit valueChanged(magneticFieldZStateTypeId, (double)data[2] / 32.768);
break;
}
case 0xf000aa41: {
if (m_c.empty())
break;
const quint16 *data = reinterpret_cast<const quint16 *>(value.constData());
quint16 Pr = data[1];
qint16 Tr = data[0];
// Sensitivity
qint64 s = (qint64)m_c[2];
qint64 val = (qint64)m_c[3] * Tr;
s += (val >> 17);
val = (qint64)m_c2[0] * Tr * Tr;
s += (val >> 34);
// Offset
qint64 o = (qint64)m_c2[1] << 14;
val = (qint64)m_c2[2] * Tr;
o += (val >> 3);
val = (qint64)m_c2[3] * Tr * Tr;
o += (val >> 19);
// Pressure (Pa)
qint64 pres = ((qint64)(s * Pr) + o) >> 14;
m_pressureValues.append((double)pres/100);
if (m_pressureValues.count() % 60 == 0) {
emit valueChanged(pressureStateTypeId, calculateMeanValue(m_pressureValues));
m_pressureValues.clear();
}
break;
}
case 0xf000aa43: {
const quint8 *data = reinterpret_cast<const quint8 *>(value.constData());
m_c.resize(4);
m_c2.resize(4);
m_c[0] = buildUINT16(data[0],data[1]);
m_c[1] = buildUINT16(data[2],data[3]);
m_c[2] = buildUINT16(data[4],data[5]);
m_c[3] = buildUINT16(data[6],data[7]);
m_c2[0] = buildUINT16(data[8],data[9]);
m_c2[1] = buildUINT16(data[10],data[11]);
m_c2[2] = buildUINT16(data[12],data[13]);
m_c2[3] = buildUINT16(data[14],data[15]);
break;
}
case 0xf000aa51: {
// TODO: evaluate movement
// const qint16 *data = reinterpret_cast<const qint16 *>(value.constData());
// emit valueChanged(rotationXStateTypeId, (double)data[0] / 131.072);
// emit valueChanged(rotationYStateTypeId, (double)data[1] / 131.072);
// emit valueChanged(rotationZStateTypeId, (double)data[2] / 131.072);
break;
}
case 0xffe1: {
const quint8 *data = reinterpret_cast<const quint8 *>(value.constData());
if (*data & 1)
emit event(leftKeyEventTypeId);
if (*data & 2)
emit event(rightKeyEventTypeId);
break;
}
default:
break;
}
}
void SensorTag::onServiceError(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;
}
qCWarning(dcMultiSensor) << "Service of " << name() << address().toString() << ":" << errorString;
}
#endif // BLUETOOTH_LE

View File

@ -0,0 +1,79 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stürz <simon.stuerz@guh.io> *
* Copyright (C) 2016 nicc *
* *
* This file is part of guh. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef SENSORTAG_H
#define SENSORTAG_H
#ifdef BLUETOOTH_LE
#include <QHash>
#include <QList>
#include <QSharedPointer>
#include <QLowEnergyService>
#include "bluetooth/bluetoothlowenergydevice.h"
#include "extern-plugininfo.h"
class SensorTag : public BluetoothLowEnergyDevice
{
Q_OBJECT
public:
explicit SensorTag(const QBluetoothDeviceInfo &deviceInfo, const QLowEnergyController::RemoteAddressType &addressType, QObject *parent = 0);
signals:
void valueChanged(StateTypeId state, QVariant value);
void event(EventTypeId event);
private:
QHash<QBluetoothUuid, QSharedPointer<QLowEnergyService>> m_services{
{QBluetoothUuid(QUuid("f000aa00-0451-4000-b000-000000000000")), QSharedPointer<QLowEnergyService>()},
{QBluetoothUuid(QUuid("f000aa10-0451-4000-b000-000000000000")), QSharedPointer<QLowEnergyService>()},
{QBluetoothUuid(QUuid("f000aa20-0451-4000-b000-000000000000")), QSharedPointer<QLowEnergyService>()},
{QBluetoothUuid(QUuid("f000aa30-0451-4000-b000-000000000000")), QSharedPointer<QLowEnergyService>()},
{QBluetoothUuid(QUuid("f000aa40-0451-4000-b000-000000000000")), QSharedPointer<QLowEnergyService>()},
{QBluetoothUuid(QUuid("f000aa50-0451-4000-b000-000000000000")), QSharedPointer<QLowEnergyService>()},
{QBluetoothUuid(QUuid("0000ffe0-0000-1000-8000-00805f9b34fb")), QSharedPointer<QLowEnergyService>()}
};
QVector<quint16> m_c;
QVector<qint16> m_c2;
QList<double> m_temperatureValues;
QList<double> m_irTemperatureValues;
QList<double> m_humidityValues;
QList<double> m_pressureValues;
double calculateMeanValue(const QList<double> &list);
private slots:
void setupServices();
void onConnectionStatusChanged();
// Service
void onServiceStateChanged(const QLowEnergyService::ServiceState &state);
void onServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value);
void onServiceError(const QLowEnergyService::ServiceError &error);
};
#endif // BLUETOOTH_LE
#endif // SENSORTAG_H

View File

@ -1,337 +1,342 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stürz <simon.stuerz@guh.io> *
* Copyright (C) 2016 nicc *
* *
* This file is part of guh. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifdef BLUETOOTH_LE
#include <QPointer>
#include <QLowEnergyService>
#include <QtMath>
#include "extern-plugininfo.h"
#include "sensortag.h"
#include "extern-plugininfo.h"
SensorTag::SensorTag(const QBluetoothDeviceInfo &deviceInfo, const QLowEnergyController::RemoteAddressType &addressType, QObject *parent) :
BluetoothLowEnergyDevice(deviceInfo, addressType, parent)
SensorTag::SensorTag(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(setupServices()));
connect(m_bluetoothDevice, &BluetoothLowEnergyDevice::connectedChanged, this, &SensorTag::onConnectedChanged);
connect(m_bluetoothDevice, &BluetoothLowEnergyDevice::servicesDiscoveryFinished, this, &SensorTag::onServiceDiscoveryFinished);
}
double SensorTag::calculateMeanValue(const QList<double> &list)
Device *SensorTag::device()
{
double sum = 0;
foreach (const double &value, list)
sum += value;
return sum / list.count();
return m_device;
}
void SensorTag::setupServices()
BluetoothLowEnergyDevice *SensorTag::bluetoothDevice()
{
foreach (auto id, m_services.keys()) {
if (!controller()->services().contains(id)) {
qCWarning(dcMultiSensor) << "Service not found for device" << name() << address().toString();
return m_bluetoothDevice;
}
void SensorTag::updateInfraredValue(const QByteArray &value)
{
qCDebug(dcMultiSensor()) << "Infrared value" << value;
}
void SensorTag::updateButtonValue(const QByteArray &value)
{
const quint8 *data = reinterpret_cast<const quint8 *>(value.constData());
if (*data & 1)
emit leftKeyPressed();
if (*data & 2)
emit rightKeyPressed();
}
void SensorTag::updateHumidityValue(const QByteArray &value)
{
qCDebug(dcMultiSensor()) << "Humidity value" << value;
}
void SensorTag::updatePressureValue(const QByteArray &value)
{
qCDebug(dcMultiSensor()) << "Pressure value" << value;
}
void SensorTag::onConnectedChanged(const bool &connected)
{
qCDebug(dcMultiSensor()) << "Sensor" << m_bluetoothDevice->name() << m_bluetoothDevice->address().toString() << (connected ? "connected" : "disconnected");
m_device->setStateValue(connectedStateTypeId, connected);
if (!connected) {
// Clean up services
m_infraredService->deleteLater();
m_buttonService->deleteLater();
m_humidityService->deleteLater();
m_pressureService->deleteLater();
m_infraredService = nullptr;
m_buttonService = nullptr;
m_humidityService = nullptr;
m_pressureService = nullptr;
}
}
void SensorTag::onServiceDiscoveryFinished()
{
if (!m_bluetoothDevice->serviceUuids().contains(infraredServiceUuid)) {
qCWarning(dcMultiSensor()) << "Could not find infrared service";
return;
}
if (!m_bluetoothDevice->serviceUuids().contains(accelerometerServiceUuid)) {
qCWarning(dcMultiSensor()) << "Could not find accelereometer service";
return;
}
if (!m_bluetoothDevice->serviceUuids().contains(humidityServiceUuid)) {
qCWarning(dcMultiSensor()) << "Could not find humidity service";
return;
}
if (!m_bluetoothDevice->serviceUuids().contains(magnetometerServiceUuid)) {
qCWarning(dcMultiSensor()) << "Could not find magnetometer service";
return;
}
if (!m_bluetoothDevice->serviceUuids().contains(pressureServiceUuid)) {
qCWarning(dcMultiSensor()) << "Could not find pressure service";
return;
}
if (!m_bluetoothDevice->serviceUuids().contains(gyroscopeServiceUuid)) {
qCWarning(dcMultiSensor()) << "Could not find magnetometer service";
return;
}
// IR Temperature
if (!m_infraredService) {
m_infraredService = m_bluetoothDevice->controller()->createServiceObject(infraredServiceUuid, this);
if (!m_infraredService) {
qCWarning(dcMultiSensor()) << "Could not create infrared service.";
return;
}
if (m_services.value(id)) {
qCWarning(dcMultiSensor) << "Attention! bad implementation of service handling!!";
connect(m_infraredService, &QLowEnergyService::stateChanged, this, &SensorTag::onInfraredServiceStateChanged);
connect(m_infraredService, &QLowEnergyService::characteristicChanged, this, &SensorTag::onInfraredServiceCharacteristicChanged);
if (m_infraredService->state() == QLowEnergyService::DiscoveryRequired) {
m_infraredService->discoverDetails();
}
}
// Buttons
if (!m_buttonService) {
m_buttonService = m_bluetoothDevice->controller()->createServiceObject(buttonServiceUuid, this);
if (!m_buttonService) {
qCWarning(dcMultiSensor()) << "Could not create button service.";
return;
}
qCDebug(dcMultiSensor) << "Setup service";
connect(m_buttonService, &QLowEnergyService::stateChanged, this, &SensorTag::onButtonServiceStateChanged);
connect(m_buttonService, &QLowEnergyService::characteristicChanged, this, &SensorTag::onButtonServiceCharacteristicChanged);
// service for temperature
QSharedPointer<QLowEnergyService> service{controller()->createServiceObject(id, this)};
if (m_buttonService->state() == QLowEnergyService::DiscoveryRequired) {
m_buttonService->discoverDetails();
}
}
if (service.isNull()) {
qCWarning(dcMultiSensor) << "Could not create service for device" << name() << address().toString();
// Humidity
if (!m_humidityService) {
m_humidityService = m_bluetoothDevice->controller()->createServiceObject(humidityServiceUuid, this);
if (!m_humidityService) {
qCWarning(dcMultiSensor()) << "Could not create humidity service.";
return;
}
m_services.insert(id, service);
connect(service.data(), SIGNAL(error(QLowEnergyService::ServiceError)), this, SLOT(onServiceError(QLowEnergyService::ServiceError)));
connect(service.data(), &QLowEnergyService::stateChanged, this, &SensorTag::onServiceStateChanged);
connect(service.data(), &QLowEnergyService::characteristicChanged, this, &SensorTag::onServiceCharacteristicChanged);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
connect(service.data(), &QLowEnergyService::characteristicRead, this, &SensorTag::onServiceCharacteristicChanged);
#endif
service->discoverDetails();
connect(m_humidityService, &QLowEnergyService::stateChanged, this, &SensorTag::onHumidityServiceStateChanged);
connect(m_humidityService, &QLowEnergyService::characteristicChanged, this, &SensorTag::onHumidityServiceCharacteristicChanged);
if (m_humidityService->state() == QLowEnergyService::DiscoveryRequired) {
m_humidityService->discoverDetails();
}
}
// Pressure
if (!m_pressureService) {
m_pressureService = m_bluetoothDevice->controller()->createServiceObject(pressureServiceUuid, this);
if (!m_pressureService) {
qCWarning(dcMultiSensor()) << "Could not create pressure service.";
return;
}
connect(m_pressureService, &QLowEnergyService::stateChanged, this, &SensorTag::onPressureServiceStateChanged);
connect(m_pressureService, &QLowEnergyService::characteristicChanged, this, &SensorTag::onPressureServiceCharacteristicChanged);
if (m_pressureService->state() == QLowEnergyService::DiscoveryRequired) {
m_pressureService->discoverDetails();
}
}
}
void SensorTag::onConnectionStatusChanged()
void SensorTag::onInfraredServiceStateChanged(const QLowEnergyService::ServiceState &state)
{
if (!isConnected()) {
// delete the services, they need to be recreated and
// rediscovered once the device will be reconnected
foreach (QSharedPointer<QLowEnergyService> service, m_services)
service->deleteLater();
// Only continue if discovered
if (state != QLowEnergyService::ServiceDiscovered)
return;
emit valueChanged(connectedStateTypeId, false);
} else {
emit valueChanged(connectedStateTypeId, true);
qCDebug(dcMultiSensor()) << "Infrared sensor service discovered.";
foreach (const QLowEnergyCharacteristic &characteristic, m_infraredService->characteristics()) {
qCDebug(dcMultiSensor()) << " -->" << characteristic.name() << characteristic.uuid().toString() << characteristic.value();
foreach (const QLowEnergyDescriptor &desciptor, characteristic.descriptors()) {
qCDebug(dcMultiSensor()) << " -->" << desciptor.name() << desciptor.uuid().toString() << desciptor.value();
}
}
// Data characteristic
m_infraredDataCharacteristic = m_infraredService->characteristic(QBluetoothUuid(QUuid("f000aa01-0451-4000-b000-000000000000")));
if (!m_infraredDataCharacteristic.isValid()) {
qCWarning(dcMultiSensor()) << "Invalid infrared data characteristic.";
}
// Enable notifications
QLowEnergyDescriptor notificationDescriptor = m_infraredDataCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
m_infraredService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100"));
// Config characteristic
m_infraredConfigCharacteristic = m_infraredService->characteristic(QBluetoothUuid(QUuid("f000aa02-0451-4000-b000-000000000000")));
if (!m_infraredConfigCharacteristic.isValid()) {
qCWarning(dcMultiSensor()) << "Invalid infrared configuration characteristic.";
}
// Enable measuring
m_infraredService->writeCharacteristic(m_infraredConfigCharacteristic, QByteArray::fromHex("01"));
}
void SensorTag::onServiceStateChanged(const QLowEnergyService::ServiceState &state)
void SensorTag::onInfraredServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
{
QPointer<QLowEnergyService> service = qobject_cast<QLowEnergyService *>(sender());
if (characteristic == m_infraredDataCharacteristic) {
updateInfraredValue(value);
switch (state) {
case QLowEnergyService::DiscoveringServices:
qCDebug(dcMultiSensor) << "Start discovering service" << service->serviceUuid();
break;
case QLowEnergyService::ServiceDiscovered:
if (m_services.contains(service->serviceUuid())) {
qCDebug(dcMultiSensor) << "... service discovered.";
auto dataId = service->serviceUuid();
dataId.data1 += 1;
auto sensorCharacteristic = service->characteristic(dataId);
if (!sensorCharacteristic.isValid()) {
qCWarning(dcMultiSensor) << "Characteristic not found for device " << name() << address().toString();
break;
}
const auto notificationDescriptor = sensorCharacteristic.descriptor(
QBluetoothUuid::ClientCharacteristicConfiguration);
if (notificationDescriptor.isValid()) {
service->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100"));
qCDebug(dcMultiSensor) << "Measuring";
}
if (service->serviceUuid().data1 == 0xffe0)
break;
auto configId = service->serviceUuid();
configId.data1 += 2;
auto sensorConfig = service->characteristic(configId);
if (!sensorConfig.isValid()) {
qCWarning(dcMultiSensor) << "Characteristic not found for device " << name() << address().toString();
break;
}
if (service->serviceUuid().data1 == 0xf000aa50) {
service->writeCharacteristic(sensorConfig, QByteArray::fromHex("07"));
} else {
service->writeCharacteristic(sensorConfig, QByteArray::fromHex("01"));
}
if (service->serviceUuid().data1 == 0xf000aa40) {
service->writeCharacteristic(sensorConfig, QByteArray::fromHex("02"));
auto calibId = service->serviceUuid();
calibId.data1 += 3;
#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
service->readCharacteristic(service->characteristic(calibId));
#endif
}
// TODO: initialize the states with the current value
}
break;
default:
break;
// FIXME: Disable measuring
// m_infraredService->writeCharacteristic(m_infraredConfigCharacteristic, QByteArray::fromHex("00"));
}
}
inline quint16 buildUINT16(quint8 loByte, quint8 hiByte) {
return ((quint16)(((loByte) & 0x00FF) + (((hiByte) & 0x00FF) << 8)));
}
void SensorTag::onServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
void SensorTag::onButtonServiceStateChanged(const QLowEnergyService::ServiceState &state)
{
qCDebug(dcMultiSensor) << "Service characteristic changed" << characteristic.uuid().toString() << value.toHex();
// Only continue if discovered
if (state != QLowEnergyService::ServiceDiscovered)
return;
auto id = characteristic.uuid();
id.data1 -= 1;
switch (characteristic.uuid().data1) {
case 0xf000aa01: {
const quint16 *data = reinterpret_cast<const quint16 *>(value.constData());
qint16 rawTamb = data[1];
m_temperatureValues.append((double)rawTamb / 128);
if (m_temperatureValues.count() % 60 == 0) {
emit valueChanged(temperatureStateTypeId, calculateMeanValue(m_temperatureValues));
m_temperatureValues.clear();
qCDebug(dcMultiSensor()) << "Button sensor service discovered.";
foreach (const QLowEnergyCharacteristic &characteristic, m_buttonService->characteristics()) {
qCDebug(dcMultiSensor()) << " -->" << characteristic.name() << characteristic.uuid().toString() << characteristic.value();
foreach (const QLowEnergyDescriptor &desciptor, characteristic.descriptors()) {
qCDebug(dcMultiSensor()) << " -->" << desciptor.name() << desciptor.uuid().toString() << desciptor.value();
}
}
qint16 Vobj2 = (double)data[0];
Vobj2 *= 0.00000015625;
double Tdie2 = ((double)rawTamb / 128) + 273.15;
const double S0 = 6.4E-14; // Calibration factor
const double a1 = 1.75E-3;
const double a2 = -1.678E-5;
const double b0 = -2.94E-5;
const double b1 = -5.7E-7;
const double b2 = 4.63E-9;
const double c2 = 13.4;
const double Tref = 298.15;
double S = S0*(1+a1*(Tdie2 - Tref)+a2*qPow((Tdie2 - Tref),2));
double Vos = b0 + b1*(Tdie2 - Tref) + b2*qPow((Tdie2 - Tref),2);
double fObj = (Vobj2 - Vos) + c2*qPow((Vobj2 - Vos),2);
double tObj = qPow(qPow(Tdie2,4) + (fObj/S),.25);
m_irTemperatureValues.append(tObj - 273.15);
if (m_irTemperatureValues.count() % 60 == 0) {
emit valueChanged(IRtemperatureStateTypeId, calculateMeanValue(m_irTemperatureValues));
m_irTemperatureValues.clear();
}
// Data characteristic
m_buttonCharacteristic = m_buttonService->characteristic(QBluetoothUuid(QUuid("0000ffe1-0000-1000-8000-00805f9b34fb")));
if (!m_buttonCharacteristic.isValid()) {
qCWarning(dcMultiSensor()) << "Invalid button data characteristic.";
}
break;
}
case 0xf000aa11: {
// TODO: evaluate movement
// const qint8 *data = reinterpret_cast<const qint8 *>(value.constData());
// emit valueChanged(accelerationXStateTypeId, (double)data[0] / 64);
// emit valueChanged(accelerationYStateTypeId, (double)data[1] / 64);
// emit valueChanged(accelerationZStateTypeId, (double)data[2] / 64);
break;
}
case 0xf000aa21: {
const quint16 *data = reinterpret_cast<const quint16 *>(value.constData());
quint16 rawH = data[1];
rawH &= ~0x0003;
m_humidityValues.append(-6.0 + 125.0/65536 * (double)rawH);
if (m_humidityValues.count() % 60 == 0) {
emit valueChanged(humidityStateTypeId, calculateMeanValue(m_humidityValues));
m_humidityValues.clear();
}
break;
}
case 0xf000aa31: {
// TODO: evaluate movement
// const qint16 *data = reinterpret_cast<const qint16 *>(value.constData());
// emit valueChanged(magneticFieldXStateTypeId, (double)data[0] / 32.768);
// emit valueChanged(magneticFieldYStateTypeId, (double)data[1] / 32.768);
// emit valueChanged(magneticFieldZStateTypeId, (double)data[2] / 32.768);
break;
}
case 0xf000aa41: {
if (m_c.empty())
break;
const quint16 *data = reinterpret_cast<const quint16 *>(value.constData());
quint16 Pr = data[1];
qint16 Tr = data[0];
// Sensitivity
qint64 s = (qint64)m_c[2];
qint64 val = (qint64)m_c[3] * Tr;
s += (val >> 17);
val = (qint64)m_c2[0] * Tr * Tr;
s += (val >> 34);
// Offset
qint64 o = (qint64)m_c2[1] << 14;
val = (qint64)m_c2[2] * Tr;
o += (val >> 3);
val = (qint64)m_c2[3] * Tr * Tr;
o += (val >> 19);
// Pressure (Pa)
qint64 pres = ((qint64)(s * Pr) + o) >> 14;
m_pressureValues.append((double)pres/100);
if (m_pressureValues.count() % 60 == 0) {
emit valueChanged(pressureStateTypeId, calculateMeanValue(m_pressureValues));
m_pressureValues.clear();
}
break;
}
case 0xf000aa43: {
const quint8 *data = reinterpret_cast<const quint8 *>(value.constData());
m_c.resize(4);
m_c2.resize(4);
m_c[0] = buildUINT16(data[0],data[1]);
m_c[1] = buildUINT16(data[2],data[3]);
m_c[2] = buildUINT16(data[4],data[5]);
m_c[3] = buildUINT16(data[6],data[7]);
m_c2[0] = buildUINT16(data[8],data[9]);
m_c2[1] = buildUINT16(data[10],data[11]);
m_c2[2] = buildUINT16(data[12],data[13]);
m_c2[3] = buildUINT16(data[14],data[15]);
break;
}
case 0xf000aa51: {
// TODO: evaluate movement
// const qint16 *data = reinterpret_cast<const qint16 *>(value.constData());
// emit valueChanged(rotationXStateTypeId, (double)data[0] / 131.072);
// emit valueChanged(rotationYStateTypeId, (double)data[1] / 131.072);
// emit valueChanged(rotationZStateTypeId, (double)data[2] / 131.072);
break;
}
case 0xffe1: {
const quint8 *data = reinterpret_cast<const quint8 *>(value.constData());
if (*data & 1)
emit event(leftKeyEventTypeId);
if (*data & 2)
emit event(rightKeyEventTypeId);
break;
}
default:
break;
}
// Enable notifications
QLowEnergyDescriptor notificationDescriptor = m_buttonCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
m_buttonService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100"));
}
void SensorTag::onServiceError(const QLowEnergyService::ServiceError &error)
void SensorTag::onButtonServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
{
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;
if (characteristic == m_buttonCharacteristic) {
updateButtonValue(value);
}
qCWarning(dcMultiSensor) << "Service of " << name() << address().toString() << ":" << errorString;
}
#endif // BLUETOOTH_LE
void SensorTag::onHumidityServiceStateChanged(const QLowEnergyService::ServiceState &state)
{
// Only continue if discovered
if (state != QLowEnergyService::ServiceDiscovered)
return;
qCDebug(dcMultiSensor()) << "Humidity sensor service discovered.";
foreach (const QLowEnergyCharacteristic &characteristic, m_humidityService->characteristics()) {
qCDebug(dcMultiSensor()) << " -->" << characteristic.name() << characteristic.uuid().toString() << characteristic.value();
foreach (const QLowEnergyDescriptor &desciptor, characteristic.descriptors()) {
qCDebug(dcMultiSensor()) << " -->" << desciptor.name() << desciptor.uuid().toString() << desciptor.value();
}
}
// Data characteristic
m_humidityDataCharacteristic = m_humidityService->characteristic(QBluetoothUuid(QUuid("f000aa21-0451-4000-b000-000000000000")));
if (!m_humidityDataCharacteristic.isValid()) {
qCWarning(dcMultiSensor()) << "Invalid humidity data characteristic.";
}
// Enable notifications
QLowEnergyDescriptor notificationDescriptor = m_humidityDataCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
m_humidityService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100"));
// Config characteristic
m_humidityConfigCharacteristic = m_humidityService->characteristic(QBluetoothUuid(QUuid("f000aa22-0451-4000-b000-000000000000")));
if (!m_humidityConfigCharacteristic.isValid()) {
qCWarning(dcMultiSensor()) << "Invalid humidity configuration characteristic.";
}
// Enable measuring
m_humidityService->writeCharacteristic(m_humidityConfigCharacteristic, QByteArray::fromHex("01"));
}
void SensorTag::onHumidityServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
{
if (characteristic == m_humidityDataCharacteristic) {
updateHumidityValue(value);
// FIXME: Disable measuring
// m_humidityService->writeCharacteristic(m_humidityConfigCharacteristic, QByteArray::fromHex("00"));
}
}
void SensorTag::onPressureServiceStateChanged(const QLowEnergyService::ServiceState &state)
{
// Only continue if discovered
if (state != QLowEnergyService::ServiceDiscovered)
return;
qCDebug(dcMultiSensor()) << "Pressure sensor service discovered.";
foreach (const QLowEnergyCharacteristic &characteristic, m_pressureService->characteristics()) {
qCDebug(dcMultiSensor()) << " -->" << characteristic.name() << characteristic.uuid().toString() << characteristic.value();
foreach (const QLowEnergyDescriptor &desciptor, characteristic.descriptors()) {
qCDebug(dcMultiSensor()) << " -->" << desciptor.name() << desciptor.uuid().toString() << desciptor.value();
}
}
// Data characteristic
m_pressureDataCharacteristic = m_pressureService->characteristic(QBluetoothUuid(QUuid("f000aa41-0451-4000-b000-000000000000")));
if (!m_pressureDataCharacteristic.isValid()) {
qCWarning(dcMultiSensor()) << "Invalid pressure data characteristic.";
}
// Enable notifications
QLowEnergyDescriptor notificationDescriptor = m_pressureDataCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
m_pressureService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100"));
// Config characteristic
m_pressureConfigCharacteristic = m_pressureService->characteristic(QBluetoothUuid(QUuid("f000aa42-0451-4000-b000-000000000000")));
if (!m_pressureConfigCharacteristic.isValid()) {
qCWarning(dcMultiSensor()) << "Invalid pressure configuration characteristic.";
}
// Enable measuring
m_pressureService->writeCharacteristic(m_pressureConfigCharacteristic, QByteArray::fromHex("01"));
}
void SensorTag::onPressureServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
{
if (characteristic == m_pressureDataCharacteristic) {
updatePressureValue(value);
// FIXME: Disable measuring
// m_pressureService->writeCharacteristic(m_pressureConfigCharacteristic, QByteArray::fromHex("00"));
}
}
void SensorTag::measure()
{
if (!m_bluetoothDevice->connected())
return;
// qCDebug(dcMultiSensor()) << "Measure data" << m_bluetoothDevice->name() << m_bluetoothDevice->address().toString();
// m_infraredService->writeCharacteristic(m_infraredConfigCharacteristic, QByteArray::fromHex("01"));
// m_humidityService->writeCharacteristic(m_humidityConfigCharacteristic, QByteArray::fromHex("01"));
// m_pressureService->writeCharacteristic(m_pressureConfigCharacteristic, QByteArray::fromHex("01"));
}

View File

@ -1,79 +1,88 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stürz <simon.stuerz@guh.io> *
* Copyright (C) 2016 nicc *
* *
* This file is part of guh. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef SENSORTAG_H
#define SENSORTAG_H
#ifdef BLUETOOTH_LE
#include <QObject>
#include <QHash>
#include <QList>
#include <QSharedPointer>
#include <QLowEnergyService>
#include "bluetooth/bluetoothlowenergydevice.h"
#include "plugin/device.h"
#include "extern-plugininfo.h"
#include "bluetooth/bluetoothlowenergydevice.h"
class SensorTag : public BluetoothLowEnergyDevice
static QBluetoothUuid infraredServiceUuid = QBluetoothUuid(QUuid("f000aa00-0451-4000-b000-000000000000"));
static QBluetoothUuid accelerometerServiceUuid = QBluetoothUuid(QUuid("f000aa10-0451-4000-b000-000000000000"));
static QBluetoothUuid humidityServiceUuid = QBluetoothUuid(QUuid("f000aa20-0451-4000-b000-000000000000"));
static QBluetoothUuid magnetometerServiceUuid = QBluetoothUuid(QUuid("f000aa30-0451-4000-b000-000000000000"));
static QBluetoothUuid pressureServiceUuid = QBluetoothUuid(QUuid("f000aa40-0451-4000-b000-000000000000"));
static QBluetoothUuid gyroscopeServiceUuid = QBluetoothUuid(QUuid("f000aa50-0451-4000-b000-000000000000"));
static QBluetoothUuid testServiceUuid = QBluetoothUuid(QUuid("f000aa60-0451-4000-b000-000000000000"));
static QBluetoothUuid otaServiceUuid = QBluetoothUuid(QUuid("f000aac0-0451-4000-b000-000000000000"));
static QBluetoothUuid buttonServiceUuid = QBluetoothUuid(QUuid("0000ffe0-0000-1000-8000-00805f9b34fb"));
// Currently unused services
class SensorTag : public QObject
{
Q_OBJECT
public:
explicit SensorTag(const QBluetoothDeviceInfo &deviceInfo, const QLowEnergyController::RemoteAddressType &addressType, QObject *parent = 0);
explicit SensorTag(Device *device, BluetoothLowEnergyDevice *bluetoothDevice, QObject *parent = nullptr);
signals:
void valueChanged(StateTypeId state, QVariant value);
void event(EventTypeId event);
Device *device();
BluetoothLowEnergyDevice *bluetoothDevice();
private:
QHash<QBluetoothUuid, QSharedPointer<QLowEnergyService>> m_services{
{QBluetoothUuid(QUuid("f000aa00-0451-4000-b000-000000000000")), QSharedPointer<QLowEnergyService>()},
{QBluetoothUuid(QUuid("f000aa10-0451-4000-b000-000000000000")), QSharedPointer<QLowEnergyService>()},
{QBluetoothUuid(QUuid("f000aa20-0451-4000-b000-000000000000")), QSharedPointer<QLowEnergyService>()},
{QBluetoothUuid(QUuid("f000aa30-0451-4000-b000-000000000000")), QSharedPointer<QLowEnergyService>()},
{QBluetoothUuid(QUuid("f000aa40-0451-4000-b000-000000000000")), QSharedPointer<QLowEnergyService>()},
{QBluetoothUuid(QUuid("f000aa50-0451-4000-b000-000000000000")), QSharedPointer<QLowEnergyService>()},
{QBluetoothUuid(QUuid("0000ffe0-0000-1000-8000-00805f9b34fb")), QSharedPointer<QLowEnergyService>()}
};
Device *m_device;
BluetoothLowEnergyDevice *m_bluetoothDevice;
QVector<quint16> m_c;
QVector<qint16> m_c2;
// Services
QLowEnergyService *m_infraredService = nullptr;
QLowEnergyService *m_buttonService = nullptr;
QLowEnergyService *m_humidityService = nullptr;
QLowEnergyService *m_pressureService = nullptr;
QLowEnergyService *m_accelerometerService = nullptr;
QLowEnergyService *m_magnetometerService = nullptr;
QLowEnergyService *m_gyroscopeService = nullptr;
QList<double> m_temperatureValues;
QList<double> m_irTemperatureValues;
QList<double> m_humidityValues;
QList<double> m_pressureValues;
// Characteristics
QLowEnergyCharacteristic m_infraredDataCharacteristic;
QLowEnergyCharacteristic m_infraredConfigCharacteristic;
QLowEnergyCharacteristic m_buttonCharacteristic;
QLowEnergyCharacteristic m_humidityDataCharacteristic;
QLowEnergyCharacteristic m_humidityConfigCharacteristic;
QLowEnergyCharacteristic m_pressureDataCharacteristic;
QLowEnergyCharacteristic m_pressureConfigCharacteristic;
double calculateMeanValue(const QList<double> &list);
void updateInfraredValue(const QByteArray &value);
void updateButtonValue(const QByteArray &value);
void updateHumidityValue(const QByteArray &value);
void updatePressureValue(const QByteArray &value);
signals:
void leftKeyPressed();
void rightKeyPressed();
private slots:
void setupServices();
void onConnectionStatusChanged();
void onConnectedChanged(const bool &connected);
void onServiceDiscoveryFinished();
// Service
void onServiceStateChanged(const QLowEnergyService::ServiceState &state);
void onServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value);
void onServiceError(const QLowEnergyService::ServiceError &error);
// Infrared sensor service
void onInfraredServiceStateChanged(const QLowEnergyService::ServiceState &state);
void onInfraredServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value);
// Button service
void onButtonServiceStateChanged(const QLowEnergyService::ServiceState &state);
void onButtonServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value);
// Humidity sensor service
void onHumidityServiceStateChanged(const QLowEnergyService::ServiceState &state);
void onHumidityServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value);
// Pressure sensor service
void onPressureServiceStateChanged(const QLowEnergyService::ServiceState &state);
void onPressureServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value);
public slots:
void measure();
};
#endif // BLUETOOTH_LE
#endif // SENSORTAG_H

View File

@ -1,7 +1,7 @@
TEMPLATE = lib
CONFIG += plugin
QT += network bluetooth
QT += network bluetooth dbus
QMAKE_CXXFLAGS += -Werror -std=c++11 -g
QMAKE_LFLAGS += -std=c++11