New Plugin: TexasInstruments, replaces MultiSensor plugin
parent
1fe3d94440
commit
57e2c66ef8
|
|
@ -39,6 +39,7 @@ PLUGIN_DIRS = \
|
||||||
snapd \
|
snapd \
|
||||||
tasmota \
|
tasmota \
|
||||||
tcpcommander \
|
tcpcommander \
|
||||||
|
texasinstruments \
|
||||||
udpcommander \
|
udpcommander \
|
||||||
unipi \
|
unipi \
|
||||||
unitec \
|
unitec \
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,255 @@
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2019 Michael Zanetti <michael.zanetti@nymea.io> *
|
||||||
|
* *
|
||||||
|
* This file is part of nymea. *
|
||||||
|
* *
|
||||||
|
* 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/>. *
|
||||||
|
* *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\page texasinstruments.html
|
||||||
|
\title Texas Instruments
|
||||||
|
\brief Plugin for Texas Instruments Devices.
|
||||||
|
|
||||||
|
\ingroup plugins
|
||||||
|
\ingroup nymea-plugins
|
||||||
|
|
||||||
|
This plugin supports devices from Texas Instruments.
|
||||||
|
|
||||||
|
Currently supported devices:
|
||||||
|
* TI SensorTag (CC2650).
|
||||||
|
|
||||||
|
\chapter TI SensorTag (CC2650)
|
||||||
|
|
||||||
|
Using Bluetooth-LE, the TI SensorTag device class allows nymea to interact with those sensors. All supported
|
||||||
|
sensors of the device are supported:
|
||||||
|
* Temperature
|
||||||
|
* IR Temperature
|
||||||
|
* Humidity
|
||||||
|
* Pressure
|
||||||
|
* Light intensity
|
||||||
|
* Motion
|
||||||
|
* Magnetic Objects
|
||||||
|
Besides reading the sensor values, the buttons, buzzer and LEDs can be read and/or controlled.
|
||||||
|
|
||||||
|
\chapter Plugin defintion
|
||||||
|
|
||||||
|
\quotefile plugins/deviceplugins/multisensor/deviceplugintexasinstruments.json
|
||||||
|
|
||||||
|
\sa {The plugin JSON File}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "deviceplugintexasinstruments.h"
|
||||||
|
#include "plugininfo.h"
|
||||||
|
#include "sensortag.h"
|
||||||
|
|
||||||
|
#include "hardware/bluetoothlowenergy/bluetoothlowenergymanager.h"
|
||||||
|
#include "plugintimer.h"
|
||||||
|
|
||||||
|
#include <QBluetoothDeviceInfo>
|
||||||
|
|
||||||
|
DevicePluginTexasInstruments::DevicePluginTexasInstruments(QObject *parent) : DevicePlugin(parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
DevicePluginTexasInstruments::~DevicePluginTexasInstruments()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceManager::DeviceError DevicePluginTexasInstruments::discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms)
|
||||||
|
{
|
||||||
|
Q_UNUSED(params)
|
||||||
|
Q_ASSERT_X(deviceClassId == sensorTagDeviceClassId, "DevicePluginTexasInstruments", "Unhandled DeviceClassId!");
|
||||||
|
|
||||||
|
if (!hardwareManager()->bluetoothLowEnergyManager()->available() || !hardwareManager()->bluetoothLowEnergyManager()->enabled()) {
|
||||||
|
return DeviceManager::DeviceErrorHardwareNotAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
BluetoothDiscoveryReply *reply = hardwareManager()->bluetoothLowEnergyManager()->discoverDevices();
|
||||||
|
connect(reply, &BluetoothDiscoveryReply::finished, this, [this, reply](){
|
||||||
|
reply->deleteLater();
|
||||||
|
|
||||||
|
if (reply->error() != BluetoothDiscoveryReply::BluetoothDiscoveryReplyErrorNoError) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Bluetooth discovery error:" << reply->error();
|
||||||
|
emit devicesDiscovered(sensorTagDeviceClassId, QList<DeviceDescriptor>());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<DeviceDescriptor> deviceDescriptors;
|
||||||
|
foreach (const QBluetoothDeviceInfo &deviceInfo, reply->discoveredDevices()) {
|
||||||
|
|
||||||
|
if (deviceInfo.name().contains("SensorTag")) {
|
||||||
|
|
||||||
|
DeviceDescriptor descriptor(sensorTagDeviceClassId, "Sensor Tag", deviceInfo.address().toString());
|
||||||
|
|
||||||
|
Devices existingDevice = myDevices().filterByParam(sensorTagDeviceMacParamTypeId, deviceInfo.address().toString());
|
||||||
|
if (!existingDevice.isEmpty()) {
|
||||||
|
descriptor.setDeviceId(existingDevice.first()->id());
|
||||||
|
}
|
||||||
|
|
||||||
|
ParamList params;
|
||||||
|
params.append(Param(sensorTagDeviceMacParamTypeId, deviceInfo.address().toString()));
|
||||||
|
foreach (Device *existingDevice, myDevices()) {
|
||||||
|
if (existingDevice->paramValue(sensorTagDeviceMacParamTypeId).toString() == deviceInfo.address().toString()) {
|
||||||
|
descriptor.setDeviceId(existingDevice->id());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
descriptor.setParams(params);
|
||||||
|
deviceDescriptors.append(descriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emit devicesDiscovered(sensorTagDeviceClassId, deviceDescriptors);
|
||||||
|
});
|
||||||
|
return DeviceManager::DeviceErrorAsync;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceManager::DeviceSetupStatus DevicePluginTexasInstruments::setupDevice(Device *device)
|
||||||
|
{
|
||||||
|
qCDebug(dcTexasInstruments()) << "Setting up Multi Sensor" << device->name() << device->params();
|
||||||
|
|
||||||
|
QBluetoothAddress address = QBluetoothAddress(device->paramValue(sensorTagDeviceMacParamTypeId).toString());
|
||||||
|
QBluetoothDeviceInfo deviceInfo = QBluetoothDeviceInfo(address, device->name(), 0);
|
||||||
|
|
||||||
|
BluetoothLowEnergyDevice *bluetoothDevice = hardwareManager()->bluetoothLowEnergyManager()->registerDevice(deviceInfo, QLowEnergyController::PublicAddress);
|
||||||
|
|
||||||
|
SensorTag *sensorTag = new SensorTag(device, bluetoothDevice, this);
|
||||||
|
m_sensorTags.insert(device, sensorTag);
|
||||||
|
|
||||||
|
if (!m_reconnectTimer) {
|
||||||
|
m_reconnectTimer = hardwareManager()->pluginTimerManager()->registerTimer(10);
|
||||||
|
connect(m_reconnectTimer, &PluginTimer::timeout, this, [this](){
|
||||||
|
foreach (SensorTag *sensorTag, m_sensorTags) {
|
||||||
|
if (!sensorTag->bluetoothDevice()->connected()) {
|
||||||
|
sensorTag->bluetoothDevice()->connectDevice();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return DeviceManager::DeviceSetupStatusSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DevicePluginTexasInstruments::postSetupDevice(Device *device)
|
||||||
|
{
|
||||||
|
// Try to connect right after setup
|
||||||
|
SensorTag *sensorTag = m_sensorTags.value(device);
|
||||||
|
|
||||||
|
// Configure sensor with state configurations
|
||||||
|
sensorTag->setTemperatureSensorEnabled(device->stateValue(sensorTagTemperatureSensorEnabledStateTypeId).toBool());
|
||||||
|
sensorTag->setHumiditySensorEnabled(device->stateValue(sensorTagHumiditySensorEnabledStateTypeId).toBool());
|
||||||
|
sensorTag->setPressureSensorEnabled(device->stateValue(sensorTagPressureSensorEnabledStateTypeId).toBool());
|
||||||
|
sensorTag->setOpticalSensorEnabled(device->stateValue(sensorTagOpticalSensorEnabledStateTypeId).toBool());
|
||||||
|
sensorTag->setAccelerometerEnabled(device->stateValue(sensorTagAccelerometerEnabledStateTypeId).toBool());
|
||||||
|
sensorTag->setGyroscopeEnabled(device->stateValue(sensorTagGyroscopeEnabledStateTypeId).toBool());
|
||||||
|
sensorTag->setMagnetometerEnabled(device->stateValue(sensorTagMagnetometerEnabledStateTypeId).toBool());
|
||||||
|
sensorTag->setMeasurementPeriod(device->stateValue(sensorTagMeasurementPeriodStateTypeId).toInt());
|
||||||
|
sensorTag->setMeasurementPeriodMovement(device->stateValue(sensorTagMeasurementPeriodMovementStateTypeId).toInt());
|
||||||
|
|
||||||
|
// Connect to the sensor
|
||||||
|
sensorTag->bluetoothDevice()->connectDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DevicePluginTexasInstruments::deviceRemoved(Device *device)
|
||||||
|
{
|
||||||
|
if (!m_sensorTags.contains(device)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SensorTag *sensorTag = m_sensorTags.take(device);
|
||||||
|
hardwareManager()->bluetoothLowEnergyManager()->unregisterDevice(sensorTag->bluetoothDevice());
|
||||||
|
sensorTag->deleteLater();
|
||||||
|
|
||||||
|
if (myDevices().isEmpty()) {
|
||||||
|
hardwareManager()->pluginTimerManager()->unregisterTimer(m_reconnectTimer);
|
||||||
|
m_reconnectTimer = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceManager::DeviceError DevicePluginTexasInstruments::executeAction(Device *device, const Action &action)
|
||||||
|
{
|
||||||
|
SensorTag *sensorTag = m_sensorTags.value(device);
|
||||||
|
if (action.actionTypeId() == sensorTagBuzzerActionTypeId) {
|
||||||
|
sensorTag->setBuzzerPower(action.param(sensorTagBuzzerActionBuzzerParamTypeId).value().toBool());
|
||||||
|
return DeviceManager::DeviceErrorNoError;
|
||||||
|
} else if (action.actionTypeId() == sensorTagGreenLedActionTypeId) {
|
||||||
|
sensorTag->setGreenLedPower(action.param(sensorTagGreenLedActionGreenLedParamTypeId).value().toBool());
|
||||||
|
return DeviceManager::DeviceErrorNoError;
|
||||||
|
} else if (action.actionTypeId() == sensorTagRedLedActionTypeId) {
|
||||||
|
sensorTag->setRedLedPower(action.param(sensorTagRedLedActionRedLedParamTypeId).value().toBool());
|
||||||
|
return DeviceManager::DeviceErrorNoError;
|
||||||
|
} else if (action.actionTypeId() == sensorTagBuzzerImpulseActionTypeId) {
|
||||||
|
sensorTag->buzzerImpulse();
|
||||||
|
return DeviceManager::DeviceErrorNoError;
|
||||||
|
} else if (action.actionTypeId() == sensorTagTemperatureSensorEnabledActionTypeId) {
|
||||||
|
bool enabled = action.param(sensorTagTemperatureSensorEnabledActionTemperatureSensorEnabledParamTypeId).value().toBool();
|
||||||
|
device->setStateValue(sensorTagTemperatureSensorEnabledStateTypeId, enabled);
|
||||||
|
sensorTag->setTemperatureSensorEnabled(enabled);
|
||||||
|
return DeviceManager::DeviceErrorNoError;
|
||||||
|
} else if (action.actionTypeId() == sensorTagHumiditySensorEnabledActionTypeId) {
|
||||||
|
bool enabled = action.param(sensorTagHumiditySensorEnabledActionHumiditySensorEnabledParamTypeId).value().toBool();
|
||||||
|
device->setStateValue(sensorTagHumiditySensorEnabledStateTypeId, enabled);
|
||||||
|
sensorTag->setHumiditySensorEnabled(enabled);
|
||||||
|
return DeviceManager::DeviceErrorNoError;
|
||||||
|
} else if (action.actionTypeId() == sensorTagPressureSensorEnabledActionTypeId) {
|
||||||
|
bool enabled = action.param(sensorTagPressureSensorEnabledActionPressureSensorEnabledParamTypeId).value().toBool();
|
||||||
|
device->setStateValue(sensorTagPressureSensorEnabledStateTypeId, enabled);
|
||||||
|
sensorTag->setPressureSensorEnabled(enabled);
|
||||||
|
return DeviceManager::DeviceErrorNoError;
|
||||||
|
} else if (action.actionTypeId() == sensorTagOpticalSensorEnabledActionTypeId) {
|
||||||
|
bool enabled = action.param(sensorTagOpticalSensorEnabledActionOpticalSensorEnabledParamTypeId).value().toBool();
|
||||||
|
device->setStateValue(sensorTagOpticalSensorEnabledStateTypeId, enabled);
|
||||||
|
sensorTag->setOpticalSensorEnabled(enabled);
|
||||||
|
return DeviceManager::DeviceErrorNoError;
|
||||||
|
} else if (action.actionTypeId() == sensorTagAccelerometerEnabledActionTypeId) {
|
||||||
|
bool enabled = action.param(sensorTagAccelerometerEnabledActionAccelerometerEnabledParamTypeId).value().toBool();
|
||||||
|
device->setStateValue(sensorTagAccelerometerEnabledStateTypeId, enabled);
|
||||||
|
sensorTag->setAccelerometerEnabled(enabled);
|
||||||
|
return DeviceManager::DeviceErrorNoError;
|
||||||
|
} else if (action.actionTypeId() == sensorTagGyroscopeEnabledActionTypeId) {
|
||||||
|
bool enabled = action.param(sensorTagGyroscopeEnabledActionGyroscopeEnabledParamTypeId).value().toBool();
|
||||||
|
device->setStateValue(sensorTagGyroscopeEnabledStateTypeId, enabled);
|
||||||
|
sensorTag->setGyroscopeEnabled(enabled);
|
||||||
|
return DeviceManager::DeviceErrorNoError;
|
||||||
|
} else if (action.actionTypeId() == sensorTagMagnetometerEnabledActionTypeId) {
|
||||||
|
bool enabled = action.param(sensorTagMagnetometerEnabledActionMagnetometerEnabledParamTypeId).value().toBool();
|
||||||
|
device->setStateValue(sensorTagMagnetometerEnabledStateTypeId, enabled);
|
||||||
|
sensorTag->setMagnetometerEnabled(enabled);
|
||||||
|
return DeviceManager::DeviceErrorNoError;
|
||||||
|
} else if (action.actionTypeId() == sensorTagMeasurementPeriodActionTypeId) {
|
||||||
|
int period = action.param(sensorTagMeasurementPeriodActionMeasurementPeriodParamTypeId).value().toInt();
|
||||||
|
device->setStateValue(sensorTagMeasurementPeriodStateTypeId, period);
|
||||||
|
sensorTag->setMeasurementPeriod(period);
|
||||||
|
return DeviceManager::DeviceErrorNoError;
|
||||||
|
} else if (action.actionTypeId() == sensorTagMeasurementPeriodMovementActionTypeId) {
|
||||||
|
int period = action.param(sensorTagMeasurementPeriodMovementActionMeasurementPeriodMovementParamTypeId).value().toInt();
|
||||||
|
device->setStateValue(sensorTagMeasurementPeriodMovementStateTypeId, period);
|
||||||
|
sensorTag->setMeasurementPeriodMovement(period);
|
||||||
|
return DeviceManager::DeviceErrorNoError;
|
||||||
|
} else if (action.actionTypeId() == sensorTagMovementSensitivityActionTypeId) {
|
||||||
|
int sensitivity = action.param(sensorTagMovementSensitivityActionMovementSensitivityParamTypeId).value().toInt();
|
||||||
|
device->setStateValue(sensorTagMovementSensitivityStateTypeId, sensitivity);
|
||||||
|
sensorTag->setMovementSensitivity(sensitivity);
|
||||||
|
return DeviceManager::DeviceErrorNoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DeviceManager::DeviceErrorActionTypeNotFound;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2019 Michael Zanetti <michael.zanetti@nymea.io> *
|
||||||
|
* *
|
||||||
|
* This file is part of nymea. *
|
||||||
|
* *
|
||||||
|
* 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 DEVICEPLUGINTEXASINSTRUMENTS_H
|
||||||
|
#define DEVICEPLUGINTEXASINSTRUMENTS_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include "plugin/deviceplugin.h"
|
||||||
|
|
||||||
|
class SensorTag;
|
||||||
|
|
||||||
|
class PluginTimer;
|
||||||
|
|
||||||
|
class DevicePluginTexasInstruments : public DevicePlugin
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PLUGIN_METADATA(IID "io.nymea.DevicePlugin" FILE "deviceplugintexasinstruments.json")
|
||||||
|
Q_INTERFACES(DevicePlugin)
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DevicePluginTexasInstruments(QObject *parent = nullptr);
|
||||||
|
~DevicePluginTexasInstruments() override;
|
||||||
|
|
||||||
|
DeviceManager::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) override;
|
||||||
|
DeviceManager::DeviceSetupStatus setupDevice(Device *device) override;
|
||||||
|
void postSetupDevice(Device *device) override;
|
||||||
|
void deviceRemoved(Device *device) override;
|
||||||
|
DeviceManager::DeviceError executeAction(Device *device, const Action &action) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QHash<Device*, SensorTag*> m_sensorTags;
|
||||||
|
|
||||||
|
PluginTimer *m_reconnectTimer = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DEVICEPLUGINTEXASINSTRUMENTS_H
|
||||||
|
|
@ -0,0 +1,273 @@
|
||||||
|
{
|
||||||
|
"displayName": "Texas Instruments",
|
||||||
|
"name": "TexasInstruments",
|
||||||
|
"id": "ae550a91-e734-4331-9d71-9f37df0b0fa6",
|
||||||
|
"vendors": [
|
||||||
|
{
|
||||||
|
"id": "2edf543e-dc2c-4693-bb0c-e76c0d305fad",
|
||||||
|
"name": "texasInstruments",
|
||||||
|
"displayName": "Texas Instruments",
|
||||||
|
"deviceClasses": [
|
||||||
|
{
|
||||||
|
"id": "158a06b6-b27f-4951-957e-6f1e3b44f604",
|
||||||
|
"name": "sensorTag",
|
||||||
|
"displayName": "Sensor Tag (CC2650)",
|
||||||
|
"createMethods": ["discovery"],
|
||||||
|
"interfaces": ["temperaturesensor", "humiditysensor", "pressuresensor", "lightsensor", "connectable"],
|
||||||
|
"paramTypes": [
|
||||||
|
{
|
||||||
|
"id": "d51ed68e-c84a-4136-a5b5-be2f95fd5a0f",
|
||||||
|
"name": "mac",
|
||||||
|
"displayName": "MAC address",
|
||||||
|
"type": "QString",
|
||||||
|
"inputType": "MacAddress"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateTypes": [
|
||||||
|
{
|
||||||
|
"id": "a9629b11-0f34-47f0-a0f0-f758a6aec2b4",
|
||||||
|
"name": "connected",
|
||||||
|
"displayName": "Connected",
|
||||||
|
"displayNameEvent": "Connected changed",
|
||||||
|
"type": "bool",
|
||||||
|
"cached": false,
|
||||||
|
"defaultValue": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "8359ada9-df1c-4e60-bb87-9e21d05ee2e2",
|
||||||
|
"name": "temperature",
|
||||||
|
"displayName": "temperature",
|
||||||
|
"displayNameEvent": "temperature changed",
|
||||||
|
"type": "double",
|
||||||
|
"unit": "DegreeCelsius",
|
||||||
|
"defaultValue": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "c664e9ec-a045-49ba-add1-1642ceba7c4f",
|
||||||
|
"name": "objectTemperature",
|
||||||
|
"displayName": "Object temperature",
|
||||||
|
"displayNameEvent": "Object temperature changed",
|
||||||
|
"type": "double",
|
||||||
|
"unit": "DegreeCelsius",
|
||||||
|
"defaultValue": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "e83a50ff-96c9-4b6d-889f-f4238353e794",
|
||||||
|
"name": "humidity",
|
||||||
|
"displayName": "Humidity",
|
||||||
|
"displayNameEvent": "Humidity changed",
|
||||||
|
"type": "double",
|
||||||
|
"minValue": 0,
|
||||||
|
"maxValue": 100,
|
||||||
|
"unit": "Percentage",
|
||||||
|
"defaultValue": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "645633ad-77d4-45b2-8be8-d6ca7a12eb7a",
|
||||||
|
"name": "pressure",
|
||||||
|
"displayName": "Barometric pressure",
|
||||||
|
"displayNameEvent": "Barometric pressure changed",
|
||||||
|
"type": "double",
|
||||||
|
"unit": "HectoPascal",
|
||||||
|
"defaultValue": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "6635dce4-2d8d-4608-a836-768c3014f356",
|
||||||
|
"name": "lightIntensity",
|
||||||
|
"displayName": "Light intensity",
|
||||||
|
"displayNameEvent": "Light intensity changed",
|
||||||
|
"type": "double",
|
||||||
|
"unit": "Lux",
|
||||||
|
"defaultValue": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "4be5ca26-0565-419d-b18b-2a5a385d2a3d",
|
||||||
|
"name": "moving",
|
||||||
|
"displayName": "Moving",
|
||||||
|
"displayNameEvent": "Moving changed",
|
||||||
|
"type": "bool",
|
||||||
|
"cached": false,
|
||||||
|
"defaultValue": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "758d9b39-7390-40f5-8e19-d8b0f4a0a0c6",
|
||||||
|
"name": "magnetDetected",
|
||||||
|
"displayName": "Magnet detected",
|
||||||
|
"displayNameEvent": "Magnet detected changed",
|
||||||
|
"type": "bool",
|
||||||
|
"cached": false,
|
||||||
|
"defaultValue": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "8995e49e-ca2d-4dd9-a22f-de6c566c2115",
|
||||||
|
"name": "leftButtonPressed",
|
||||||
|
"displayName": "Left button pressed",
|
||||||
|
"displayNameEvent": "Left button pressed changed",
|
||||||
|
"type": "bool",
|
||||||
|
"cached": false,
|
||||||
|
"defaultValue": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ef8eedc5-6a45-4dfb-bb55-ada1a931b20b",
|
||||||
|
"name": "rightButtonPressed",
|
||||||
|
"displayName": "Right button pressed",
|
||||||
|
"displayNameEvent": "Right button pressed changed",
|
||||||
|
"type": "bool",
|
||||||
|
"cached": false,
|
||||||
|
"defaultValue": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "8d692132-f950-486f-b3dd-fe1ebc574e1d",
|
||||||
|
"name": "greenLed",
|
||||||
|
"displayName": "Green LED",
|
||||||
|
"displayNameEvent": "Green LED power changed",
|
||||||
|
"displayNameAction": "Set green LED power",
|
||||||
|
"type": "bool",
|
||||||
|
"cached": false,
|
||||||
|
"defaultValue": false,
|
||||||
|
"writable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bb585725-6393-42de-aea2-ea4f525ad348",
|
||||||
|
"name": "redLed",
|
||||||
|
"displayName": "Red LED",
|
||||||
|
"displayNameEvent": "Red LED power changed",
|
||||||
|
"displayNameAction": "Set red LED power",
|
||||||
|
"type": "bool",
|
||||||
|
"cached": false,
|
||||||
|
"defaultValue": false,
|
||||||
|
"writable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "d522c536-4427-4c53-9980-7820b2649aad",
|
||||||
|
"name": "buzzer",
|
||||||
|
"displayName": "Buzzer",
|
||||||
|
"displayNameEvent": "Buzzer power changed",
|
||||||
|
"displayNameAction": "Set buzzer power",
|
||||||
|
"type": "bool",
|
||||||
|
"cached": false,
|
||||||
|
"defaultValue": false,
|
||||||
|
"writable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "6f0e40a2-0f97-4c1e-8229-757e3c18b345",
|
||||||
|
"name": "temperatureSensorEnabled",
|
||||||
|
"displayName": "Temperature sensor enabled",
|
||||||
|
"displayNameEvent": "Temperature sensor enabled changed",
|
||||||
|
"displayNameAction": "Set temperature sensor enabled",
|
||||||
|
"type": "bool",
|
||||||
|
"defaultValue": true,
|
||||||
|
"writable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "29881172-626a-42d5-83b8-3e2e5ca533be",
|
||||||
|
"name": "humiditySensorEnabled",
|
||||||
|
"displayName": "Humidity sensor enabled",
|
||||||
|
"displayNameEvent": "Humidity sensor enabled changed",
|
||||||
|
"displayNameAction": "Set humidity sensor enabled",
|
||||||
|
"type": "bool",
|
||||||
|
"defaultValue": true,
|
||||||
|
"writable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "50e5e282-9707-4b31-bb3f-a6ca30a7e1ff",
|
||||||
|
"name": "pressureSensorEnabled",
|
||||||
|
"displayName": "Pressure sensor enabled",
|
||||||
|
"displayNameEvent": "Pressure sensor enabled changed",
|
||||||
|
"displayNameAction": "Set pressure sensor enabled",
|
||||||
|
"type": "bool",
|
||||||
|
"defaultValue": true,
|
||||||
|
"writable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1460a6d6-9fb4-4385-b27b-ee4b7594e454",
|
||||||
|
"name": "opticalSensorEnabled",
|
||||||
|
"displayName": "Optical sensor enabled",
|
||||||
|
"displayNameEvent": "Optical sensor enabled changed",
|
||||||
|
"displayNameAction": "Set optical sensor enabled",
|
||||||
|
"type": "bool",
|
||||||
|
"defaultValue": true,
|
||||||
|
"writable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "5786c91a-d94d-461a-8d22-f978dd1438ab",
|
||||||
|
"name": "accelerometerEnabled",
|
||||||
|
"displayName": "Accelerometer enabled",
|
||||||
|
"displayNameEvent": "Accelerometer enabled changed",
|
||||||
|
"displayNameAction": "Set accelerometer enabled",
|
||||||
|
"type": "bool",
|
||||||
|
"defaultValue": true,
|
||||||
|
"writable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "94517544-cb97-4816-8993-cb4cf2651a1e",
|
||||||
|
"name": "gyroscopeEnabled",
|
||||||
|
"displayName": "Gyroscope enabled",
|
||||||
|
"displayNameEvent": "Gyroscope enabled changed",
|
||||||
|
"displayNameAction": "Set gyroscope enabled",
|
||||||
|
"type": "bool",
|
||||||
|
"defaultValue": true,
|
||||||
|
"writable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "96aae111-b1c1-48a1-9b1f-b56efa546d0d",
|
||||||
|
"name": "magnetometerEnabled",
|
||||||
|
"displayName": "Magnetometer enabled",
|
||||||
|
"displayNameEvent": "Magnetometer enabled changed",
|
||||||
|
"displayNameAction": "Set magnetometer enabled",
|
||||||
|
"type": "bool",
|
||||||
|
"defaultValue": true,
|
||||||
|
"writable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "c5308565-5dc9-409e-ae99-577c212c7a92",
|
||||||
|
"name": "measurementPeriod",
|
||||||
|
"displayName": "Measurement period for enviromental sensors",
|
||||||
|
"displayNameEvent": "Measurement period for enviromental sensors changed",
|
||||||
|
"displayNameAction": "Set measurement period for enviromental sensors",
|
||||||
|
"type": "int",
|
||||||
|
"minValue": 10,
|
||||||
|
"maxValue": 2500,
|
||||||
|
"defaultValue": 2000,
|
||||||
|
"writable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "5237c89c-c21d-4d78-ac99-8be661b40da7",
|
||||||
|
"name": "measurementPeriodMovement",
|
||||||
|
"displayName": "Measurement period movement sensor",
|
||||||
|
"displayNameEvent": "Measurement period movement sensor changed",
|
||||||
|
"displayNameAction": "Set measurement period movement sensor",
|
||||||
|
"type": "int",
|
||||||
|
"minValue": 10,
|
||||||
|
"maxValue": 2500,
|
||||||
|
"defaultValue": 300,
|
||||||
|
"writable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "a3298d16-eea6-4474-9061-90466e92d476",
|
||||||
|
"name": "movementSensitivity",
|
||||||
|
"displayName": "Movement sensitivity",
|
||||||
|
"displayNameEvent": "Movement sensitivity changed",
|
||||||
|
"displayNameAction": "Set movement sensitivity",
|
||||||
|
"type": "int",
|
||||||
|
"unit": "Percentage",
|
||||||
|
"minValue": 0,
|
||||||
|
"maxValue": 100,
|
||||||
|
"defaultValue": 40,
|
||||||
|
"writable": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"actionTypes": [
|
||||||
|
{
|
||||||
|
"id": "a048ab2e-4f17-4467-a166-a7572156c07e",
|
||||||
|
"name": "buzzerImpulse",
|
||||||
|
"displayName": "Buzzer impulse"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,329 @@
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2015-2018 Simon Stuerz <simon.stuerz@guh.io> *
|
||||||
|
* *
|
||||||
|
* This file is part of nymea. *
|
||||||
|
* *
|
||||||
|
* 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/>. *
|
||||||
|
* *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
#include "sensordataprocessor.h"
|
||||||
|
#include "extern-plugininfo.h"
|
||||||
|
#include "math.h"
|
||||||
|
|
||||||
|
#include <QVector3D>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QDataStream>
|
||||||
|
#include <QDateTime>
|
||||||
|
|
||||||
|
SensorDataProcessor::SensorDataProcessor(Device *device, QObject *parent) :
|
||||||
|
QObject(parent),
|
||||||
|
m_device(device)
|
||||||
|
{
|
||||||
|
// Create data filters
|
||||||
|
m_temperatureFilter = new SensorFilter(SensorFilter::TypeLowPass, this);
|
||||||
|
m_temperatureFilter->setLowPassAlpha(0.1);
|
||||||
|
m_temperatureFilter->setFilterWindowSize(30);
|
||||||
|
|
||||||
|
m_objectTemperatureFilter = new SensorFilter(SensorFilter::TypeLowPass, this);
|
||||||
|
m_objectTemperatureFilter->setLowPassAlpha(0.4);
|
||||||
|
m_objectTemperatureFilter->setFilterWindowSize(20);
|
||||||
|
|
||||||
|
m_humidityFilter = new SensorFilter(SensorFilter::TypeLowPass, this);
|
||||||
|
m_humidityFilter->setLowPassAlpha(0.1);
|
||||||
|
m_humidityFilter->setFilterWindowSize(30);
|
||||||
|
|
||||||
|
m_pressureFilter = new SensorFilter(SensorFilter::TypeLowPass, this);
|
||||||
|
m_pressureFilter->setLowPassAlpha(0.1);
|
||||||
|
m_pressureFilter->setFilterWindowSize(30);
|
||||||
|
|
||||||
|
m_opticalFilter = new SensorFilter(SensorFilter::TypeLowPass, this);
|
||||||
|
m_opticalFilter->setLowPassAlpha(0.01);
|
||||||
|
m_opticalFilter->setFilterWindowSize(10);
|
||||||
|
|
||||||
|
m_accelerometerFilter = new SensorFilter(SensorFilter::TypeLowPass, this);
|
||||||
|
m_accelerometerFilter->setLowPassAlpha(0.6);
|
||||||
|
m_accelerometerFilter->setFilterWindowSize(40);
|
||||||
|
|
||||||
|
// Check if the data should be logged
|
||||||
|
if (m_filterDebug) {
|
||||||
|
m_logFile = new QFile("/tmp/multisensor.log", this);
|
||||||
|
if (!m_logFile->open(QIODevice::Append | QIODevice::Text)) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Could not open log file" << m_logFile->fileName();
|
||||||
|
delete m_logFile;
|
||||||
|
m_logFile = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SensorDataProcessor::~SensorDataProcessor()
|
||||||
|
{
|
||||||
|
if (m_logFile) {
|
||||||
|
m_logFile->close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorDataProcessor::setAccelerometerRange(int accelerometerRange)
|
||||||
|
{
|
||||||
|
m_accelerometerRange = accelerometerRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorDataProcessor::setMovementSensitivity(int movementSensitivity)
|
||||||
|
{
|
||||||
|
m_movementSensitivity = movementSensitivity;
|
||||||
|
}
|
||||||
|
|
||||||
|
double SensorDataProcessor::roundValue(float value)
|
||||||
|
{
|
||||||
|
int tmpValue = static_cast<int>(value * 10);
|
||||||
|
return static_cast<double>(tmpValue) / 10.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SensorDataProcessor::testBitUint8(quint8 value, int bitPosition)
|
||||||
|
{
|
||||||
|
return (((value)>> (bitPosition)) & 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorDataProcessor::processTemperatureData(const QByteArray &data)
|
||||||
|
{
|
||||||
|
Q_ASSERT(data.count() == 4);
|
||||||
|
|
||||||
|
quint16 rawObjectTemperature = 0;
|
||||||
|
quint16 rawAmbientTemperature = 0;
|
||||||
|
|
||||||
|
QByteArray payload(data);
|
||||||
|
QDataStream stream(&payload, QIODevice::ReadOnly);
|
||||||
|
stream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
stream >> rawObjectTemperature >> rawAmbientTemperature ;
|
||||||
|
|
||||||
|
float scaleFactor = 0.03125;
|
||||||
|
float objectTemperature = static_cast<float>(rawObjectTemperature) / 4 * scaleFactor;
|
||||||
|
float ambientTemperature = static_cast<float>(rawAmbientTemperature) / 4 * scaleFactor;
|
||||||
|
|
||||||
|
//qCDebug(dcTexasInstruments()) << "Temperature value" << data.toHex();
|
||||||
|
//qCDebug(dcTexasInstruments()) << "Object temperature" << roundValue(objectTemperature) << "°C";
|
||||||
|
//qCDebug(dcTexasInstruments()) << "Ambient temperature" << roundValue(ambientTemperature) << "°C";
|
||||||
|
|
||||||
|
float objectTemperatureFiltered = m_objectTemperatureFilter->filterValue(objectTemperature);
|
||||||
|
float ambientTemperatureFiltered = m_temperatureFilter->filterValue(ambientTemperature);
|
||||||
|
|
||||||
|
if (m_objectTemperatureFilter->isReady()) {
|
||||||
|
m_device->setStateValue(sensorTagObjectTemperatureStateTypeId, roundValue(objectTemperatureFiltered));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: only change the state once the filter has collected enough data
|
||||||
|
if (m_temperatureFilter->isReady()) {
|
||||||
|
m_device->setStateValue(sensorTagTemperatureStateTypeId, roundValue(ambientTemperatureFiltered));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorDataProcessor::processKeyData(const QByteArray &data)
|
||||||
|
{
|
||||||
|
Q_ASSERT(data.count() == 1);
|
||||||
|
quint8 flags = static_cast<quint8>(data.at(0));
|
||||||
|
setLeftButtonPressed(testBitUint8(flags, 0));
|
||||||
|
setRightButtonPressed(testBitUint8(flags, 1));
|
||||||
|
setMagnetDetected(testBitUint8(flags, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorDataProcessor::processHumidityData(const QByteArray &data)
|
||||||
|
{
|
||||||
|
Q_ASSERT(data.count() == 4);
|
||||||
|
quint16 rawHumidityTemperature = 0;
|
||||||
|
quint16 rawHumidity = 0;
|
||||||
|
|
||||||
|
QByteArray payload(data);
|
||||||
|
QDataStream stream(&payload, QIODevice::ReadOnly);
|
||||||
|
stream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
stream >> rawHumidityTemperature >> rawHumidity ;
|
||||||
|
|
||||||
|
// Note: we don't need the temperature measurement from the humidity sensor
|
||||||
|
//double humidityTemperature = (rawHumidityTemperature / 65536.0 * 165.0) - 40;
|
||||||
|
double humidity = rawHumidity / 65536.0 * 100.0;
|
||||||
|
double humidityFiltered = m_humidityFilter->filterValue(humidity);
|
||||||
|
|
||||||
|
if (m_humidityFilter->isReady()) {
|
||||||
|
m_device->setStateValue(sensorTagHumidityStateTypeId, roundValue(humidityFiltered));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorDataProcessor::processPressureData(const QByteArray &data)
|
||||||
|
{
|
||||||
|
Q_ASSERT(data.count() == 6);
|
||||||
|
|
||||||
|
QByteArray temperatureData(data.left(3));
|
||||||
|
quint32 rawTemperature = static_cast<quint8>(temperatureData.at(2));
|
||||||
|
rawTemperature <<= 8;
|
||||||
|
rawTemperature |= static_cast<quint8>(temperatureData.at(1));
|
||||||
|
rawTemperature <<= 8;
|
||||||
|
rawTemperature |= static_cast<quint8>(temperatureData.at(0));
|
||||||
|
|
||||||
|
QByteArray pressureData(data.right(3));
|
||||||
|
quint32 rawPressure = static_cast<quint8>(pressureData.at(2));
|
||||||
|
rawPressure <<= 8;
|
||||||
|
rawPressure |= static_cast<quint8>(pressureData.at(1));
|
||||||
|
rawPressure <<= 8;
|
||||||
|
rawPressure |= static_cast<quint8>(pressureData.at(0));
|
||||||
|
|
||||||
|
// Note: we don't need the temperature measurement from the barometic pressure sensor
|
||||||
|
//qCDebug(dcTexasInstruments()) << "Pressure temperature:" << roundValue(rawTemperature / 100.0) << "°C";
|
||||||
|
//qCDebug(dcTexasInstruments()) << "Pressure:" << roundValue(rawPressure / 100.0) << "mBar";
|
||||||
|
|
||||||
|
double pressureFiltered = m_pressureFilter->filterValue(rawPressure / 100.0);
|
||||||
|
if (m_pressureFilter->isReady()) {
|
||||||
|
m_device->setStateValue(sensorTagPressureStateTypeId, roundValue(pressureFiltered));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorDataProcessor::processOpticalData(const QByteArray &data)
|
||||||
|
{
|
||||||
|
Q_ASSERT(data.count() == 2);
|
||||||
|
|
||||||
|
quint16 rawOptical = 0;
|
||||||
|
QByteArray payload(data);
|
||||||
|
QDataStream stream(&payload, QIODevice::ReadOnly);
|
||||||
|
stream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
stream >> rawOptical;
|
||||||
|
|
||||||
|
quint16 lumm = rawOptical & 0x0FFF;
|
||||||
|
quint16 lume = (rawOptical & 0xF000) >> 12;
|
||||||
|
|
||||||
|
double lux = lumm * (0.01 * pow(2,lume));
|
||||||
|
|
||||||
|
//qCDebug(dcTexasInstruments()) << "Lux:" << lux;
|
||||||
|
|
||||||
|
double luxFiltered = m_opticalFilter->filterValue(lux);
|
||||||
|
if (m_opticalFilter->isReady()) {
|
||||||
|
m_device->setStateValue(sensorTagLightIntensityStateTypeId, qRound(luxFiltered));
|
||||||
|
}
|
||||||
|
|
||||||
|
logSensorValue(lux, qRound(luxFiltered));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorDataProcessor::processMovementData(const QByteArray &data)
|
||||||
|
{
|
||||||
|
//qCDebug(dcTexasInstruments()) << "--> Movement value" << data.toHex();
|
||||||
|
|
||||||
|
QByteArray payload(data);
|
||||||
|
QDataStream stream(&payload, QIODevice::ReadOnly);
|
||||||
|
stream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
|
qint16 gyroXRaw = 0; qint16 gyroYRaw = 0; qint16 gyroZRaw = 0;
|
||||||
|
stream >> gyroXRaw >> gyroYRaw >> gyroZRaw;
|
||||||
|
|
||||||
|
qint16 accXRaw = 0; qint16 accYRaw = 0; qint16 accZRaw = 0;
|
||||||
|
stream >> accXRaw >> accYRaw >> accZRaw;
|
||||||
|
|
||||||
|
qint16 magXRaw = 0; qint16 magYRaw = 0; qint16 magZRaw = 0;
|
||||||
|
stream >> magXRaw >> magYRaw >> magZRaw;
|
||||||
|
|
||||||
|
|
||||||
|
// Calculate rotation [deg/s], Range +- 250
|
||||||
|
float gyroX = static_cast<float>(gyroXRaw) / (65536 / 500);
|
||||||
|
float gyroY = static_cast<float>(gyroYRaw) / (65536 / 500);
|
||||||
|
float gyroZ = static_cast<float>(gyroZRaw) / (65536 / 500);
|
||||||
|
|
||||||
|
// Calculate acceleration [G], Range +- m_accelerometerRange
|
||||||
|
float accX = static_cast<float>(accXRaw) / (32768 / static_cast<int>(m_accelerometerRange));
|
||||||
|
float accY = static_cast<float>(accYRaw) / (32768 / static_cast<int>(m_accelerometerRange));
|
||||||
|
float accZ = static_cast<float>(accZRaw) / (32768 / static_cast<int>(m_accelerometerRange));
|
||||||
|
|
||||||
|
// Calculate magnetism [uT], Range +- 4900
|
||||||
|
float magX = static_cast<float>(magXRaw);
|
||||||
|
float magY = static_cast<float>(magYRaw);
|
||||||
|
float magZ = static_cast<float>(magZRaw);
|
||||||
|
|
||||||
|
|
||||||
|
//qCDebug(dcTexasInstruments()) << "Accelerometer x:" << accX << " y:" << accY << " z:" << accZ;
|
||||||
|
//qCDebug(dcTexasInstruments()) << "Gyroscope x:" << gyroX << " y:" << gyroY << " z:" << gyroZ;
|
||||||
|
//qCDebug(dcTexasInstruments()) << "Magnetometer x:" << magX << " y:" << magY << " z:" << magZ;
|
||||||
|
|
||||||
|
QVector3D accelerometerVector(accX, accY, accZ);
|
||||||
|
QVector3D gyroscopeVector(gyroX, gyroY, gyroZ);
|
||||||
|
QVector3D magnetometerVector(magX, magY, magZ);
|
||||||
|
|
||||||
|
Q_UNUSED(gyroscopeVector)
|
||||||
|
Q_UNUSED(magnetometerVector)
|
||||||
|
|
||||||
|
double filteredVectorLength = m_accelerometerFilter->filterValue(accelerometerVector.length());
|
||||||
|
|
||||||
|
// Initialize the accelerometer value if no data known yet
|
||||||
|
if (m_lastAccelerometerVectorLenght == -99999) {
|
||||||
|
m_lastAccelerometerVectorLenght = filteredVectorLength;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double delta = qAbs(qAbs(m_lastAccelerometerVectorLenght) - qAbs(filteredVectorLength));
|
||||||
|
bool motionDetected = (delta >= m_movementSensitivity);
|
||||||
|
m_device->setStateValue(sensorTagMovingStateTypeId, motionDetected);
|
||||||
|
m_lastAccelerometerVectorLenght = filteredVectorLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorDataProcessor::reset()
|
||||||
|
{
|
||||||
|
m_lastAccelerometerVectorLenght = -99999;
|
||||||
|
|
||||||
|
// Reset data filters
|
||||||
|
m_temperatureFilter->reset();
|
||||||
|
m_objectTemperatureFilter->reset();
|
||||||
|
m_humidityFilter->reset();
|
||||||
|
m_pressureFilter->reset();
|
||||||
|
m_opticalFilter->reset();
|
||||||
|
m_accelerometerFilter->reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorDataProcessor::setLeftButtonPressed(bool pressed)
|
||||||
|
{
|
||||||
|
if (m_leftButtonPressed == pressed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
qCDebug(dcTexasInstruments()) << "Left button" << (pressed ? "pressed" : "released");
|
||||||
|
m_leftButtonPressed = pressed;
|
||||||
|
m_device->setStateValue(sensorTagLeftButtonPressedStateTypeId, m_leftButtonPressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorDataProcessor::setRightButtonPressed(bool pressed)
|
||||||
|
{
|
||||||
|
if (m_rightButtonPressed == pressed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
qCDebug(dcTexasInstruments()) << "Right button" << (pressed ? "pressed" : "released");
|
||||||
|
m_rightButtonPressed = pressed;
|
||||||
|
m_device->setStateValue(sensorTagRightButtonPressedStateTypeId, m_rightButtonPressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorDataProcessor::setMagnetDetected(bool detected)
|
||||||
|
{
|
||||||
|
if (m_magnetDetected == detected)
|
||||||
|
return;
|
||||||
|
|
||||||
|
qCDebug(dcTexasInstruments()) << "Magnet detector" << (detected ? "active" : "inactive");
|
||||||
|
m_magnetDetected = detected;
|
||||||
|
m_device->setStateValue(sensorTagMagnetDetectedStateTypeId, m_magnetDetected);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorDataProcessor::logSensorValue(double originalValue, double filteredValue)
|
||||||
|
{
|
||||||
|
if (!m_filterDebug || !m_logFile)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QString logLine = QString("%1 %2 %3\n").arg(QDateTime::currentDateTime().toTime_t()).arg(originalValue).arg(filteredValue);
|
||||||
|
|
||||||
|
QTextStream logStream(m_logFile);
|
||||||
|
logStream.setCodec("UTF-8");
|
||||||
|
logStream << logLine;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2015-2018 Simon Stuerz <simon.stuerz@guh.io> *
|
||||||
|
* *
|
||||||
|
* This file is part of nymea. *
|
||||||
|
* *
|
||||||
|
* 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 SENSORDATAPROCESSOR_H
|
||||||
|
#define SENSORDATAPROCESSOR_H
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include "plugin/device.h"
|
||||||
|
#include "extern-plugininfo.h"
|
||||||
|
|
||||||
|
#include "sensorfilter.h"
|
||||||
|
|
||||||
|
class SensorDataProcessor : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit SensorDataProcessor(Device *device, QObject *parent = nullptr);
|
||||||
|
~SensorDataProcessor();
|
||||||
|
|
||||||
|
void setAccelerometerRange(int accelerometerRange);
|
||||||
|
void setMovementSensitivity(int movementSensitivity);
|
||||||
|
|
||||||
|
static double roundValue(float value);
|
||||||
|
static bool testBitUint8(quint8 value, int bitPosition);
|
||||||
|
|
||||||
|
void processTemperatureData(const QByteArray &data);
|
||||||
|
void processKeyData(const QByteArray &data);
|
||||||
|
void processHumidityData(const QByteArray &data);
|
||||||
|
void processPressureData(const QByteArray &data);
|
||||||
|
void processOpticalData(const QByteArray &data);
|
||||||
|
void processMovementData(const QByteArray &data);
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Device *m_device = nullptr;
|
||||||
|
double m_lastAccelerometerVectorLenght = -99999;
|
||||||
|
|
||||||
|
int m_accelerometerRange = 16;
|
||||||
|
double m_movementSensitivity = 0.5;
|
||||||
|
|
||||||
|
bool m_leftButtonPressed = false;
|
||||||
|
bool m_rightButtonPressed = false;
|
||||||
|
bool m_magnetDetected = false;
|
||||||
|
|
||||||
|
// Log sensor data for debugging filters
|
||||||
|
// Note: set this to true for enable sensor filter logging
|
||||||
|
bool m_filterDebug = true;
|
||||||
|
QFile *m_logFile = nullptr;
|
||||||
|
|
||||||
|
SensorFilter *m_temperatureFilter = nullptr;
|
||||||
|
SensorFilter *m_objectTemperatureFilter = nullptr;
|
||||||
|
SensorFilter *m_humidityFilter = nullptr;
|
||||||
|
SensorFilter *m_pressureFilter = nullptr;
|
||||||
|
SensorFilter *m_opticalFilter = nullptr;
|
||||||
|
SensorFilter *m_accelerometerFilter = nullptr;
|
||||||
|
|
||||||
|
// Set methods
|
||||||
|
void setLeftButtonPressed(bool pressed);
|
||||||
|
void setRightButtonPressed(bool pressed);
|
||||||
|
void setMagnetDetected(bool detected);
|
||||||
|
|
||||||
|
void logSensorValue(double originalValue, double filteredValue);
|
||||||
|
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SENSORDATAPROCESSOR_H
|
||||||
|
|
@ -0,0 +1,178 @@
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2015-2018 Simon Stuerz <simon.stuerz@guh.io> *
|
||||||
|
* *
|
||||||
|
* This file is part of nymea. *
|
||||||
|
* *
|
||||||
|
* 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/>. *
|
||||||
|
* *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
#include "sensorfilter.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
SensorFilter::SensorFilter(Type filterType, QObject *parent) :
|
||||||
|
QObject(parent),
|
||||||
|
m_filterType(filterType)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
float SensorFilter::filterValue(float value)
|
||||||
|
{
|
||||||
|
float resultValue = value;
|
||||||
|
switch (m_filterType) {
|
||||||
|
case TypeLowPass:
|
||||||
|
resultValue = lowPassFilterValue(value);
|
||||||
|
break;
|
||||||
|
case TypeHighPass:
|
||||||
|
resultValue = highPassFilterValue(value);
|
||||||
|
break;
|
||||||
|
case TypeAverage:
|
||||||
|
resultValue = averageFilterValue(value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SensorFilter::isReady() const
|
||||||
|
{
|
||||||
|
// Note: filter is ready once 10% of window filled
|
||||||
|
return m_inputData.size() >= m_filterWindowSize * 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorFilter::reset()
|
||||||
|
{
|
||||||
|
m_averageSum = 0;
|
||||||
|
m_inputData.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
SensorFilter::Type SensorFilter::filterType() const
|
||||||
|
{
|
||||||
|
return m_filterType;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<float> SensorFilter::inputData() const
|
||||||
|
{
|
||||||
|
return m_inputData;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<float> SensorFilter::outputData() const
|
||||||
|
{
|
||||||
|
return m_outputData;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint SensorFilter::windowSize() const
|
||||||
|
{
|
||||||
|
return m_filterWindowSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorFilter::setFilterWindowSize(uint windowSize)
|
||||||
|
{
|
||||||
|
Q_ASSERT_X(windowSize > 0, "value out of range", "The filter window size must be bigger than 0");
|
||||||
|
m_filterWindowSize = windowSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
float SensorFilter::lowPassAlpha() const
|
||||||
|
{
|
||||||
|
return m_lowPassAlpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorFilter::setLowPassAlpha(float alpha)
|
||||||
|
{
|
||||||
|
Q_ASSERT_X(alpha > 0 && alpha <= 1, "value out of range", "The alpha low pass filter value must be [ 0 < alpha <= 1 ]");
|
||||||
|
m_lowPassAlpha = alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
float SensorFilter::highPassAlpha() const
|
||||||
|
{
|
||||||
|
return m_highPassAlpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorFilter::setHighPassAlpha(float alpha)
|
||||||
|
{
|
||||||
|
Q_ASSERT_X(alpha > 0 && alpha <= 1, "value out of range", "The alpha high pass filter value must be [ 0 < alpha <= 1 ]");
|
||||||
|
m_highPassAlpha = alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorFilter::addInputValue(float value)
|
||||||
|
{
|
||||||
|
m_inputData.append(value);
|
||||||
|
if (static_cast<uint>(m_inputData.size()) > m_filterWindowSize) {
|
||||||
|
m_inputData.removeFirst();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float SensorFilter::lowPassFilterValue(float value)
|
||||||
|
{
|
||||||
|
addInputValue(value);
|
||||||
|
|
||||||
|
// Check if we have enough data for filtering
|
||||||
|
if (m_inputData.size() < 2) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<float> outputData;
|
||||||
|
outputData.append(m_inputData.at(0));
|
||||||
|
for (int i = 1; i < m_inputData.size(); i++) {
|
||||||
|
// y[i] := y[i-1] + α * (x[i] - y[i-1])
|
||||||
|
outputData.append(outputData.at(i - 1) + m_lowPassAlpha * (m_inputData.at(i) - outputData.at(i - 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_outputData = outputData;
|
||||||
|
|
||||||
|
return m_outputData.last();
|
||||||
|
}
|
||||||
|
|
||||||
|
float SensorFilter::highPassFilterValue(float value)
|
||||||
|
{
|
||||||
|
addInputValue(value);
|
||||||
|
|
||||||
|
// Check if we have enough data for filtering
|
||||||
|
if (m_inputData.size() < 2) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<float> outputData;
|
||||||
|
outputData.append(m_inputData.at(0));
|
||||||
|
for (int i = 1; i < m_inputData.size(); i++) {
|
||||||
|
// y[i] := α * y[i-1] + α * (x[i] - x[i-1])
|
||||||
|
outputData.append(m_highPassAlpha * outputData.at(i - 1) + m_highPassAlpha * (m_inputData.at(i) - m_inputData.at(i - 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_outputData = outputData;
|
||||||
|
return m_outputData.last();
|
||||||
|
}
|
||||||
|
|
||||||
|
float SensorFilter::averageFilterValue(float value)
|
||||||
|
{
|
||||||
|
if (m_inputData.isEmpty()) {
|
||||||
|
addInputValue(value);
|
||||||
|
m_averageSum = value;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (static_cast<uint>(m_inputData.size()) >= m_filterWindowSize) {
|
||||||
|
m_averageSum -= m_inputData.takeFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
addInputValue(value);
|
||||||
|
m_averageSum += value;
|
||||||
|
return m_averageSum / m_inputData.size();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2015-2018 Simon Stuerz <simon.stuerz@guh.io> *
|
||||||
|
* *
|
||||||
|
* This file is part of nymea. *
|
||||||
|
* *
|
||||||
|
* 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 SENSORFILTER_H
|
||||||
|
#define SENSORFILTER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
|
class SensorFilter : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
enum Type {
|
||||||
|
TypeLowPass,
|
||||||
|
TypeHighPass,
|
||||||
|
TypeAverage
|
||||||
|
};
|
||||||
|
Q_ENUM(Type)
|
||||||
|
|
||||||
|
explicit SensorFilter(Type filterType, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
float filterValue(float value);
|
||||||
|
|
||||||
|
bool isReady() const;
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
Type filterType() const;
|
||||||
|
|
||||||
|
QVector<float> inputData() const;
|
||||||
|
QVector<float> outputData() const;
|
||||||
|
|
||||||
|
// Filter configuration
|
||||||
|
uint windowSize() const;
|
||||||
|
void setFilterWindowSize(uint windowSize = 20);
|
||||||
|
|
||||||
|
float lowPassAlpha() const;
|
||||||
|
void setLowPassAlpha(float alpha = 0.2f);
|
||||||
|
|
||||||
|
float highPassAlpha() const;
|
||||||
|
void setHighPassAlpha(float alpha = 0.2f);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Type m_filterType = TypeLowPass;
|
||||||
|
uint m_filterWindowSize = 20;
|
||||||
|
float m_lowPassAlpha = 0.2f;
|
||||||
|
float m_highPassAlpha = 0.2f;
|
||||||
|
|
||||||
|
float m_averageSum = 0;
|
||||||
|
|
||||||
|
QVector<float> m_inputData;
|
||||||
|
QVector<float> m_outputData;
|
||||||
|
|
||||||
|
void addInputValue(float value);
|
||||||
|
|
||||||
|
// Filter methods
|
||||||
|
float lowPassFilterValue(float value);
|
||||||
|
float highPassFilterValue(float value);
|
||||||
|
float averageFilterValue(float value);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SENSORFILTER_H
|
||||||
|
|
@ -0,0 +1,912 @@
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2015-2018 Simon Stuerz <simon.stuerz@guh.io> *
|
||||||
|
* *
|
||||||
|
* 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/>. *
|
||||||
|
* *
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
#include "sensortag.h"
|
||||||
|
#include "extern-plugininfo.h"
|
||||||
|
#include "math.h"
|
||||||
|
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QVector3D>
|
||||||
|
#include <QDataStream>
|
||||||
|
|
||||||
|
SensorTag::SensorTag(Device *device, BluetoothLowEnergyDevice *bluetoothDevice, QObject *parent) :
|
||||||
|
QObject(parent),
|
||||||
|
m_device(device),
|
||||||
|
m_bluetoothDevice(bluetoothDevice),
|
||||||
|
m_dataProcessor(new SensorDataProcessor(m_device, this))
|
||||||
|
{
|
||||||
|
connect(m_bluetoothDevice, &BluetoothLowEnergyDevice::connectedChanged, this, &SensorTag::onConnectedChanged);
|
||||||
|
connect(m_bluetoothDevice, &BluetoothLowEnergyDevice::servicesDiscoveryFinished, this, &SensorTag::onServiceDiscoveryFinished);
|
||||||
|
}
|
||||||
|
|
||||||
|
Device *SensorTag::device()
|
||||||
|
{
|
||||||
|
return m_device;
|
||||||
|
}
|
||||||
|
|
||||||
|
BluetoothLowEnergyDevice *SensorTag::bluetoothDevice()
|
||||||
|
{
|
||||||
|
return m_bluetoothDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::setTemperatureSensorEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
qCDebug(dcTexasInstruments()) << "Temperature sensor" << (enabled ? "enabled" : "disabled");
|
||||||
|
|
||||||
|
if (m_temperatureEnabled == enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_temperatureEnabled = enabled;
|
||||||
|
setTemperatureSensorPower(m_temperatureEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::setHumiditySensorEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
qCDebug(dcTexasInstruments()) << "Humidity sensor" << (enabled ? "enabled" : "disabled");
|
||||||
|
|
||||||
|
if (m_humidityEnabled == enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_humidityEnabled = enabled;
|
||||||
|
setHumiditySensorPower(m_humidityEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::setPressureSensorEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
qCDebug(dcTexasInstruments()) << "Pressure sensor" << (enabled ? "enabled" : "disabled");
|
||||||
|
|
||||||
|
if (m_pressureEnabled == enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_pressureEnabled = enabled;
|
||||||
|
setPressureSensorPower(m_pressureEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::setOpticalSensorEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
qCDebug(dcTexasInstruments()) << "Optical sensor" << (enabled ? "enabled" : "disabled");
|
||||||
|
|
||||||
|
if (m_opticalEnabled == enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_opticalEnabled = enabled;
|
||||||
|
setOpticalSensorPower(m_opticalEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::setAccelerometerEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
qCDebug(dcTexasInstruments()) << "Accelerometer" << (enabled ? "enabled" : "disabled");
|
||||||
|
|
||||||
|
if (m_accelerometerEnabled == enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_accelerometerEnabled = enabled;
|
||||||
|
configureMovement();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::setAccelerometerRange(const SensorTag::SensorAccelerometerRange &range)
|
||||||
|
{
|
||||||
|
qCDebug(dcTexasInstruments()) << "Accelerometer" << range;
|
||||||
|
|
||||||
|
if (m_accelerometerRange == range)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_accelerometerRange = range;
|
||||||
|
configureMovement();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::setGyroscopeEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
qCDebug(dcTexasInstruments()) << "Gyroscope" << (enabled ? "enabled" : "disabled");
|
||||||
|
|
||||||
|
if (m_gyroscopeEnabled == enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_gyroscopeEnabled = enabled;
|
||||||
|
configureMovement();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::setMagnetometerEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
qCDebug(dcTexasInstruments()) << "Magnetometer" << (enabled ? "enabled" : "disabled");
|
||||||
|
|
||||||
|
if (m_magnetometerEnabled == enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_magnetometerEnabled = enabled;
|
||||||
|
configureMovement();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::setMeasurementPeriod(int period)
|
||||||
|
{
|
||||||
|
qCDebug(dcTexasInstruments()) << "Set sensor measurement period to" << period << "ms";
|
||||||
|
|
||||||
|
if (period % 10 != 0) {
|
||||||
|
int adjustedValue = qRound(static_cast<float>(period) / 10.0) * 10;
|
||||||
|
qCWarning(dcTexasInstruments()) << "Measurement period of sensors" << period << "must be a multiple of 10ms. Adjusting it to" << adjustedValue;
|
||||||
|
period = adjustedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_temperaturePeriod = period;
|
||||||
|
if (m_temperatureService && m_temperaturePeriodCharacteristic.isValid())
|
||||||
|
configurePeriod(m_temperatureService, m_temperaturePeriodCharacteristic, m_temperaturePeriod);
|
||||||
|
|
||||||
|
m_humidityPeriod = period;
|
||||||
|
if (m_humidityService && m_humidityPeriodCharacteristic.isValid())
|
||||||
|
configurePeriod(m_humidityService, m_humidityPeriodCharacteristic, m_humidityPeriod);
|
||||||
|
|
||||||
|
m_pressurePeriod = period;
|
||||||
|
if (m_pressureService && m_pressurePeriodCharacteristic.isValid())
|
||||||
|
configurePeriod(m_pressureService, m_pressurePeriodCharacteristic, m_pressurePeriod);
|
||||||
|
|
||||||
|
m_opticalPeriod = period;
|
||||||
|
if (m_opticalService && m_opticalPeriodCharacteristic.isValid())
|
||||||
|
configurePeriod(m_opticalService, m_opticalPeriodCharacteristic, m_opticalPeriod);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::setMeasurementPeriodMovement(int period)
|
||||||
|
{
|
||||||
|
qCDebug(dcTexasInstruments()) << "Set movement sensor measurement period to" << period << "ms";
|
||||||
|
|
||||||
|
if (period % 10 != 0) {
|
||||||
|
int adjustedValue = qRound(static_cast<float>(period) / 10.0) * 10;
|
||||||
|
qCWarning(dcTexasInstruments()) << "Measurement period of movement sensor" << period << "must be a multiple of 10ms. Adjusting it to" << adjustedValue;
|
||||||
|
period = adjustedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_movementPeriod = period;
|
||||||
|
if (m_movementService && m_movementPeriodCharacteristic.isValid())
|
||||||
|
configurePeriod(m_movementService, m_movementPeriodCharacteristic, m_movementPeriod);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::setMovementSensitivity(int percentage)
|
||||||
|
{
|
||||||
|
m_movementSensitivity = static_cast<double>(percentage) / 100.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::setGreenLedPower(bool power)
|
||||||
|
{
|
||||||
|
m_greenLedEnabled = power;
|
||||||
|
qCDebug(dcTexasInstruments()) << "Green LED" << (power ? "enabled" : "disabled");
|
||||||
|
configureIo();
|
||||||
|
m_device->setStateValue(sensorTagGreenLedStateTypeId, m_greenLedEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::setRedLedPower(bool power)
|
||||||
|
{
|
||||||
|
m_redLedEnabled = power;
|
||||||
|
qCDebug(dcTexasInstruments()) << "Red LED" << (power ? "enabled" : "disabled");
|
||||||
|
configureIo();
|
||||||
|
m_device->setStateValue(sensorTagRedLedStateTypeId, m_redLedEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::setBuzzerPower(bool power)
|
||||||
|
{
|
||||||
|
m_buzzerEnabled = power;
|
||||||
|
qCDebug(dcTexasInstruments()) << "Buzzer" << (power ? "enabled" : "disabled");
|
||||||
|
configureIo();
|
||||||
|
m_device->setStateValue(sensorTagBuzzerStateTypeId, m_buzzerEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::buzzerImpulse()
|
||||||
|
{
|
||||||
|
qCDebug(dcTexasInstruments()) << "Buzzer impulse";
|
||||||
|
setBuzzerPower(true);
|
||||||
|
QTimer::singleShot(1000, this, &SensorTag::onBuzzerImpulseTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::configurePeriod(QLowEnergyService *serice, const QLowEnergyCharacteristic &characteristic, int measurementPeriod)
|
||||||
|
{
|
||||||
|
Q_ASSERT(measurementPeriod % 10 == 0);
|
||||||
|
QByteArray payload;
|
||||||
|
QDataStream stream(&payload, QIODevice::WriteOnly);
|
||||||
|
stream << static_cast<quint8>(measurementPeriod / 10);
|
||||||
|
|
||||||
|
qCDebug(dcTexasInstruments()) << "Configure period to" << measurementPeriod << payload.toHex();
|
||||||
|
serice->writeCharacteristic(characteristic, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::configureMovement()
|
||||||
|
{
|
||||||
|
if (!m_movementService || !m_movementConfigurationCharacteristic.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
quint16 configuration = 0;
|
||||||
|
if (m_gyroscopeEnabled) {
|
||||||
|
configuration |= (1 << 0); // enable x-axis
|
||||||
|
configuration |= (1 << 1); // enable y-axis
|
||||||
|
configuration |= (1 << 2); // enable z-axis
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_accelerometerEnabled) {
|
||||||
|
configuration |= (1 << 3); // enable x-axis
|
||||||
|
configuration |= (1 << 4); // enable y-axis
|
||||||
|
configuration |= (1 << 5); // enable z-axis
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_magnetometerEnabled) {
|
||||||
|
configuration |= (1 << 6); // enable all axis
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always enable wake on movement in order to save energy
|
||||||
|
configuration |= (1 << 8); // enable
|
||||||
|
|
||||||
|
// Accelerometer range 2 Bit ( 0 = 2G, 1 = 4G, 2 = 8G, 3 = 16G)
|
||||||
|
switch (m_accelerometerRange) {
|
||||||
|
case SensorAccelerometerRange2G:
|
||||||
|
// Bit 9 = 0
|
||||||
|
// Bit 10 = 0
|
||||||
|
break;
|
||||||
|
case SensorAccelerometerRange4G:
|
||||||
|
configuration |= (1 << 11);
|
||||||
|
// Bit 12 = 0
|
||||||
|
break;
|
||||||
|
case SensorAccelerometerRange8G:
|
||||||
|
// Bit 13 = 0
|
||||||
|
configuration |= (1 << 14);
|
||||||
|
break;
|
||||||
|
case SensorAccelerometerRange16G:
|
||||||
|
configuration |= (1 << 15);
|
||||||
|
configuration |= (1 << 16);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray data;
|
||||||
|
QDataStream stream(&data, QIODevice::WriteOnly);
|
||||||
|
stream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
stream << configuration;
|
||||||
|
|
||||||
|
qCDebug(dcTexasInstruments()) << "Configure movement sensor" << data.toHex();
|
||||||
|
m_movementService->writeCharacteristic(m_movementConfigurationCharacteristic, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::configureSensorMode(const SensorTag::SensorMode &mode)
|
||||||
|
{
|
||||||
|
if (!m_ioService || !m_ioDataCharacteristic.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
qCDebug(dcTexasInstruments()) << "Setting" << mode;
|
||||||
|
QByteArray data;
|
||||||
|
QDataStream stream(&data, QIODevice::WriteOnly);
|
||||||
|
stream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
stream << static_cast<quint8>(mode);
|
||||||
|
|
||||||
|
m_ioService->writeCharacteristic(m_ioConfigurationCharacteristic, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::configureIo()
|
||||||
|
{
|
||||||
|
if (!m_ioService || !m_ioDataCharacteristic.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Write value to IO
|
||||||
|
quint8 configuration = 0;
|
||||||
|
if (m_redLedEnabled)
|
||||||
|
configuration |= (1 << 0); // Red LED
|
||||||
|
|
||||||
|
if (m_greenLedEnabled)
|
||||||
|
configuration |= (1 << 1); // Green LED
|
||||||
|
|
||||||
|
if (m_buzzerEnabled)
|
||||||
|
configuration |= (1 << 2); // Buzzer
|
||||||
|
|
||||||
|
QByteArray payload;
|
||||||
|
QDataStream stream(&payload, QIODevice::WriteOnly);
|
||||||
|
stream << configuration;
|
||||||
|
|
||||||
|
m_ioService->writeCharacteristic(m_ioDataCharacteristic, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::setTemperatureSensorPower(bool power)
|
||||||
|
{
|
||||||
|
if (!m_temperatureService || !m_temperatureConfigurationCharacteristic.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
QByteArray payload = (power ? QByteArray::fromHex("01") : QByteArray::fromHex("00"));
|
||||||
|
m_temperatureService->writeCharacteristic(m_temperatureConfigurationCharacteristic, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::setHumiditySensorPower(bool power)
|
||||||
|
{
|
||||||
|
if (!m_humidityService || !m_humidityConfigurationCharacteristic.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
QByteArray payload = (power ? QByteArray::fromHex("01") : QByteArray::fromHex("00"));
|
||||||
|
m_humidityService->writeCharacteristic(m_humidityConfigurationCharacteristic, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::setPressureSensorPower(bool power)
|
||||||
|
{
|
||||||
|
if (!m_pressureService || !m_pressureConfigurationCharacteristic.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
QByteArray payload = (power ? QByteArray::fromHex("01") : QByteArray::fromHex("00"));
|
||||||
|
m_pressureService->writeCharacteristic(m_pressureConfigurationCharacteristic, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::setOpticalSensorPower(bool power)
|
||||||
|
{
|
||||||
|
if (!m_opticalService || !m_opticalConfigurationCharacteristic.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
QByteArray payload = (power ? QByteArray::fromHex("01") : QByteArray::fromHex("00"));
|
||||||
|
m_opticalService->writeCharacteristic(m_opticalConfigurationCharacteristic, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SensorTag::onConnectedChanged(const bool &connected)
|
||||||
|
{
|
||||||
|
qCDebug(dcTexasInstruments()) << "Sensor" << m_bluetoothDevice->name() << m_bluetoothDevice->address().toString() << (connected ? "connected" : "disconnected");
|
||||||
|
m_device->setStateValue(sensorTagConnectedStateTypeId, connected);
|
||||||
|
|
||||||
|
if (!connected) {
|
||||||
|
// Clean up services
|
||||||
|
m_temperatureService->deleteLater();
|
||||||
|
m_humidityService->deleteLater();
|
||||||
|
m_pressureService->deleteLater();
|
||||||
|
m_opticalService->deleteLater();
|
||||||
|
m_keyService->deleteLater();
|
||||||
|
m_movementService->deleteLater();
|
||||||
|
m_ioService->deleteLater();
|
||||||
|
|
||||||
|
m_temperatureService = nullptr;
|
||||||
|
m_humidityService = nullptr;
|
||||||
|
m_pressureService = nullptr;
|
||||||
|
m_opticalService = nullptr;
|
||||||
|
m_keyService = nullptr;
|
||||||
|
m_movementService = nullptr;
|
||||||
|
m_ioService = nullptr;
|
||||||
|
|
||||||
|
m_dataProcessor->reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::onServiceDiscoveryFinished()
|
||||||
|
{
|
||||||
|
foreach (const QBluetoothUuid serviceUuid, m_bluetoothDevice->serviceUuids()) {
|
||||||
|
qCDebug(dcTexasInstruments()) << "-->" << serviceUuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_bluetoothDevice->serviceUuids().contains(temperatureServiceUuid)) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Could not find temperature service";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_bluetoothDevice->serviceUuids().contains(humidityServiceUuid)) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Could not find humidity service";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_bluetoothDevice->serviceUuids().contains(pressureServiceUuid)) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Could not find pressure service";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_bluetoothDevice->serviceUuids().contains(opticalServiceUuid)) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Could not find optical service";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_bluetoothDevice->serviceUuids().contains(keyServiceUuid)) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Could not find key service";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_bluetoothDevice->serviceUuids().contains(movementServiceUuid)) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Could not find movement service";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_bluetoothDevice->serviceUuids().contains(ioServiceUuid)) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Could not find IO service";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IR Temperature
|
||||||
|
if (!m_temperatureService) {
|
||||||
|
m_temperatureService = m_bluetoothDevice->controller()->createServiceObject(temperatureServiceUuid, this);
|
||||||
|
if (!m_temperatureService) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Could not create temperature service.";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(m_temperatureService, &QLowEnergyService::stateChanged, this, &SensorTag::onTemperatureServiceStateChanged);
|
||||||
|
connect(m_temperatureService, &QLowEnergyService::characteristicChanged, this, &SensorTag::onTemperatureServiceCharacteristicChanged);
|
||||||
|
|
||||||
|
if (m_temperatureService->state() == QLowEnergyService::DiscoveryRequired) {
|
||||||
|
m_temperatureService->discoverDetails();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Humidity
|
||||||
|
if (!m_humidityService) {
|
||||||
|
m_humidityService = m_bluetoothDevice->controller()->createServiceObject(humidityServiceUuid, this);
|
||||||
|
if (!m_humidityService) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Could not create humidity service.";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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(dcTexasInstruments()) << "Could not create pressure service.";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Optical
|
||||||
|
if (!m_opticalService) {
|
||||||
|
m_opticalService = m_bluetoothDevice->controller()->createServiceObject(opticalServiceUuid, this);
|
||||||
|
if (!m_opticalService) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Could not create optical service.";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(m_opticalService, &QLowEnergyService::stateChanged, this, &SensorTag::onOpticalServiceStateChanged);
|
||||||
|
connect(m_opticalService, &QLowEnergyService::characteristicChanged, this, &SensorTag::onOpticalServiceCharacteristicChanged);
|
||||||
|
|
||||||
|
if (m_opticalService->state() == QLowEnergyService::DiscoveryRequired) {
|
||||||
|
m_opticalService->discoverDetails();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key
|
||||||
|
if (!m_keyService) {
|
||||||
|
m_keyService = m_bluetoothDevice->controller()->createServiceObject(keyServiceUuid, this);
|
||||||
|
if (!m_keyService) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Could not create key service.";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(m_keyService, &QLowEnergyService::stateChanged, this, &SensorTag::onKeyServiceStateChanged);
|
||||||
|
connect(m_keyService, &QLowEnergyService::characteristicChanged, this, &SensorTag::onKeyServiceCharacteristicChanged);
|
||||||
|
|
||||||
|
if (m_keyService->state() == QLowEnergyService::DiscoveryRequired) {
|
||||||
|
m_keyService->discoverDetails();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Movement
|
||||||
|
if (!m_movementService) {
|
||||||
|
m_movementService = m_bluetoothDevice->controller()->createServiceObject(movementServiceUuid, this);
|
||||||
|
if (!m_movementService) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Could not create movement service.";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(m_movementService, &QLowEnergyService::stateChanged, this, &SensorTag::onMovementServiceStateChanged);
|
||||||
|
connect(m_movementService, &QLowEnergyService::characteristicChanged, this, &SensorTag::onMovementServiceCharacteristicChanged);
|
||||||
|
|
||||||
|
if (m_movementService->state() == QLowEnergyService::DiscoveryRequired) {
|
||||||
|
m_movementService->discoverDetails();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IO
|
||||||
|
if (!m_ioService) {
|
||||||
|
m_ioService = m_bluetoothDevice->controller()->createServiceObject(ioServiceUuid, this);
|
||||||
|
if (!m_ioService) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Could not create IO service.";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(m_ioService, &QLowEnergyService::stateChanged, this, &SensorTag::onIoServiceStateChanged);
|
||||||
|
connect(m_ioService, &QLowEnergyService::characteristicChanged, this, &SensorTag::onIoServiceCharacteristicChanged);
|
||||||
|
|
||||||
|
if (m_ioService->state() == QLowEnergyService::DiscoveryRequired) {
|
||||||
|
m_ioService->discoverDetails();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::onBuzzerImpulseTimeout()
|
||||||
|
{
|
||||||
|
setBuzzerPower(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::onTemperatureServiceStateChanged(const QLowEnergyService::ServiceState &state)
|
||||||
|
{
|
||||||
|
// Only continue if discovered
|
||||||
|
if (state != QLowEnergyService::ServiceDiscovered)
|
||||||
|
return;
|
||||||
|
|
||||||
|
qCDebug(dcTexasInstruments()) << "Temperature sensor service discovered.";
|
||||||
|
|
||||||
|
foreach (const QLowEnergyCharacteristic &characteristic, m_temperatureService->characteristics()) {
|
||||||
|
qCDebug(dcTexasInstruments()) << " -->" << characteristic.name() << characteristic.uuid().toString() << characteristic.value();
|
||||||
|
foreach (const QLowEnergyDescriptor &descriptor, characteristic.descriptors()) {
|
||||||
|
qCDebug(dcTexasInstruments()) << " -->" << descriptor.name() << descriptor.uuid().toString() << descriptor.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data characteristic
|
||||||
|
m_temperatureDataCharacteristic = m_temperatureService->characteristic(temperatureDataCharacteristicUuid);
|
||||||
|
if (!m_temperatureDataCharacteristic.isValid()) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Invalid temperature data characteristic.";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable notifications
|
||||||
|
QLowEnergyDescriptor notificationDescriptor = m_temperatureDataCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
|
||||||
|
m_temperatureService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100"));
|
||||||
|
|
||||||
|
|
||||||
|
// Config characteristic
|
||||||
|
m_temperatureConfigurationCharacteristic = m_temperatureService->characteristic(temperatureConfigurationCharacteristicUuid);
|
||||||
|
if (!m_temperatureConfigurationCharacteristic.isValid()) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Invalid temperature configuration characteristic.";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Period characteristic
|
||||||
|
m_temperaturePeriodCharacteristic = m_temperatureService->characteristic(temperaturePeriodCharacteristicUuid);
|
||||||
|
if (!m_temperaturePeriodCharacteristic.isValid()) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Invalid temperature period characteristic.";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
configurePeriod(m_temperatureService, m_temperaturePeriodCharacteristic, m_temperaturePeriod);
|
||||||
|
|
||||||
|
// Enable/disable measuring
|
||||||
|
setTemperatureSensorPower(m_temperatureEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::onTemperatureServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
|
||||||
|
{
|
||||||
|
if (characteristic == m_temperatureDataCharacteristic) {
|
||||||
|
m_dataProcessor->processTemperatureData(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::onHumidityServiceStateChanged(const QLowEnergyService::ServiceState &state)
|
||||||
|
{
|
||||||
|
// Only continue if discovered
|
||||||
|
if (state != QLowEnergyService::ServiceDiscovered)
|
||||||
|
return;
|
||||||
|
|
||||||
|
qCDebug(dcTexasInstruments()) << "Humidity sensor service discovered.";
|
||||||
|
|
||||||
|
foreach (const QLowEnergyCharacteristic &characteristic, m_humidityService->characteristics()) {
|
||||||
|
qCDebug(dcTexasInstruments()) << " -->" << characteristic.name() << characteristic.uuid().toString() << characteristic.value();
|
||||||
|
foreach (const QLowEnergyDescriptor &descriptor, characteristic.descriptors()) {
|
||||||
|
qCDebug(dcTexasInstruments()) << " -->" << descriptor.name() << descriptor.uuid().toString() << descriptor.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data characteristic
|
||||||
|
m_humidityDataCharacteristic = m_humidityService->characteristic(humidityDataCharacteristicUuid);
|
||||||
|
if (!m_humidityDataCharacteristic.isValid()) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Invalid humidity data characteristic.";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable notifications
|
||||||
|
QLowEnergyDescriptor notificationDescriptor = m_humidityDataCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
|
||||||
|
m_humidityService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100"));
|
||||||
|
|
||||||
|
// Config characteristic
|
||||||
|
m_humidityConfigurationCharacteristic = m_humidityService->characteristic(humidityConfigurationCharacteristicUuid);
|
||||||
|
if (!m_humidityConfigurationCharacteristic.isValid()) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Invalid humidity configuration characteristic.";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Period characteristic
|
||||||
|
m_humidityPeriodCharacteristic = m_humidityService->characteristic(humidityPeriodCharacteristicUuid);
|
||||||
|
if (!m_humidityPeriodCharacteristic.isValid()) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Invalid humidity period characteristic.";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
configurePeriod(m_humidityService, m_humidityPeriodCharacteristic, m_humidityPeriod);
|
||||||
|
|
||||||
|
// Enable measuring
|
||||||
|
m_humidityService->writeCharacteristic(m_humidityConfigurationCharacteristic, QByteArray::fromHex("01"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::onHumidityServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
|
||||||
|
{
|
||||||
|
if (characteristic == m_humidityDataCharacteristic) {
|
||||||
|
m_dataProcessor->processHumidityData(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::onPressureServiceStateChanged(const QLowEnergyService::ServiceState &state)
|
||||||
|
{
|
||||||
|
// Only continue if discovered
|
||||||
|
if (state != QLowEnergyService::ServiceDiscovered)
|
||||||
|
return;
|
||||||
|
|
||||||
|
qCDebug(dcTexasInstruments()) << "Pressure sensor service discovered.";
|
||||||
|
|
||||||
|
foreach (const QLowEnergyCharacteristic &characteristic, m_pressureService->characteristics()) {
|
||||||
|
qCDebug(dcTexasInstruments()) << " -->" << characteristic.name() << characteristic.uuid().toString() << characteristic.value();
|
||||||
|
foreach (const QLowEnergyDescriptor &descriptor, characteristic.descriptors()) {
|
||||||
|
qCDebug(dcTexasInstruments()) << " -->" << descriptor.name() << descriptor.uuid().toString() << descriptor.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data characteristic
|
||||||
|
m_pressureDataCharacteristic = m_pressureService->characteristic(pressureDataCharacteristicUuid);
|
||||||
|
if (!m_pressureDataCharacteristic.isValid()) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Invalid pressure data characteristic.";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable notifications
|
||||||
|
QLowEnergyDescriptor notificationDescriptor = m_pressureDataCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
|
||||||
|
m_pressureService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100"));
|
||||||
|
|
||||||
|
// Config characteristic
|
||||||
|
m_pressureConfigurationCharacteristic = m_pressureService->characteristic(pressureConfigurationCharacteristicUuid);
|
||||||
|
if (!m_pressureConfigurationCharacteristic.isValid()) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Invalid pressure configuration characteristic.";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Period characteristic
|
||||||
|
m_pressurePeriodCharacteristic = m_pressureService->characteristic(pressurePeriodCharacteristicUuid);
|
||||||
|
if (!m_pressurePeriodCharacteristic.isValid()) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Invalid pressure period characteristic.";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
configurePeriod(m_pressureService, m_pressurePeriodCharacteristic, m_pressurePeriod);
|
||||||
|
|
||||||
|
// Enable measuring
|
||||||
|
m_pressureService->writeCharacteristic(m_pressureConfigurationCharacteristic, QByteArray::fromHex("01"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::onPressureServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
|
||||||
|
{
|
||||||
|
if (characteristic == m_pressureDataCharacteristic) {
|
||||||
|
m_dataProcessor->processPressureData(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::onOpticalServiceStateChanged(const QLowEnergyService::ServiceState &state)
|
||||||
|
{
|
||||||
|
// Only continue if discovered
|
||||||
|
if (state != QLowEnergyService::ServiceDiscovered)
|
||||||
|
return;
|
||||||
|
|
||||||
|
qCDebug(dcTexasInstruments()) << "Optical sensor service discovered.";
|
||||||
|
|
||||||
|
foreach (const QLowEnergyCharacteristic &characteristic, m_pressureService->characteristics()) {
|
||||||
|
qCDebug(dcTexasInstruments()) << " -->" << characteristic.name() << characteristic.uuid().toString() << characteristic.value();
|
||||||
|
foreach (const QLowEnergyDescriptor &descriptor, characteristic.descriptors()) {
|
||||||
|
qCDebug(dcTexasInstruments()) << " -->" << descriptor.name() << descriptor.uuid().toString() << descriptor.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data characteristic
|
||||||
|
m_opticalDataCharacteristic = m_opticalService->characteristic(opticalDataCharacteristicUuid);
|
||||||
|
if (!m_opticalDataCharacteristic.isValid()) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Invalid optical data characteristic.";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable notifications
|
||||||
|
QLowEnergyDescriptor notificationDescriptor = m_opticalDataCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
|
||||||
|
m_opticalService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100"));
|
||||||
|
|
||||||
|
// Config characteristic
|
||||||
|
m_opticalConfigurationCharacteristic = m_opticalService->characteristic(opticalConfigurationCharacteristicUuid);
|
||||||
|
if (!m_opticalConfigurationCharacteristic.isValid()) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Invalid optical configuration characteristic.";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Period characteristic
|
||||||
|
m_opticalPeriodCharacteristic = m_opticalService->characteristic(opticalPeriodCharacteristicUuid);
|
||||||
|
if (!m_opticalPeriodCharacteristic.isValid()) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Invalid optical period characteristic.";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set measurement period
|
||||||
|
configurePeriod(m_opticalService, m_opticalPeriodCharacteristic, m_opticalPeriod);
|
||||||
|
|
||||||
|
// Enable measuring
|
||||||
|
m_opticalService->writeCharacteristic(m_opticalConfigurationCharacteristic, QByteArray::fromHex("01"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::onOpticalServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
|
||||||
|
{
|
||||||
|
if (characteristic == m_opticalDataCharacteristic) {
|
||||||
|
m_dataProcessor->processOpticalData(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::onKeyServiceStateChanged(const QLowEnergyService::ServiceState &state)
|
||||||
|
{
|
||||||
|
// Only continue if discovered
|
||||||
|
if (state != QLowEnergyService::ServiceDiscovered)
|
||||||
|
return;
|
||||||
|
|
||||||
|
qCDebug(dcTexasInstruments()) << "Key service discovered.";
|
||||||
|
foreach (const QLowEnergyCharacteristic &characteristic, m_keyService->characteristics()) {
|
||||||
|
qCDebug(dcTexasInstruments()) << " -->" << characteristic.name() << characteristic.uuid().toString() << characteristic.value();
|
||||||
|
foreach (const QLowEnergyDescriptor &descriptor, characteristic.descriptors()) {
|
||||||
|
qCDebug(dcTexasInstruments()) << " -->" << descriptor.name() << descriptor.uuid().toString() << descriptor.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data characteristic
|
||||||
|
m_keyDataCharacteristic = m_keyService->characteristic(keyDataCharacteristicUuid);
|
||||||
|
if (!m_keyDataCharacteristic.isValid()) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Invalid button data characteristic.";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable notifications
|
||||||
|
QLowEnergyDescriptor notificationDescriptor = m_keyDataCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
|
||||||
|
m_keyService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::onKeyServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
|
||||||
|
{
|
||||||
|
if (characteristic == m_keyDataCharacteristic) {
|
||||||
|
m_dataProcessor->processKeyData(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::onMovementServiceStateChanged(const QLowEnergyService::ServiceState &state)
|
||||||
|
{
|
||||||
|
// Only continue if discovered
|
||||||
|
if (state != QLowEnergyService::ServiceDiscovered)
|
||||||
|
return;
|
||||||
|
|
||||||
|
qCDebug(dcTexasInstruments()) << "Movement sensor service discovered.";
|
||||||
|
|
||||||
|
foreach (const QLowEnergyCharacteristic &characteristic, m_pressureService->characteristics()) {
|
||||||
|
qCDebug(dcTexasInstruments()) << " -->" << characteristic.name() << characteristic.uuid().toString() << characteristic.value();
|
||||||
|
foreach (const QLowEnergyDescriptor &descriptor, characteristic.descriptors()) {
|
||||||
|
qCDebug(dcTexasInstruments()) << " -->" << descriptor.name() << descriptor.uuid().toString() << descriptor.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data characteristic
|
||||||
|
m_movementDataCharacteristic = m_movementService->characteristic(movementDataCharacteristicUuid);
|
||||||
|
if (!m_movementDataCharacteristic.isValid()) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Invalid movement data characteristic.";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable notifications
|
||||||
|
QLowEnergyDescriptor notificationDescriptor = m_movementDataCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
|
||||||
|
m_movementService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100"));
|
||||||
|
|
||||||
|
// Config characteristic
|
||||||
|
m_movementConfigurationCharacteristic = m_movementService->characteristic(movementConfigurationCharacteristicUuid);
|
||||||
|
if (!m_movementConfigurationCharacteristic.isValid()) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Invalid movement configuration characteristic.";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Period characteristic
|
||||||
|
m_movementPeriodCharacteristic = m_movementService->characteristic(movementPeriodCharacteristicUuid);
|
||||||
|
if (!m_movementPeriodCharacteristic.isValid()) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Invalid movement period characteristic.";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set measurement period
|
||||||
|
configurePeriod(m_movementService, m_movementPeriodCharacteristic, m_movementPeriod);
|
||||||
|
configureMovement();
|
||||||
|
|
||||||
|
// Enable measuring
|
||||||
|
m_movementService->writeCharacteristic(m_movementConfigurationCharacteristic, QByteArray::fromHex("01"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::onMovementServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
|
||||||
|
{
|
||||||
|
if (characteristic == m_movementDataCharacteristic) {
|
||||||
|
m_dataProcessor->processMovementData(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::onIoServiceStateChanged(const QLowEnergyService::ServiceState &state)
|
||||||
|
{
|
||||||
|
// Only continue if discovered
|
||||||
|
if (state != QLowEnergyService::ServiceDiscovered)
|
||||||
|
return;
|
||||||
|
|
||||||
|
qCDebug(dcTexasInstruments()) << "IO service discovered.";
|
||||||
|
|
||||||
|
foreach (const QLowEnergyCharacteristic &characteristic, m_pressureService->characteristics()) {
|
||||||
|
qCDebug(dcTexasInstruments()) << " -->" << characteristic.name() << characteristic.uuid().toString() << characteristic.value();
|
||||||
|
foreach (const QLowEnergyDescriptor &descriptor, characteristic.descriptors()) {
|
||||||
|
qCDebug(dcTexasInstruments()) << " -->" << descriptor.name() << descriptor.uuid().toString() << descriptor.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data characteristic
|
||||||
|
m_ioDataCharacteristic = m_ioService->characteristic(ioDataCharacteristicUuid);
|
||||||
|
if (!m_ioDataCharacteristic.isValid()) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Invalid IO data characteristic.";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable notifications
|
||||||
|
QLowEnergyDescriptor notificationDescriptor = m_ioDataCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
|
||||||
|
m_ioService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100"));
|
||||||
|
|
||||||
|
// Config characteristic
|
||||||
|
m_ioConfigurationCharacteristic = m_ioService->characteristic(ioConfigurationCharacteristicUuid);
|
||||||
|
if (!m_ioConfigurationCharacteristic.isValid()) {
|
||||||
|
qCWarning(dcTexasInstruments()) << "Invalid IO configuration characteristic.";
|
||||||
|
m_bluetoothDevice->disconnectDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
configureIo();
|
||||||
|
configureSensorMode(SensorModeRemote);
|
||||||
|
configureIo();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorTag::onIoServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
|
||||||
|
{
|
||||||
|
qCDebug(dcTexasInstruments()) << characteristic.uuid().toString() << value.toHex();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,228 @@
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2015-2018 Simon Stuerz <simon.stuerz@guh.io> *
|
||||||
|
* *
|
||||||
|
* 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
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include "plugin/device.h"
|
||||||
|
#include "extern-plugininfo.h"
|
||||||
|
#include "sensordataprocessor.h"
|
||||||
|
|
||||||
|
#include "hardware/bluetoothlowenergy/bluetoothlowenergydevice.h"
|
||||||
|
|
||||||
|
// http://processors.wiki.ti.com/index.php/CC2650_SensorTag_User's_Guide
|
||||||
|
|
||||||
|
static QBluetoothUuid temperatureServiceUuid = QBluetoothUuid(QUuid("f000aa00-0451-4000-b000-000000000000"));
|
||||||
|
static QBluetoothUuid temperatureDataCharacteristicUuid = QBluetoothUuid(QUuid("f000aa01-0451-4000-b000-000000000000"));
|
||||||
|
static QBluetoothUuid temperatureConfigurationCharacteristicUuid = QBluetoothUuid(QUuid("f000aa02-0451-4000-b000-000000000000"));
|
||||||
|
static QBluetoothUuid temperaturePeriodCharacteristicUuid = QBluetoothUuid(QUuid("f000aa03-0451-4000-b000-000000000000"));
|
||||||
|
|
||||||
|
static QBluetoothUuid humidityServiceUuid = QBluetoothUuid(QUuid("f000aa20-0451-4000-b000-000000000000"));
|
||||||
|
static QBluetoothUuid humidityDataCharacteristicUuid = QBluetoothUuid(QUuid("f000aa21-0451-4000-b000-000000000000"));
|
||||||
|
static QBluetoothUuid humidityConfigurationCharacteristicUuid = QBluetoothUuid(QUuid("f000aa22-0451-4000-b000-000000000000"));
|
||||||
|
static QBluetoothUuid humidityPeriodCharacteristicUuid = QBluetoothUuid(QUuid("f000aa23-0451-4000-b000-000000000000"));
|
||||||
|
|
||||||
|
static QBluetoothUuid pressureServiceUuid = QBluetoothUuid(QUuid("f000aa40-0451-4000-b000-000000000000"));
|
||||||
|
static QBluetoothUuid pressureDataCharacteristicUuid = QBluetoothUuid(QUuid("f000aa41-0451-4000-b000-000000000000"));
|
||||||
|
static QBluetoothUuid pressureConfigurationCharacteristicUuid = QBluetoothUuid(QUuid("f000aa42-0451-4000-b000-000000000000"));
|
||||||
|
static QBluetoothUuid pressurePeriodCharacteristicUuid = QBluetoothUuid(QUuid("f000aa44-0451-4000-b000-000000000000"));
|
||||||
|
|
||||||
|
static QBluetoothUuid opticalServiceUuid = QBluetoothUuid(QUuid("f000aa70-0451-4000-b000-000000000000"));
|
||||||
|
static QBluetoothUuid opticalDataCharacteristicUuid = QBluetoothUuid(QUuid("f000aa71-0451-4000-b000-000000000000"));
|
||||||
|
static QBluetoothUuid opticalConfigurationCharacteristicUuid = QBluetoothUuid(QUuid("f000aa72-0451-4000-b000-000000000000"));
|
||||||
|
static QBluetoothUuid opticalPeriodCharacteristicUuid = QBluetoothUuid(QUuid("f000aa73-0451-4000-b000-000000000000"));
|
||||||
|
|
||||||
|
static QBluetoothUuid keyServiceUuid = QBluetoothUuid(QUuid("0000ffe0-0000-1000-8000-00805f9b34fb"));
|
||||||
|
static QBluetoothUuid keyDataCharacteristicUuid = QBluetoothUuid(QUuid("0000ffe1-0000-1000-8000-00805f9b34fb"));
|
||||||
|
|
||||||
|
static QBluetoothUuid ioServiceUuid = QBluetoothUuid(QUuid("f000aa64-0451-4000-b000-000000000000"));
|
||||||
|
static QBluetoothUuid ioDataCharacteristicUuid = QBluetoothUuid(QUuid("f000aa65-0451-4000-b000-000000000000"));
|
||||||
|
static QBluetoothUuid ioConfigurationCharacteristicUuid = QBluetoothUuid(QUuid("f000aa66-0451-4000-b000-000000000000"));
|
||||||
|
|
||||||
|
static QBluetoothUuid movementServiceUuid = QBluetoothUuid(QUuid("f000aa80-0451-4000-b000-000000000000"));
|
||||||
|
static QBluetoothUuid movementDataCharacteristicUuid = QBluetoothUuid(QUuid("f000aa81-0451-4000-b000-000000000000"));
|
||||||
|
static QBluetoothUuid movementConfigurationCharacteristicUuid = QBluetoothUuid(QUuid("f000aa82-0451-4000-b000-000000000000"));
|
||||||
|
static QBluetoothUuid movementPeriodCharacteristicUuid = QBluetoothUuid(QUuid("f000aa83-0451-4000-b000-000000000000"));
|
||||||
|
|
||||||
|
|
||||||
|
class SensorTag : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
enum SensorAccelerometerRange {
|
||||||
|
SensorAccelerometerRange2G = 2,
|
||||||
|
SensorAccelerometerRange4G = 4,
|
||||||
|
SensorAccelerometerRange8G = 8,
|
||||||
|
SensorAccelerometerRange16G = 16
|
||||||
|
};
|
||||||
|
Q_ENUM(SensorAccelerometerRange)
|
||||||
|
|
||||||
|
enum SensorMode {
|
||||||
|
SensorModeLocal = 0,
|
||||||
|
SensorModeRemote = 1,
|
||||||
|
SensorModeTest = 2
|
||||||
|
};
|
||||||
|
Q_ENUM(SensorMode)
|
||||||
|
|
||||||
|
explicit SensorTag(Device *device, BluetoothLowEnergyDevice *bluetoothDevice, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
Device *device();
|
||||||
|
BluetoothLowEnergyDevice *bluetoothDevice();
|
||||||
|
|
||||||
|
// Configurations
|
||||||
|
void setTemperatureSensorEnabled(bool enabled);
|
||||||
|
void setHumiditySensorEnabled(bool enabled);
|
||||||
|
void setPressureSensorEnabled(bool enabled);
|
||||||
|
void setOpticalSensorEnabled(bool enabled);
|
||||||
|
void setAccelerometerEnabled(bool enabled);
|
||||||
|
void setGyroscopeEnabled(bool enabled);
|
||||||
|
void setMagnetometerEnabled(bool enabled);
|
||||||
|
|
||||||
|
void setAccelerometerRange(const SensorAccelerometerRange &range);
|
||||||
|
void setMeasurementPeriod(int period);
|
||||||
|
void setMeasurementPeriodMovement(int period);
|
||||||
|
void setMovementSensitivity(int percentage);
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
void setGreenLedPower(bool power);
|
||||||
|
void setRedLedPower(bool power);
|
||||||
|
void setBuzzerPower(bool power);
|
||||||
|
void buzzerImpulse();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Device *m_device;
|
||||||
|
BluetoothLowEnergyDevice *m_bluetoothDevice;
|
||||||
|
|
||||||
|
// Services
|
||||||
|
QLowEnergyService *m_temperatureService = nullptr;
|
||||||
|
QLowEnergyService *m_humidityService = nullptr;
|
||||||
|
QLowEnergyService *m_pressureService = nullptr;
|
||||||
|
QLowEnergyService *m_opticalService = nullptr;
|
||||||
|
QLowEnergyService *m_keyService = nullptr;
|
||||||
|
QLowEnergyService *m_movementService = nullptr;
|
||||||
|
QLowEnergyService *m_ioService = nullptr;
|
||||||
|
|
||||||
|
// Characteristics
|
||||||
|
QLowEnergyCharacteristic m_temperatureDataCharacteristic;
|
||||||
|
QLowEnergyCharacteristic m_temperatureConfigurationCharacteristic;
|
||||||
|
QLowEnergyCharacteristic m_temperaturePeriodCharacteristic;
|
||||||
|
|
||||||
|
QLowEnergyCharacteristic m_humidityDataCharacteristic;
|
||||||
|
QLowEnergyCharacteristic m_humidityConfigurationCharacteristic;
|
||||||
|
QLowEnergyCharacteristic m_humidityPeriodCharacteristic;
|
||||||
|
|
||||||
|
QLowEnergyCharacteristic m_pressureDataCharacteristic;
|
||||||
|
QLowEnergyCharacteristic m_pressureConfigurationCharacteristic;
|
||||||
|
QLowEnergyCharacteristic m_pressurePeriodCharacteristic;
|
||||||
|
|
||||||
|
QLowEnergyCharacteristic m_opticalDataCharacteristic;
|
||||||
|
QLowEnergyCharacteristic m_opticalConfigurationCharacteristic;
|
||||||
|
QLowEnergyCharacteristic m_opticalPeriodCharacteristic;
|
||||||
|
|
||||||
|
QLowEnergyCharacteristic m_keyDataCharacteristic;
|
||||||
|
|
||||||
|
QLowEnergyCharacteristic m_movementDataCharacteristic;
|
||||||
|
QLowEnergyCharacteristic m_movementConfigurationCharacteristic;
|
||||||
|
QLowEnergyCharacteristic m_movementPeriodCharacteristic;
|
||||||
|
|
||||||
|
QLowEnergyCharacteristic m_ioDataCharacteristic;
|
||||||
|
QLowEnergyCharacteristic m_ioConfigurationCharacteristic;
|
||||||
|
|
||||||
|
// Measure periods
|
||||||
|
int m_temperaturePeriod = 2500;
|
||||||
|
int m_humidityPeriod = 2500;
|
||||||
|
int m_pressurePeriod = 2500;
|
||||||
|
int m_opticalPeriod = 2500;
|
||||||
|
int m_movementPeriod = 500;
|
||||||
|
double m_movementSensitivity = 0.5;
|
||||||
|
SensorAccelerometerRange m_accelerometerRange = SensorAccelerometerRange16G;
|
||||||
|
|
||||||
|
// States
|
||||||
|
bool m_greenLedEnabled = false;
|
||||||
|
bool m_redLedEnabled = false;
|
||||||
|
bool m_buzzerEnabled = false;
|
||||||
|
|
||||||
|
// Plugin configs
|
||||||
|
bool m_temperatureEnabled = true;
|
||||||
|
bool m_humidityEnabled = true;
|
||||||
|
bool m_pressureEnabled = true;
|
||||||
|
bool m_opticalEnabled = true;
|
||||||
|
bool m_accelerometerEnabled = true;
|
||||||
|
bool m_gyroscopeEnabled = false;
|
||||||
|
bool m_magnetometerEnabled = false;
|
||||||
|
|
||||||
|
SensorDataProcessor *m_dataProcessor = nullptr;
|
||||||
|
|
||||||
|
// Configuration methods
|
||||||
|
void configurePeriod(QLowEnergyService *serice, const QLowEnergyCharacteristic &characteristic, int measurementPeriod);
|
||||||
|
void configureMovement();
|
||||||
|
void configureSensorMode(const SensorMode &mode);
|
||||||
|
void configureIo();
|
||||||
|
|
||||||
|
void setTemperatureSensorPower(bool power);
|
||||||
|
void setHumiditySensorPower(bool power);
|
||||||
|
void setPressureSensorPower(bool power);
|
||||||
|
void setOpticalSensorPower(bool power);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void leftButtonPressedChanged(bool pressed);
|
||||||
|
void rightButtonPressedChanged(bool pressed);
|
||||||
|
void magnetDetectedChanged(bool detected);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onConnectedChanged(const bool &connected);
|
||||||
|
void onServiceDiscoveryFinished();
|
||||||
|
|
||||||
|
void onBuzzerImpulseTimeout();
|
||||||
|
|
||||||
|
// Temperature sensor service
|
||||||
|
void onTemperatureServiceStateChanged(const QLowEnergyService::ServiceState &state);
|
||||||
|
void onTemperatureServiceCharacteristicChanged(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);
|
||||||
|
|
||||||
|
// Optical sensor service
|
||||||
|
void onOpticalServiceStateChanged(const QLowEnergyService::ServiceState &state);
|
||||||
|
void onOpticalServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value);
|
||||||
|
|
||||||
|
// Button service
|
||||||
|
void onKeyServiceStateChanged(const QLowEnergyService::ServiceState &state);
|
||||||
|
void onKeyServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value);
|
||||||
|
|
||||||
|
// Movement service
|
||||||
|
void onMovementServiceStateChanged(const QLowEnergyService::ServiceState &state);
|
||||||
|
void onMovementServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value);
|
||||||
|
|
||||||
|
// IO service
|
||||||
|
void onIoServiceStateChanged(const QLowEnergyService::ServiceState &state);
|
||||||
|
void onIoServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SENSORTAG_H
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
include(../plugins.pri)
|
||||||
|
|
||||||
|
QT += bluetooth
|
||||||
|
|
||||||
|
TARGET = $$qtLibraryTarget(nymea_deviceplugintexasinstruments)
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
deviceplugintexasinstruments.h \
|
||||||
|
sensortag.h \
|
||||||
|
sensordataprocessor.h \
|
||||||
|
sensorfilter.h
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
deviceplugintexasinstruments.cpp \
|
||||||
|
sensortag.cpp \
|
||||||
|
sensordataprocessor.cpp \
|
||||||
|
sensorfilter.cpp
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE TS>
|
||||||
|
<TS version="2.1">
|
||||||
|
</TS>
|
||||||
Loading…
Reference in New Issue