Add sensor actions

This commit is contained in:
Simon Stürz 2018-02-23 20:53:01 +01:00
parent 66398c3a29
commit 496db05c4c
5 changed files with 283 additions and 24 deletions

View File

@ -117,7 +117,6 @@ void DevicePluginMultiSensor::postSetupDevice(Device *device)
sensor->bluetoothDevice()->connectDevice();
}
void DevicePluginMultiSensor::deviceRemoved(Device *device)
{
if (!m_sensors.contains(device))
@ -129,6 +128,26 @@ void DevicePluginMultiSensor::deviceRemoved(Device *device)
sensor->deleteLater();
}
DeviceManager::DeviceError DevicePluginMultiSensor::executeAction(Device *device, const Action &action)
{
SensorTag *sensor = m_sensors.value(device);
if (action.actionTypeId() == sensortagBuzzerActionTypeId) {
sensor->setBuzzerPower(action.param(sensortagBuzzerStateParamTypeId).value().toBool());
return DeviceManager::DeviceErrorNoError;
} else if (action.actionTypeId() == sensortagGreenLedActionTypeId) {
sensor->setGreenLedPower(action.param(sensortagGreenLedStateParamTypeId).value().toBool());
return DeviceManager::DeviceErrorNoError;
} else if (action.actionTypeId() == sensortagRedLedActionTypeId) {
sensor->setRedLedPower(action.param(sensortagRedLedStateParamTypeId).value().toBool());
return DeviceManager::DeviceErrorNoError;
} else if (action.actionTypeId() == sensortagBuzzerImpulseActionTypeId) {
sensor->buzzerImpulse();
return DeviceManager::DeviceErrorNoError;
}
return DeviceManager::DeviceErrorActionTypeNotFound;
}
bool DevicePluginMultiSensor::verifyExistingDevices(const QBluetoothDeviceInfo &deviceInfo)
{
foreach (Device *device, m_sensors.keys()) {
@ -188,21 +207,11 @@ void DevicePluginMultiSensor::onPluginConfigurationChanged(const ParamTypeId &pa
} else if (paramTypeId == MultiSensorMagnetometerEnabledParamTypeId) {
sensor->setMagnetometerEnabled(value.toBool());
} else if (paramTypeId == MultiSensorMeasurementPeriodParamTypeId) {
int valueInt = value.toInt();
if (valueInt % 10 != 0) {
qCWarning(dcMultiSensor()) << "Measurement period of sensors" << valueInt << "must be a multiple of 10ms";
// FIXME: force to valid value
return;
}
sensor->setMeasurementPeriod(valueInt);
sensor->setMeasurementPeriod(value.toInt());
} else if (paramTypeId == MultiSensorMeasurementPeriodParamTypeId) {
int valueInt = value.toInt();
if (valueInt % 10 != 0) {
qCWarning(dcMultiSensor()) << "Measurement period of movement sensor" << valueInt << "must be a multiple of 10ms";
// FIXME: force to valid value
return;
}
sensor->setMeasurementPeriodMovement(valueInt);
sensor->setMeasurementPeriodMovement(value.toInt());
} else if (paramTypeId == MultiSensorMovementSensitivityParamTypeId) {
sensor->setMovementSensitivity(value.toInt());
}
}
}

View File

@ -49,6 +49,8 @@ public:
void postSetupDevice(Device *device) override;
void deviceRemoved(Device *device) override;
DeviceManager::DeviceError executeAction(Device *device, const Action &action) override;
private:
PluginTimer *m_reconnectTimer = nullptr;
QHash<Device *, SensorTag *> m_sensors;

View File

@ -178,6 +178,43 @@
"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",
"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",
"defaultValue": false,
"writable": true
},
{
"id": "d522c536-4427-4c53-9980-7820b2649aad",
"name": "buzzer",
"displayName": "Buzzer",
"displayNameEvent": "Buzzer power changed",
"displayNameAction": "Set buzzer power",
"type": "bool",
"defaultValue": false,
"writable": true
}
],
"actionTypes": [
{
"id": "a048ab2e-4f17-4467-a166-a7572156c07e",
"name": "buzzerImpulse",
"displayName": "Buzzer impulse"
}
]
}

View File

@ -24,6 +24,7 @@
#include "extern-plugininfo.h"
#include "math.h"
#include <QTimer>
#include <QVector3D>
#include <QDataStream>
@ -83,6 +84,12 @@ void SensorTag::setMeasurementPeriod(int period)
{
qCDebug(dcMultiSensor()) << "Set sensor measurement period to" << period << "ms";
if (period % 10 != 0) {
int adjustedValue = qRound(static_cast<float>(period) / 10.0) * 10;
qCWarning(dcMultiSensor()) << "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);
@ -105,6 +112,12 @@ void SensorTag::setMeasurementPeriodMovement(int period)
{
qCDebug(dcMultiSensor()) << "Set movement sensor measurement period to" << period << "ms";
if (period % 10 != 0) {
int adjustedValue = qRound(static_cast<float>(period) / 10.0) * 10;
qCWarning(dcMultiSensor()) << "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);
@ -116,6 +129,37 @@ void SensorTag::setMovementSensitivity(int percentage)
m_movementSensitivity = static_cast<double>(percentage) / 100.0;
}
void SensorTag::setGreenLedPower(bool power)
{
m_greenLedEnabled = power;
qCDebug(dcMultiSensor()) << "Green LED" << (power ? "enabled" : "disabled");
configureIo();
m_device->setStateValue(sensortagGreenLedStateTypeId, m_greenLedEnabled);
}
void SensorTag::setRedLedPower(bool power)
{
m_redLedEnabled = power;
qCDebug(dcMultiSensor()) << "Red LED" << (power ? "enabled" : "disabled");
configureIo();
m_device->setStateValue(sensortagRedLedStateTypeId, m_redLedEnabled);
}
void SensorTag::setBuzzerPower(bool power)
{
m_buzzerEnabled = power;
qCDebug(dcMultiSensor()) << "Buzzer" << (power ? "enabled" : "disabled");
configureIo();
m_device->setStateValue(sensortagBuzzerStateTypeId, m_buzzerEnabled);
}
void SensorTag::buzzerImpulse()
{
qCDebug(dcMultiSensor()) << "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);
@ -153,7 +197,28 @@ void SensorTag::configureMovement(bool gyroscopeEnabled, bool accelerometerEnabl
configuration |= (1 << 8); // enable
}
// Accelerometer 2 Bit ( 0 = 2G, 1 = 4G, 2 = 8G, 3 = 16G) - Default 0
// Accelerometer range 2 Bit ( 0 = 2G, 1 = 4G, 2 = 8G, 3 = 16G) - Default 0
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);
@ -163,6 +228,43 @@ void SensorTag::configureMovement(bool gyroscopeEnabled, bool accelerometerEnabl
m_movementService->writeCharacteristic(m_movementConfigurationCharacteristic, data);
}
void SensorTag::configureSensorMode(const SensorTag::SensorMode &mode)
{
if (!m_ioService || !m_ioDataCharacteristic.isValid())
return;
qCDebug(dcMultiSensor()) << "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::processTemperatureData(const QByteArray &data)
{
Q_ASSERT(data.count() == 4);
@ -281,9 +383,9 @@ void SensorTag::processMovementData(const QByteArray &data)
double gyroY = static_cast<double>(gyroYRaw) / (65536 / 500);
double gyroZ = static_cast<double>(gyroZRaw) / (65536 / 500);
double accX = static_cast<double>(accXRaw) / (32768 / m_accelerometerRange);
double accY = static_cast<double>(accYRaw) / (32768 / m_accelerometerRange);
double accZ = static_cast<double>(accZRaw) / (32768 / 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);
@ -291,7 +393,7 @@ void SensorTag::processMovementData(const QByteArray &data)
double magZ = static_cast<double>(magZRaw);
qCDebug(dcMultiSensor()) << "Accelerometer x:" << accX << " y:" << accY << " z:" << accZ;
//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;
@ -302,7 +404,11 @@ void SensorTag::processMovementData(const QByteArray &data)
Q_UNUSED(gyroscopeVector)
Q_UNUSED(magnetometerVector)
qCDebug(dcMultiSensor()) << accelerometerVector.length();
double limit = m_accelerometerRange * m_movementSensitivity;
bool motionDetected = (accelerometerVector.length() >= limit);
qCDebug(dcMultiSensor()) << accelerometerVector.length() << " | " << limit << (motionDetected ? "motion" : "-");
m_device->setStateValue(sensortagMovingStateTypeId, motionDetected);
}
void SensorTag::setLeftButtonPressed(bool pressed)
@ -414,6 +520,12 @@ void SensorTag::onServiceDiscoveryFinished()
return;
}
if (!m_bluetoothDevice->serviceUuids().contains(ioServiceUuid)) {
qCWarning(dcMultiSensor()) << "Could not find IO service";
m_bluetoothDevice->disconnectDevice();
return;
}
// IR Temperature
if (!m_temperatureService) {
m_temperatureService = m_bluetoothDevice->controller()->createServiceObject(temperatureServiceUuid, this);
@ -514,6 +626,23 @@ void SensorTag::onServiceDiscoveryFinished()
m_movementService->discoverDetails();
}
}
// IO
if (!m_ioService) {
m_ioService = m_bluetoothDevice->controller()->createServiceObject(ioServiceUuid, this);
if (!m_ioService) {
qCWarning(dcMultiSensor()) << "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::onTemperatureServiceStateChanged(const QLowEnergyService::ServiceState &state)
@ -825,7 +954,6 @@ void SensorTag::onMovementServiceStateChanged(const QLowEnergyService::ServiceSt
// Set measurement period
configurePeriod(m_movementService, m_movementPeriodCharacteristic, m_movementPeriod);
configureMovement(m_gyroscopeEnabled, m_accelerometerEnabled, m_magnetometerEnabled, true);
// Enable measuring
@ -838,3 +966,50 @@ void SensorTag::onMovementServiceCharacteristicChanged(const QLowEnergyCharacter
processMovementData(value);
}
}
void SensorTag::onIoServiceStateChanged(const QLowEnergyService::ServiceState &state)
{
// Only continue if discovered
if (state != QLowEnergyService::ServiceDiscovered)
return;
qCDebug(dcMultiSensor()) << "IO service discovered.";
foreach (const QLowEnergyCharacteristic &characteristic, m_pressureService->characteristics()) {
qCDebug(dcMultiSensor()) << " -->" << characteristic.name() << characteristic.uuid().toString() << characteristic.value();
foreach (const QLowEnergyDescriptor &desciptor, characteristic.descriptors()) {
qCDebug(dcMultiSensor()) << " -->" << desciptor.name() << desciptor.uuid().toString() << desciptor.value();
}
}
// Data characteristic
m_ioDataCharacteristic = m_ioService->characteristic(ioDataCharacteristicUuid);
if (!m_ioDataCharacteristic.isValid()) {
qCWarning(dcMultiSensor()) << "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(dcMultiSensor()) << "Invalid IO configuration characteristic.";
m_bluetoothDevice->disconnectDevice();
}
configureSensorMode(SensorModeRemote);
configureIo();
}
void SensorTag::onIoServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value)
{
qCDebug(dcMultiSensor()) << characteristic.uuid().toString() << value.toHex();
}
void SensorTag::onBuzzerImpulseTimeout()
{
setBuzzerPower(false);
}

View File

@ -68,11 +68,27 @@ 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 setAccelerometerEnabled(bool enabled);
void setGyroscopeEnabled(bool enabled);
void setMagnetometerEnabled(bool enabled);
@ -80,6 +96,12 @@ public:
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;
@ -91,6 +113,7 @@ private:
QLowEnergyService *m_opticalService = nullptr;
QLowEnergyService *m_keyService = nullptr;
QLowEnergyService *m_movementService = nullptr;
QLowEnergyService *m_ioService = nullptr;
// Characteristics
QLowEnergyCharacteristic m_temperatureDataCharacteristic;
@ -115,19 +138,25 @@ private:
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 = 50;
double m_movementSensitivity = 0.5;
// Note: possible value: 2G, 4G, 8G, 16G, default 2G
int m_accelerometerRange = 2;
SensorAccelerometerRange m_accelerometerRange = SensorAccelerometerRange16G;
bool m_leftButtonPressed = false;
bool m_rightButtonPressed = false;
bool m_magnetDetected = false;
bool m_greenLedEnabled = false;
bool m_redLedEnabled = false;
bool m_buzzerEnabled = false;
// Plugin configs
bool m_accelerometerEnabled = true;
@ -136,6 +165,8 @@ private:
void configurePeriod(QLowEnergyService *serice, const QLowEnergyCharacteristic &characteristic, int measurementPeriod);
void configureMovement(bool gyroscopeEnabled = false, bool accelerometerEnabled = true, bool magnetometerEnabled = true, bool wakeOnMotion = true);
void configureSensorMode(const SensorMode &mode);
void configureIo();
void processTemperatureData(const QByteArray &data);
void processKeyData(const QByteArray &data);
@ -186,6 +217,11 @@ private slots:
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);
void onBuzzerImpulseTimeout();
};
#endif // SENSORTAG_H