Temporary commit for nymea migration

This commit is contained in:
Simon Stürz 2018-03-13 14:14:39 +01:00
parent c6af7eb04e
commit 431d56d366
10 changed files with 758 additions and 232 deletions

View File

@ -97,6 +97,10 @@ DeviceManager::DeviceSetupStatus DevicePluginMultiSensor::setupDevice(Device *de
SensorTag *sensor = new SensorTag(device, bluetoothDevice, this);
// Preconfigure with plugin configurations
sensor->setTemperatureSensorEnabled(configValue(MultiSensorTemperatureEnabledParamTypeId).toBool());
sensor->setHumiditySensorEnabled(configValue(MultiSensorHumidityEnabledParamTypeId).toBool());
sensor->setPressureSensorEnabled(configValue(MultiSensorPressureEnabledParamTypeId).toBool());
sensor->setOpticalSensorEnabled(configValue(MultiSensorOpticalEnabledParamTypeId).toBool());
sensor->setAccelerometerEnabled(configValue(MultiSensorAccelerometerEnabledParamTypeId).toBool());
sensor->setGyroscopeEnabled(configValue(MultiSensorGyroscopeEnabledParamTypeId).toBool());
sensor->setMagnetometerEnabled(configValue(MultiSensorMagnetometerEnabledParamTypeId).toBool());
@ -200,7 +204,15 @@ void DevicePluginMultiSensor::onPluginConfigurationChanged(const ParamTypeId &pa
qCDebug(dcMultiSensor()) << "Plugin configuration changed" << paramTypeId.toString() << value;
foreach (SensorTag *sensor, m_sensors.values()) {
if (paramTypeId == MultiSensorAccelerometerEnabledParamTypeId) {
if (paramTypeId == MultiSensorTemperatureEnabledParamTypeId) {
sensor->setTemperatureSensorEnabled(value.toBool());
} else if (paramTypeId == MultiSensorHumidityEnabledParamTypeId) {
sensor->setHumiditySensorEnabled(value.toBool());
} else if (paramTypeId == MultiSensorPressureEnabledParamTypeId) {
sensor->setPressureSensorEnabled(value.toBool());
} else if (paramTypeId == MultiSensorOpticalEnabledParamTypeId) {
sensor->setOpticalSensorEnabled(value.toBool());
} else if (paramTypeId == MultiSensorAccelerometerEnabledParamTypeId) {
sensor->setAccelerometerEnabled(value.toBool());
} else if (paramTypeId == MultiSensorGyroscopeEnabledParamTypeId) {
sensor->setGyroscopeEnabled(value.toBool());

View File

@ -3,6 +3,34 @@
"name": "MultiSensor",
"id": "23bf0d8d-df7d-4bee-80ee-f015c5a7f52e",
"paramTypes": [
{
"id": "6f0e40a2-0f97-4c1e-8229-757e3c18b345",
"name": "temperatureEnabled",
"displayName": "Temperature sensor enabled",
"type": "bool",
"defaultValue": true
},
{
"id": "29881172-626a-42d5-83b8-3e2e5ca533be",
"name": "humidityEnabled",
"displayName": "Humidity sensor enabled",
"type": "bool",
"defaultValue": true
},
{
"id": "50e5e282-9707-4b31-bb3f-a6ca30a7e1ff",
"name": "pressureEnabled",
"displayName": "Pressure sensor enabled",
"type": "bool",
"defaultValue": true
},
{
"id": "1460a6d6-9fb4-4385-b27b-ee4b7594e454",
"name": "opticalEnabled",
"displayName": "Optical sensor enabled",
"type": "bool",
"defaultValue": true
},
{
"id": "5786c91a-d94d-461a-8d22-f978dd1438ab",
"name": "accelerometerEnabled",

View File

@ -0,0 +1,15 @@
# Autocreated plot script for system disk usage
set term png small size 2000,1000
set output "multisensor.png"
set title "Multisensor filter"
set xlabel "Time"
set ylabel "Value"
set xdata time
set timefmt "%s"
set xtics format "%H:%M:%S"
set yrange [0:*]
set grid
plot "/tmp/multisensor.log" using 1:2 with lines title "Original value", \
"/tmp/multisensor.log" using 1:3 with lines title "Filtered value"

View File

@ -5,9 +5,13 @@ TARGET = $$qtLibraryTarget(nymea_devicepluginmultisensor)
SOURCES += \
devicepluginmultisensor.cpp \
#sensortag-old.cpp \
sensortag.cpp
sensortag.cpp \
sensorfilter.cpp \
sensordataprocessor.cpp
HEADERS += \
devicepluginmultisensor.h \
#sensortag-old.h \
sensortag.h
sensortag.h \
sensorfilter.h \
sensordataprocessor.h

View File

@ -0,0 +1,307 @@
#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(dcMultiSensor()) << "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 ;
double scaleFactor = 0.03125;
double objectTemperature = static_cast<double>(rawObjectTemperature) / 4 * scaleFactor;
double ambientTemperature = static_cast<double>(rawAmbientTemperature) / 4 * scaleFactor;
//qCDebug(dcMultiSensor()) << "Temperature value" << data.toHex();
//qCDebug(dcMultiSensor()) << "Object temperature" << roundValue(objectTemperature) << "°C";
//qCDebug(dcMultiSensor()) << "Ambient temperature" << roundValue(ambientTemperature) << "°C";
double objectTemperatureFiltered = m_objectTemperatureFilter->filterValue(objectTemperature);
double 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 enought 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(dcMultiSensor()) << "Pressure temperature:" << roundValue(rawTemperature / 100.0) << "°C";
//qCDebug(dcMultiSensor()) << "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(dcMultiSensor()) << "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(dcMultiSensor()) << "--> 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
double gyroX = static_cast<double>(gyroXRaw) / (65536 / 500);
double gyroY = static_cast<double>(gyroYRaw) / (65536 / 500);
double gyroZ = static_cast<double>(gyroZRaw) / (65536 / 500);
// Calculate acceleration [G], Range +- m_accelerometerRange
double accX = static_cast<double>(accXRaw) / (32768 / static_cast<int>(m_accelerometerRange));
double accY = static_cast<double>(accYRaw) / (32768 / static_cast<int>(m_accelerometerRange));
double accZ = static_cast<double>(accZRaw) / (32768 / static_cast<int>(m_accelerometerRange));
// Calculate magnetism [uT], Range +- 4900
double magX = static_cast<double>(magXRaw);
double magY = static_cast<double>(magYRaw);
double magZ = static_cast<double>(magZRaw);
//qCDebug(dcMultiSensor()) << "Accelerometer x:" << accX << " y:" << accY << " z:" << accZ;
//qCDebug(dcMultiSensor()) << "Gyroscope x:" << gyroX << " y:" << gyroY << " z:" << gyroZ;
//qCDebug(dcMultiSensor()) << "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(dcMultiSensor()) << "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(dcMultiSensor()) << "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(dcMultiSensor()) << "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;
}

View File

@ -0,0 +1,71 @@
#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

View File

@ -0,0 +1,156 @@
#include "sensorfilter.h"
#include <QDebug>
SensorFilter::SensorFilter(Type filterType, QObject *parent) :
QObject(parent),
m_filterType(filterType)
{
}
double SensorFilter::filterValue(double value)
{
double 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<double> SensorFilter::inputData() const
{
return m_inputData;
}
QVector<double> 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;
}
double SensorFilter::lowPassAlpha() const
{
return m_lowPassAlpha;
}
void SensorFilter::setLowPassAlpha(double 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;
}
double SensorFilter::highPassAlpha() const
{
return m_highPassAlpha;
}
void SensorFilter::setHighPassAlpha(double 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(double value)
{
m_inputData.append(value);
if (m_inputData.size() > m_filterWindowSize) {
m_inputData.removeFirst();
}
}
double SensorFilter::lowPassFilterValue(double value)
{
addInputValue(value);
// Check if we have enought data for filtering
if (m_inputData.size() < 2) {
return value;
}
QVector<double> 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();
}
double SensorFilter::highPassFilterValue(double value)
{
addInputValue(value);
// Check if we have enought data for filtering
if (m_inputData.size() < 2) {
return value;
}
QVector<double> 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();
}
double SensorFilter::averageFilterValue(double value)
{
if (m_inputData.isEmpty()) {
addInputValue(value);
m_averageSum = value;
return value;
}
if (m_inputData.size() >= m_filterWindowSize) {
m_averageSum -= m_inputData.takeFirst();
}
addInputValue(value);
m_averageSum += value;
return m_averageSum / m_inputData.size();
}

View File

@ -0,0 +1,60 @@
#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);
double filterValue(double value);
bool isReady() const;
void reset();
Type filterType() const;
QVector<double> inputData() const;
QVector<double> outputData() const;
// Filter configuration
uint windowSize() const;
void setFilterWindowSize(uint windowSize = 20);
double lowPassAlpha() const;
void setLowPassAlpha(double alpha = 0.2);
double highPassAlpha() const;
void setHighPassAlpha(double alpha = 0.2);
private:
Type m_filterType = TypeLowPass;
int m_filterWindowSize = 20;
double m_lowPassAlpha = 0.2;
double m_highPassAlpha = 0.2;
double m_averageSum = 0;
QVector<double> m_inputData;
QVector<double> m_outputData;
void addInputValue(double value);
// Filter methods
double lowPassFilterValue(double value);
double highPassFilterValue(double value);
double averageFilterValue(double value);
};
#endif // SENSORFILTER_H

View File

@ -31,7 +31,8 @@
SensorTag::SensorTag(Device *device, BluetoothLowEnergyDevice *bluetoothDevice, QObject *parent) :
QObject(parent),
m_device(device),
m_bluetoothDevice(bluetoothDevice)
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);
@ -47,6 +48,50 @@ BluetoothLowEnergyDevice *SensorTag::bluetoothDevice()
return m_bluetoothDevice;
}
void SensorTag::setTemperatureSensorEnabled(bool enabled)
{
qCDebug(dcMultiSensor()) << "Temperature sensor" << (enabled ? "enabled" : "disabled");
if (m_temperatureEnabled == enabled)
return;
m_temperatureEnabled = enabled;
setTemperatureSensorPower(m_temperatureEnabled);
}
void SensorTag::setHumiditySensorEnabled(bool enabled)
{
qCDebug(dcMultiSensor()) << "Humidity sensor" << (enabled ? "enabled" : "disabled");
if (m_humidityEnabled == enabled)
return;
m_humidityEnabled = enabled;
setHumiditySensorPower(m_humidityEnabled);
}
void SensorTag::setPressureSensorEnabled(bool enabled)
{
qCDebug(dcMultiSensor()) << "Pressure sensor" << (enabled ? "enabled" : "disabled");
if (m_pressureEnabled == enabled)
return;
m_pressureEnabled = enabled;
setPressureSensorPower(m_pressureEnabled);
}
void SensorTag::setOpticalSensorEnabled(bool enabled)
{
qCDebug(dcMultiSensor()) << "Optical sensor" << (enabled ? "enabled" : "disabled");
if (m_opticalEnabled == enabled)
return;
m_opticalEnabled = enabled;
setOpticalSensorPower(m_opticalEnabled);
}
void SensorTag::setAccelerometerEnabled(bool enabled)
{
qCDebug(dcMultiSensor()) << "Accelerometer" << (enabled ? "enabled" : "disabled");
@ -275,203 +320,42 @@ void SensorTag::configureIo()
m_ioService->writeCharacteristic(m_ioDataCharacteristic, payload);
}
void SensorTag::processTemperatureData(const QByteArray &data)
void SensorTag::setTemperatureSensorPower(bool power)
{
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(dcMultiSensor()) << "Temperature value" << data.toHex();
//qCDebug(dcMultiSensor()) << "Object temperature" << roundValue(objectTemperature) << "°C";
//qCDebug(dcMultiSensor()) << "Ambient temperature" << roundValue(ambientTemperature) << "°C";
m_device->setStateValue(sensortagObjectTemperatureStateTypeId, roundValue(objectTemperature));
m_device->setStateValue(sensortagTemperatureStateTypeId, roundValue(ambientTemperature));
}
void SensorTag::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 SensorTag::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;
//qCDebug(dcMultiSensor()) << "Humidity" << humidity << "%" << humidityTemperature << "°C";
m_device->setStateValue(sensortagHumidityStateTypeId, roundValue(humidity));
}
void SensorTag::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(dcMultiSensor()) << "Pressure temperature:" << roundValue(rawTemperature / 100.0) << "°C";
//qCDebug(dcMultiSensor()) << "Pressure:" << roundValue(rawPressure / 100.0) << "mBar";
m_device->setStateValue(sensortagPressureStateTypeId, roundValue(rawPressure / 100.0));
}
void SensorTag::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(dcMultiSensor()) << "Lux:" << lux;
device()->setStateValue(sensortagLightIntensityStateTypeId, roundValue(lux));
}
void SensorTag::processMovementData(const QByteArray &data)
{
//qCDebug(dcMultiSensor()) << "--> 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
double gyroX = static_cast<double>(gyroXRaw) / (65536 / 500);
double gyroY = static_cast<double>(gyroYRaw) / (65536 / 500);
double gyroZ = static_cast<double>(gyroZRaw) / (65536 / 500);
// Calculate acceleration [G], Range +- m_accelerometerRange
double accX = static_cast<double>(accXRaw) / (32768 / static_cast<int>(m_accelerometerRange));
double accY = static_cast<double>(accYRaw) / (32768 / static_cast<int>(m_accelerometerRange));
double accZ = static_cast<double>(accZRaw) / (32768 / static_cast<int>(m_accelerometerRange));
// Calculate magnetism [uT], Range +- 4900
double magX = static_cast<double>(magXRaw);
double magY = static_cast<double>(magYRaw);
double magZ = static_cast<double>(magZRaw);
//qCDebug(dcMultiSensor()) << "Accelerometer x:" << accX << " y:" << accY << " z:" << accZ;
//qCDebug(dcMultiSensor()) << "Gyroscope x:" << gyroX << " y:" << gyroY << " z:" << gyroZ;
//qCDebug(dcMultiSensor()) << "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)
// Initialize the accelerometer value if no data known yet
if (m_lastAccelerometerVectorLenght == -99999) {
m_lastAccelerometerVectorLenght = accelerometerVector.length();
return;
}
double delta = qAbs(qAbs(m_lastAccelerometerVectorLenght) - qAbs(accelerometerVector.length()));
bool motionDetected = (delta >= m_movementSensitivity);
//qCDebug(dcMultiSensor()) << accelerometerVector.length() << " | " << delta << m_movementSensitivity << (motionDetected ? "motion" : "-");
m_device->setStateValue(sensortagMovingStateTypeId, motionDetected);
m_lastAccelerometerVectorLenght = accelerometerVector.length();
}
void SensorTag::setLeftButtonPressed(bool pressed)
{
if (m_leftButtonPressed == pressed)
if (!m_temperatureService || !m_temperatureConfigurationCharacteristic.isValid())
return;
qCDebug(dcMultiSensor()) << "Left button" << (pressed ? "pressed" : "released");
m_leftButtonPressed = pressed;
emit leftButtonPressedChainged(m_leftButtonPressed);
m_device->setStateValue(sensortagLeftButtonPressedStateTypeId, m_leftButtonPressed);
QByteArray payload = (power ? QByteArray::fromHex("01") : QByteArray::fromHex("00"));
m_temperatureService->writeCharacteristic(m_temperatureConfigurationCharacteristic, payload);
}
void SensorTag::setRightButtonPressed(bool pressed)
void SensorTag::setHumiditySensorPower(bool power)
{
if (m_rightButtonPressed == pressed)
if (!m_humidityService || !m_humidityConfigurationCharacteristic.isValid())
return;
qCDebug(dcMultiSensor()) << "Right button" << (pressed ? "pressed" : "released");
m_rightButtonPressed = pressed;
emit rightButtonPressedChainged(m_rightButtonPressed);
m_device->setStateValue(sensortagRightButtonPressedStateTypeId, m_rightButtonPressed);
QByteArray payload = (power ? QByteArray::fromHex("01") : QByteArray::fromHex("00"));
m_humidityService->writeCharacteristic(m_humidityConfigurationCharacteristic, payload);
}
void SensorTag::setMagnetDetected(bool detected)
void SensorTag::setPressureSensorPower(bool power)
{
if (m_magnetDetected == detected)
if (!m_pressureService || !m_pressureConfigurationCharacteristic.isValid())
return;
qCDebug(dcMultiSensor()) << "Magnet detector" << (detected ? "active" : "inactive");
m_magnetDetected = detected;
emit magnetDetectedChainged(m_magnetDetected);
m_device->setStateValue(sensortagMagnetDetectedStateTypeId, m_magnetDetected);
QByteArray payload = (power ? QByteArray::fromHex("01") : QByteArray::fromHex("00"));
m_pressureService->writeCharacteristic(m_pressureConfigurationCharacteristic, payload);
}
bool SensorTag::testBitUint8(quint8 value, int bitPosition)
void SensorTag::setOpticalSensorPower(bool power)
{
return (((value)>> (bitPosition)) & 1);
if (!m_opticalService || !m_opticalConfigurationCharacteristic.isValid())
return;
QByteArray payload = (power ? QByteArray::fromHex("01") : QByteArray::fromHex("00"));
m_opticalService->writeCharacteristic(m_opticalConfigurationCharacteristic, payload);
}
double SensorTag::roundValue(float value)
{
int tmpValue = static_cast<int>(value * 10);
return static_cast<double>(tmpValue) / 10.0;
}
void SensorTag::onConnectedChanged(const bool &connected)
{
@ -496,7 +380,7 @@ void SensorTag::onConnectedChanged(const bool &connected)
m_movementService = nullptr;
m_ioService = nullptr;
m_lastAccelerometerVectorLenght = -99999;
m_dataProcessor->reset();
}
}
@ -667,6 +551,11 @@ void SensorTag::onServiceDiscoveryFinished()
}
}
void SensorTag::onBuzzerImpulseTimeout()
{
setBuzzerPower(false);
}
void SensorTag::onTemperatureServiceStateChanged(const QLowEnergyService::ServiceState &state)
{
// Only continue if discovered
@ -713,17 +602,14 @@ void SensorTag::onTemperatureServiceStateChanged(const QLowEnergyService::Servic
configurePeriod(m_temperatureService, m_temperaturePeriodCharacteristic, m_temperaturePeriod);
// Enable measuring
m_temperatureService->writeCharacteristic(m_temperatureConfigurationCharacteristic, QByteArray::fromHex("01"));
// Enable/disable measuring
setTemperatureSensorPower(m_temperatureEnabled);
}
void SensorTag::onTemperatureServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
{
if (characteristic == m_temperatureDataCharacteristic) {
processTemperatureData(value);
// FIXME: Disable measuring
// m_temperatureService->writeCharacteristic(m_temperatureConfigCharacteristic, QByteArray::fromHex("00"));
m_dataProcessor->processTemperatureData(value);
}
}
@ -779,9 +665,7 @@ void SensorTag::onHumidityServiceStateChanged(const QLowEnergyService::ServiceSt
void SensorTag::onHumidityServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
{
if (characteristic == m_humidityDataCharacteristic) {
processHumidityData(value);
// FIXME: Disable measuring
// m_humidityService->writeCharacteristic(m_humidityConfigCharacteristic, QByteArray::fromHex("00"));
m_dataProcessor->processHumidityData(value);
}
}
@ -837,9 +721,7 @@ void SensorTag::onPressureServiceStateChanged(const QLowEnergyService::ServiceSt
void SensorTag::onPressureServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
{
if (characteristic == m_pressureDataCharacteristic) {
processPressureData(value);
// FIXME: Disable measuring
// m_pressureService->writeCharacteristic(m_pressureConfigCharacteristic, QByteArray::fromHex("00"));
m_dataProcessor->processPressureData(value);
}
}
@ -894,11 +776,8 @@ void SensorTag::onOpticalServiceStateChanged(const QLowEnergyService::ServiceSta
void SensorTag::onOpticalServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
{
if (characteristic == m_opticalDataCharacteristic) {
processOpticalData(value);
// FIXME: Disable measuring
// m_opticalService->writeCharacteristic(m_pressureopticalCharacteristic, QByteArray::fromHex("00"));
m_dataProcessor->processOpticalData(value);
}
}
void SensorTag::onKeyServiceStateChanged(const QLowEnergyService::ServiceState &state)
@ -930,7 +809,7 @@ void SensorTag::onKeyServiceStateChanged(const QLowEnergyService::ServiceState &
void SensorTag::onKeyServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
{
if (characteristic == m_keyDataCharacteristic) {
processKeyData(value);
m_dataProcessor->processKeyData(value);
}
}
@ -985,7 +864,7 @@ void SensorTag::onMovementServiceStateChanged(const QLowEnergyService::ServiceSt
void SensorTag::onMovementServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
{
if (characteristic == m_movementDataCharacteristic) {
processMovementData(value);
m_dataProcessor->processMovementData(value);
}
}
@ -1031,8 +910,3 @@ void SensorTag::onIoServiceCharacteristicChanged(const QLowEnergyCharacteristic
{
qCDebug(dcMultiSensor()) << characteristic.uuid().toString() << value.toHex();
}
void SensorTag::onBuzzerImpulseTimeout()
{
setBuzzerPower(false);
}

View File

@ -27,6 +27,8 @@
#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
@ -89,10 +91,15 @@ public:
BluetoothLowEnergyDevice *bluetoothDevice();
// Configurations
void setTemperatureSensorEnabled(bool enabled);
void setHumiditySensorEnabled(bool enabled);
void setPressureSensorEnabled(bool enabled);
void setOpticalSensorEnabled(bool enabled);
void setAccelerometerEnabled(bool enabled);
void setAccelerometerRange(const SensorAccelerometerRange &range);
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);
@ -152,49 +159,43 @@ private:
SensorAccelerometerRange m_accelerometerRange = SensorAccelerometerRange16G;
// States
bool m_leftButtonPressed = false;
bool m_rightButtonPressed = false;
bool m_magnetDetected = false;
bool m_greenLedEnabled = false;
bool m_redLedEnabled = false;
bool m_buzzerEnabled = false;
double m_lastAccelerometerVectorLenght = -99999;
// 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 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);
// Set methods
void setLeftButtonPressed(bool pressed);
void setRightButtonPressed(bool pressed);
void setMagnetDetected(bool detected);
// Helper
bool testBitUint8(quint8 value, int bitPosition);
double roundValue(float value);
void setTemperatureSensorPower(bool power);
void setHumiditySensorPower(bool power);
void setPressureSensorPower(bool power);
void setOpticalSensorPower(bool power);
signals:
void leftButtonPressedChainged(bool pressed);
void rightButtonPressedChainged(bool pressed);
void magnetDetectedChainged(bool detected);
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);
@ -222,8 +223,6 @@ private slots:
// IO service
void onIoServiceStateChanged(const QLowEnergyService::ServiceState &state);
void onIoServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value);
void onBuzzerImpulseTimeout();
};
#endif // SENSORTAG_H