From 0479ecb0bb790157fd01f61a113c92f9c718adbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 22 Feb 2018 23:24:43 +0100 Subject: [PATCH 01/12] Add first version of new sensor tag --- multisensor/devicepluginmultisensor.cpp | 31 +- multisensor/devicepluginmultisensor.h | 9 +- multisensor/devicepluginmultisensor.json | 155 ++++-- multisensor/sensortag.cpp | 639 ++++++++++++++++++----- multisensor/sensortag.h | 167 ++++-- 5 files changed, 779 insertions(+), 222 deletions(-) diff --git a/multisensor/devicepluginmultisensor.cpp b/multisensor/devicepluginmultisensor.cpp index fb362375..e1e9aadb 100644 --- a/multisensor/devicepluginmultisensor.cpp +++ b/multisensor/devicepluginmultisensor.cpp @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Copyright (C) 2015 Simon Stuerz * + * Copyright (C) 2015-2018 Simon Stuerz * * Copyright (C) 2016 nicc * * * * This file is part of nymea. * @@ -52,10 +52,15 @@ DevicePluginMultiSensor::DevicePluginMultiSensor() } +DevicePluginMultiSensor::~DevicePluginMultiSensor() +{ + hardwareManager()->pluginTimerManager()->unregisterTimer(m_reconnectTimer); +} + void DevicePluginMultiSensor::init() { - m_measureTimer = hardwareManager()->pluginTimerManager()->registerTimer(60); - connect(m_measureTimer, &PluginTimer::timeout, this, &DevicePluginMultiSensor::onPluginTimer); + m_reconnectTimer = hardwareManager()->pluginTimerManager()->registerTimer(10); + connect(m_reconnectTimer, &PluginTimer::timeout, this, &DevicePluginMultiSensor::onPluginTimer); } DeviceManager::DeviceError DevicePluginMultiSensor::discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) @@ -89,8 +94,6 @@ DeviceManager::DeviceSetupStatus DevicePluginMultiSensor::setupDevice(Device *de BluetoothLowEnergyDevice *bluetoothDevice = hardwareManager()->bluetoothLowEnergyManager()->registerDevice(deviceInfo, QLowEnergyController::PublicAddress); SensorTag *sensor = new SensorTag(device, bluetoothDevice, this); - connect(sensor, &SensorTag::leftKeyPressed, this, &DevicePluginMultiSensor::onSensorLeftButtonPressed); - connect(sensor, &SensorTag::rightKeyPressed, this, &DevicePluginMultiSensor::onSensorRightButtonPressed); m_sensors.insert(device, sensor); sensor->bluetoothDevice()->connectDevice(); @@ -124,23 +127,13 @@ bool DevicePluginMultiSensor::verifyExistingDevices(const QBluetoothDeviceInfo & void DevicePluginMultiSensor::onPluginTimer() { - foreach (SensorTag *sensor, m_sensors) { - sensor->measure(); + foreach (SensorTag *sensor, m_sensors.values()) { + if (!sensor->bluetoothDevice()->connected()) { + sensor->bluetoothDevice()->connectDevice(); + } } } -void DevicePluginMultiSensor::onSensorLeftButtonPressed() -{ - SensorTag *sensor = static_cast(sender()); - emit emitEvent(Event(sensortagLeftKeyEventTypeId, sensor->device()->id())); -} - -void DevicePluginMultiSensor::onSensorRightButtonPressed() -{ - SensorTag *sensor = static_cast(sender()); - emit emitEvent(Event(sensortagRightKeyEventTypeId, sensor->device()->id())); -} - void DevicePluginMultiSensor::onBluetoothDiscoveryFinished() { BluetoothDiscoveryReply *reply = static_cast(sender()); diff --git a/multisensor/devicepluginmultisensor.h b/multisensor/devicepluginmultisensor.h index 0731b207..22206770 100644 --- a/multisensor/devicepluginmultisensor.h +++ b/multisensor/devicepluginmultisensor.h @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Copyright (C) 2015 Simon Stuerz * + * Copyright (C) 2015-2018 Simon Stuerz * * Copyright (C) 2016 nicc * * * * This file is part of nymea. * @@ -41,6 +41,7 @@ class DevicePluginMultiSensor : public DevicePlugin public: explicit DevicePluginMultiSensor(); + ~DevicePluginMultiSensor(); void init() override; DeviceManager::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) override; @@ -48,17 +49,13 @@ public: void deviceRemoved(Device *device) override; private: - PluginTimer *m_measureTimer = nullptr; + PluginTimer *m_reconnectTimer = nullptr; QHash m_sensors; bool verifyExistingDevices(const QBluetoothDeviceInfo &deviceInfo); private slots: void onPluginTimer(); - - void onSensorLeftButtonPressed(); - void onSensorRightButtonPressed(); - void onBluetoothDiscoveryFinished(); }; diff --git a/multisensor/devicepluginmultisensor.json b/multisensor/devicepluginmultisensor.json index 93711f0f..f71831a8 100644 --- a/multisensor/devicepluginmultisensor.json +++ b/multisensor/devicepluginmultisensor.json @@ -2,6 +2,47 @@ "displayName": "MultiSensor", "name": "MultiSensor", "id": "23bf0d8d-df7d-4bee-80ee-f015c5a7f52e", + "paramTypes": [ + { + "id": "5786c91a-d94d-461a-8d22-f978dd1438ab", + "name": "accelerometerEnabled", + "displayName": "Accelerometer enabled", + "type": "bool", + "defaultValue": true + }, + { + "id": "94517544-cb97-4816-8993-cb4cf2651a1e", + "name": "gyroscopeEnabled", + "displayName": "Gyroscope enabled", + "type": "bool", + "defaultValue": false + }, + { + "id": "96aae111-b1c1-48a1-9b1f-b56efa546d0d", + "name": "magnetometerEnabled", + "displayName": "Magnetometer enabled", + "type": "bool", + "defaultValue": false + }, + { + "id": "5237c89c-c21d-4d78-ac99-8be661b40da7", + "name": "measurementPeriodMovement", + "displayName": "Measurement period movement sensor", + "type": "int", + "minValue": 10, + "maxValue": 2500, + "defaultValue": 2000 + }, + { + "id": "c5308565-5dc9-409e-ae99-577c212c7a92", + "name": "measurementPeriod", + "displayName": "Measurement period for enviromental sensors", + "type": "int", + "minValue": 10, + "maxValue": 2500, + "defaultValue": 500 + } + ], "vendors": [ { "id": "2edf543e-dc2c-4693-bb0c-e76c0d305fad", @@ -9,12 +50,12 @@ "displayName": "Texas Instruments", "deviceClasses": [ { - "displayName": "Sensor Tag", - "name": "sensortag", "id": "158a06b6-b27f-4951-957e-6f1e3b44f604", + "name": "sensortag", + "displayName": "Sensor Tag (CC2650)", "createMethods": ["discovery"], "deviceIcon": "Thermometer", - "criticalStateTypeId": "a9629b11-0f34-47f0-a0f0-f758a6aec2b4", + "interfaces": ["connectable", "humiditysensor", "temperaturesensor"], "basicTags": [ "Device", "Sensor" @@ -23,14 +64,14 @@ { "id": "bdb9d684-2f98-45f5-889c-f184c1e73dc7", "name": "name", - "displayName": "name", + "displayName": "Name", "type": "QString", "inputType": "TextLine" }, { "id": "d51ed68e-c84a-4136-a5b5-be2f95fd5a0f", "name": "mac", - "displayName": "mac address", + "displayName": "MAC address", "type": "QString", "inputType": "MacAddress" } @@ -39,29 +80,12 @@ { "id": "a9629b11-0f34-47f0-a0f0-f758a6aec2b4", "name": "connected", - "displayName": "connected", - "displayNameEvent": "connected changed", + "displayName": "Connected", + "displayNameEvent": "Connected changed", "type": "bool", + "cached": false, "defaultValue": false }, - { - "id": "c664e9ec-a045-49ba-add1-1642ceba7c4f", - "name": "IRtemperature", - "displayName": "IR temperature", - "displayNameEvent": "IR temperature changed", - "type": "double", - "unit": "DegreeCelsius", - "defaultValue": 0 - }, - { - "id": "e83a50ff-96c9-4b6d-889f-f4238353e794", - "name": "humidity", - "displayName": "humidity", - "displayNameEvent": "humidity changed", - "type": "double", - "unit": "Percentage", - "defaultValue": 0 - }, { "id": "8359ada9-df1c-4e60-bb87-9e21d05ee2e2", "name": "temperature", @@ -71,34 +95,79 @@ "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": "pressure", - "displayNameEvent": "pressure changed", + "displayName": "Barometric pressure", + "displayNameEvent": "Barometric pressure changed", "type": "double", "unit": "HectoPascal", "defaultValue": 0 }, { - "id": "4be5ca26-0565-419d-b18b-2a5a385d2a3d", - "name": "moving", - "displayName": "moving", - "displayNameEvent": "moving changed", - "type": "bool", - "defaultValue": false - } - ], - "eventTypes": [ - { - "id": "61478490-bed0-4fed-9d58-f13c35b4f220", - "name": "leftKey", - "displayName": "left key pressed" + "id": "6635dce4-2d8d-4608-a836-768c3014f356", + "name": "lightIntensity", + "displayName": "Light intensity", + "displayNameEvent": "Light intensity changed", + "type": "double", + "unit": "Lux", + "defaultValue": 0 }, { - "id": "b7e927db-af28-4fdc-8eb7-edb02258ff5a", - "name": "rightKey", - "displayName": "right key pressed" + "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 } ] } diff --git a/multisensor/sensortag.cpp b/multisensor/sensortag.cpp index 6d261e7b..8e331e4e 100644 --- a/multisensor/sensortag.cpp +++ b/multisensor/sensortag.cpp @@ -1,6 +1,30 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015-2018 Simon Stuerz * + * * + * 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 * + * . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include "sensortag.h" #include "extern-plugininfo.h" +#include + SensorTag::SensorTag(Device *device, BluetoothLowEnergyDevice *bluetoothDevice, QObject *parent) : QObject(parent), m_device(device), @@ -20,28 +44,212 @@ BluetoothLowEnergyDevice *SensorTag::bluetoothDevice() return m_bluetoothDevice; } -void SensorTag::updateInfraredValue(const QByteArray &value) +void SensorTag::setAccelerometerEnabled(bool enabled) { - qCDebug(dcMultiSensor()) << "Infrared value" << value; + m_accelerometerEnabled = enabled; } -void SensorTag::updateButtonValue(const QByteArray &value) +void SensorTag::configurePeriod(QLowEnergyService *serice, const QLowEnergyCharacteristic &characteristic, int measurementPeriod) { - const quint8 *data = reinterpret_cast(value.constData()); - if (*data & 1) - emit leftKeyPressed(); - if (*data & 2) - emit rightKeyPressed(); + Q_ASSERT(measurementPeriod % 10 == 0); + QByteArray payload; + QDataStream stream(&payload, QIODevice::WriteOnly); + stream << static_cast(measurementPeriod / 10); + + qCDebug(dcMultiSensor()) << "Configure period to" << measurementPeriod << payload.toHex(); + serice->writeCharacteristic(characteristic, payload); } -void SensorTag::updateHumidityValue(const QByteArray &value) +void SensorTag::configureMovement(bool gyroscopeEnabled, bool accelerometerEnabled, bool magnetometerEnabled, bool wakeOnMotion) { - qCDebug(dcMultiSensor()) << "Humidity value" << value; + if (!m_movementService || !m_movementConfigurationCharacteristic.isValid()) + return; + + quint16 configuration = 0; + if (gyroscopeEnabled) { + configuration |= (1 << 0); // enable x-axis + configuration |= (1 << 1); // enable y-axis + configuration |= (1 << 2); // enable z-axis + } + + if (accelerometerEnabled) { + configuration |= (1 << 3); // enable x-axis + configuration |= (1 << 4); // enable y-axis + configuration |= (1 << 5); // enable z-axis + } + + if (magnetometerEnabled) { + configuration |= (1 << 6); // enable all axis + } + + if (wakeOnMotion) { + configuration |= (1 << 8); // enable + } + + // Accelerometer 2 Bit ( 0 = 2G, 1 = 4G, 2 = 8G, 3 = 16G) + // Default 0 + + QByteArray data; + QDataStream stream(&data, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::BigEndian); + stream << configuration; + + qCDebug(dcMultiSensor()) << "Configure movement sensor" << data.toHex(); + m_movementService->writeCharacteristic(m_movementConfigurationCharacteristic, data); } -void SensorTag::updatePressureValue(const QByteArray &value) +void SensorTag::processTemperatureData(const QByteArray &data) { - qCDebug(dcMultiSensor()) << "Pressure value" << value; + 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(rawObjectTemperature) / 4 * scaleFactor; + float ambientTemperature = static_cast(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(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 ; + + //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 pressureData(data.right(3)); + quint32 rawPressure = static_cast(pressureData.at(2)); + rawPressure <<= 8; + rawPressure |= static_cast(pressureData.at(1)); + rawPressure <<= 8; + rawPressure |= static_cast(pressureData.at(0)); + + //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); + + 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, unit deg/s, range -250, +250 + double gyroX = static_cast(gyroXRaw) / (65536 / 500); + double gyroY = static_cast(gyroYRaw) / (65536 / 500); + double gyroZ = static_cast(gyroZRaw) / (65536 / 500); + qCDebug(dcMultiSensor()) << "Gyroscope x:" << gyroX << " y:" << gyroY << " z:" << gyroZ; + +} + +void SensorTag::setLeftButtonPressed(bool pressed) +{ + if (m_leftButtonPressed == pressed) + return; + + qCDebug(dcMultiSensor()) << "Left button" << (pressed ? "pressed" : "released"); + m_leftButtonPressed = pressed; + emit leftButtonPressedChainged(m_leftButtonPressed); + m_device->setStateValue(sensortagLeftButtonPressedStateTypeId, m_leftButtonPressed); +} + +void SensorTag::setRightButtonPressed(bool pressed) +{ + if (m_rightButtonPressed == pressed) + return; + + qCDebug(dcMultiSensor()) << "Right button" << (pressed ? "pressed" : "released"); + m_rightButtonPressed = pressed; + emit rightButtonPressedChainged(m_rightButtonPressed); + m_device->setStateValue(sensortagRightButtonPressedStateTypeId, m_rightButtonPressed); +} + +void SensorTag::setMagnetDetected(bool detected) +{ + if (m_magnetDetected == detected) + return; + + qCDebug(dcMultiSensor()) << "Magnet detector" << (detected ? "active" : "inactive"); + m_magnetDetected = detected; + emit magnetDetectedChainged(m_magnetDetected); + m_device->setStateValue(sensortagMagnetDetectedStateTypeId, m_magnetDetected); +} + +bool SensorTag::testBitUint8(quint8 value, int bitPosition) +{ + return (((value)>> (bitPosition)) & 1); +} + +double SensorTag::roundValue(float value) +{ + int tmpValue = static_cast(value * 10); + return static_cast(tmpValue) / 10.0; } void SensorTag::onConnectedChanged(const bool &connected) @@ -51,80 +259,79 @@ void SensorTag::onConnectedChanged(const bool &connected) if (!connected) { // Clean up services - m_infraredService->deleteLater(); - m_buttonService->deleteLater(); + m_temperatureService->deleteLater(); m_humidityService->deleteLater(); m_pressureService->deleteLater(); + m_opticalService->deleteLater(); + m_keyService->deleteLater(); + m_movementService->deleteLater(); - m_infraredService = nullptr; - m_buttonService = nullptr; + m_temperatureService = nullptr; m_humidityService = nullptr; m_pressureService = nullptr; + m_opticalService = nullptr; + m_keyService = nullptr; + m_movementService = nullptr; } - } void SensorTag::onServiceDiscoveryFinished() { - if (!m_bluetoothDevice->serviceUuids().contains(infraredServiceUuid)) { - qCWarning(dcMultiSensor()) << "Could not find infrared service"; - return; + foreach (const QBluetoothUuid serviceUuid, m_bluetoothDevice->serviceUuids()) { + qCDebug(dcMultiSensor()) << "-->" << serviceUuid; } - if (!m_bluetoothDevice->serviceUuids().contains(accelerometerServiceUuid)) { - qCWarning(dcMultiSensor()) << "Could not find accelereometer service"; + if (!m_bluetoothDevice->serviceUuids().contains(temperatureServiceUuid)) { + qCWarning(dcMultiSensor()) << "Could not find temperature service"; + m_bluetoothDevice->disconnectDevice(); return; } if (!m_bluetoothDevice->serviceUuids().contains(humidityServiceUuid)) { qCWarning(dcMultiSensor()) << "Could not find humidity service"; - return; - } - - if (!m_bluetoothDevice->serviceUuids().contains(magnetometerServiceUuid)) { - qCWarning(dcMultiSensor()) << "Could not find magnetometer service"; + m_bluetoothDevice->disconnectDevice(); return; } if (!m_bluetoothDevice->serviceUuids().contains(pressureServiceUuid)) { qCWarning(dcMultiSensor()) << "Could not find pressure service"; + m_bluetoothDevice->disconnectDevice(); return; } - if (!m_bluetoothDevice->serviceUuids().contains(gyroscopeServiceUuid)) { - qCWarning(dcMultiSensor()) << "Could not find magnetometer service"; + if (!m_bluetoothDevice->serviceUuids().contains(opticalServiceUuid)) { + qCWarning(dcMultiSensor()) << "Could not find optical service"; + m_bluetoothDevice->disconnectDevice(); return; } + if (!m_bluetoothDevice->serviceUuids().contains(keyServiceUuid)) { + qCWarning(dcMultiSensor()) << "Could not find key service"; + m_bluetoothDevice->disconnectDevice(); + return; + } + + if (!m_bluetoothDevice->serviceUuids().contains(movementServiceUuid)) { + qCWarning(dcMultiSensor()) << "Could not find movement service"; + m_bluetoothDevice->disconnectDevice(); + return; + } + + // IR Temperature - if (!m_infraredService) { - m_infraredService = m_bluetoothDevice->controller()->createServiceObject(infraredServiceUuid, this); - if (!m_infraredService) { - qCWarning(dcMultiSensor()) << "Could not create infrared service."; + if (!m_temperatureService) { + m_temperatureService = m_bluetoothDevice->controller()->createServiceObject(temperatureServiceUuid, this); + if (!m_temperatureService) { + qCWarning(dcMultiSensor()) << "Could not create temperature service."; + m_bluetoothDevice->disconnectDevice(); return; } - connect(m_infraredService, &QLowEnergyService::stateChanged, this, &SensorTag::onInfraredServiceStateChanged); - connect(m_infraredService, &QLowEnergyService::characteristicChanged, this, &SensorTag::onInfraredServiceCharacteristicChanged); + connect(m_temperatureService, &QLowEnergyService::stateChanged, this, &SensorTag::onTemperatureServiceStateChanged); + connect(m_temperatureService, &QLowEnergyService::characteristicChanged, this, &SensorTag::onTemperatureServiceCharacteristicChanged); - if (m_infraredService->state() == QLowEnergyService::DiscoveryRequired) { - m_infraredService->discoverDetails(); - } - } - - // Buttons - if (!m_buttonService) { - m_buttonService = m_bluetoothDevice->controller()->createServiceObject(buttonServiceUuid, this); - if (!m_buttonService) { - qCWarning(dcMultiSensor()) << "Could not create button service."; - return; - } - - connect(m_buttonService, &QLowEnergyService::stateChanged, this, &SensorTag::onButtonServiceStateChanged); - connect(m_buttonService, &QLowEnergyService::characteristicChanged, this, &SensorTag::onButtonServiceCharacteristicChanged); - - if (m_buttonService->state() == QLowEnergyService::DiscoveryRequired) { - m_buttonService->discoverDetails(); + if (m_temperatureService->state() == QLowEnergyService::DiscoveryRequired) { + m_temperatureService->discoverDetails(); } } @@ -133,6 +340,7 @@ void SensorTag::onServiceDiscoveryFinished() m_humidityService = m_bluetoothDevice->controller()->createServiceObject(humidityServiceUuid, this); if (!m_humidityService) { qCWarning(dcMultiSensor()) << "Could not create humidity service."; + m_bluetoothDevice->disconnectDevice(); return; } @@ -148,6 +356,7 @@ void SensorTag::onServiceDiscoveryFinished() m_pressureService = m_bluetoothDevice->controller()->createServiceObject(pressureServiceUuid, this); if (!m_pressureService) { qCWarning(dcMultiSensor()) << "Could not create pressure service."; + m_bluetoothDevice->disconnectDevice(); return; } @@ -157,17 +366,69 @@ void SensorTag::onServiceDiscoveryFinished() m_pressureService->discoverDetails(); } } + + + // Optical + if (!m_opticalService) { + m_opticalService = m_bluetoothDevice->controller()->createServiceObject(opticalServiceUuid, this); + if (!m_opticalService) { + qCWarning(dcMultiSensor()) << "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(dcMultiSensor()) << "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(dcMultiSensor()) << "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(); + } + } } -void SensorTag::onInfraredServiceStateChanged(const QLowEnergyService::ServiceState &state) +void SensorTag::onTemperatureServiceStateChanged(const QLowEnergyService::ServiceState &state) { // Only continue if discovered if (state != QLowEnergyService::ServiceDiscovered) return; - qCDebug(dcMultiSensor()) << "Infrared sensor service discovered."; + qCDebug(dcMultiSensor()) << "Temperature sensor service discovered."; - foreach (const QLowEnergyCharacteristic &characteristic, m_infraredService->characteristics()) { + foreach (const QLowEnergyCharacteristic &characteristic, m_temperatureService->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(); @@ -175,66 +436,47 @@ void SensorTag::onInfraredServiceStateChanged(const QLowEnergyService::ServiceSt } // Data characteristic - m_infraredDataCharacteristic = m_infraredService->characteristic(QBluetoothUuid(QUuid("f000aa01-0451-4000-b000-000000000000"))); - if (!m_infraredDataCharacteristic.isValid()) { - qCWarning(dcMultiSensor()) << "Invalid infrared data characteristic."; + m_temperatureDataCharacteristic = m_temperatureService->characteristic(QBluetoothUuid(QUuid("f000aa01-0451-4000-b000-000000000000"))); + if (!m_temperatureDataCharacteristic.isValid()) { + qCWarning(dcMultiSensor()) << "Invalid temperature data characteristic."; + m_bluetoothDevice->disconnectDevice(); + return; } // Enable notifications - QLowEnergyDescriptor notificationDescriptor = m_infraredDataCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration); - m_infraredService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100")); + QLowEnergyDescriptor notificationDescriptor = m_temperatureDataCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration); + m_temperatureService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100")); // Config characteristic - m_infraredConfigCharacteristic = m_infraredService->characteristic(QBluetoothUuid(QUuid("f000aa02-0451-4000-b000-000000000000"))); - if (!m_infraredConfigCharacteristic.isValid()) { - qCWarning(dcMultiSensor()) << "Invalid infrared configuration characteristic."; + m_temperatureConfigurationCharacteristic = m_temperatureService->characteristic(temperatureConfigurationCharacteristicUuid); + if (!m_temperatureConfigurationCharacteristic.isValid()) { + qCWarning(dcMultiSensor()) << "Invalid temperature configuration characteristic."; + m_bluetoothDevice->disconnectDevice(); + return; } + // Period characteristic + m_temperaturePeriodCharacteristic = m_temperatureService->characteristic(temperaturePeriodCharacteristicUuid); + if (!m_temperaturePeriodCharacteristic.isValid()) { + qCWarning(dcMultiSensor()) << "Invalid temperature period characteristic."; + m_bluetoothDevice->disconnectDevice(); + return; + } + + configurePeriod(m_temperatureService, m_temperaturePeriodCharacteristic, m_temperaturePeriod); + // Enable measuring - m_infraredService->writeCharacteristic(m_infraredConfigCharacteristic, QByteArray::fromHex("01")); + m_temperatureService->writeCharacteristic(m_temperatureConfigurationCharacteristic, QByteArray::fromHex("01")); } -void SensorTag::onInfraredServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) +void SensorTag::onTemperatureServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) { - if (characteristic == m_infraredDataCharacteristic) { - updateInfraredValue(value); + if (characteristic == m_temperatureDataCharacteristic) { + processTemperatureData(value); // FIXME: Disable measuring - // m_infraredService->writeCharacteristic(m_infraredConfigCharacteristic, QByteArray::fromHex("00")); - } -} - -void SensorTag::onButtonServiceStateChanged(const QLowEnergyService::ServiceState &state) -{ - // Only continue if discovered - if (state != QLowEnergyService::ServiceDiscovered) - return; - - qCDebug(dcMultiSensor()) << "Button sensor service discovered."; - - foreach (const QLowEnergyCharacteristic &characteristic, m_buttonService->characteristics()) { - qCDebug(dcMultiSensor()) << " -->" << characteristic.name() << characteristic.uuid().toString() << characteristic.value(); - foreach (const QLowEnergyDescriptor &desciptor, characteristic.descriptors()) { - qCDebug(dcMultiSensor()) << " -->" << desciptor.name() << desciptor.uuid().toString() << desciptor.value(); - } - } - - // Data characteristic - m_buttonCharacteristic = m_buttonService->characteristic(QBluetoothUuid(QUuid("0000ffe1-0000-1000-8000-00805f9b34fb"))); - if (!m_buttonCharacteristic.isValid()) { - qCWarning(dcMultiSensor()) << "Invalid button data characteristic."; - } - - // Enable notifications - QLowEnergyDescriptor notificationDescriptor = m_buttonCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration); - m_buttonService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100")); -} - -void SensorTag::onButtonServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) -{ - if (characteristic == m_buttonCharacteristic) { - updateButtonValue(value); + // m_temperatureService->writeCharacteristic(m_temperatureConfigCharacteristic, QByteArray::fromHex("00")); } } @@ -254,9 +496,11 @@ void SensorTag::onHumidityServiceStateChanged(const QLowEnergyService::ServiceSt } // Data characteristic - m_humidityDataCharacteristic = m_humidityService->characteristic(QBluetoothUuid(QUuid("f000aa21-0451-4000-b000-000000000000"))); + m_humidityDataCharacteristic = m_humidityService->characteristic(humidityDataCharacteristicUuid); if (!m_humidityDataCharacteristic.isValid()) { qCWarning(dcMultiSensor()) << "Invalid humidity data characteristic."; + m_bluetoothDevice->disconnectDevice(); + return; } // Enable notifications @@ -264,19 +508,31 @@ void SensorTag::onHumidityServiceStateChanged(const QLowEnergyService::ServiceSt m_humidityService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100")); // Config characteristic - m_humidityConfigCharacteristic = m_humidityService->characteristic(QBluetoothUuid(QUuid("f000aa22-0451-4000-b000-000000000000"))); - if (!m_humidityConfigCharacteristic.isValid()) { + m_humidityConfigurationCharacteristic = m_humidityService->characteristic(humidityConfigurationCharacteristicUuid); + if (!m_humidityConfigurationCharacteristic.isValid()) { qCWarning(dcMultiSensor()) << "Invalid humidity configuration characteristic."; + m_bluetoothDevice->disconnectDevice(); + return; } + // Period characteristic + m_humidityPeriodCharacteristic = m_humidityService->characteristic(humidityPeriodCharacteristicUuid); + if (!m_humidityPeriodCharacteristic.isValid()) { + qCWarning(dcMultiSensor()) << "Invalid humidity period characteristic."; + m_bluetoothDevice->disconnectDevice(); + return; + } + + configurePeriod(m_humidityService, m_humidityPeriodCharacteristic, m_humidityPeriod); + // Enable measuring - m_humidityService->writeCharacteristic(m_humidityConfigCharacteristic, QByteArray::fromHex("01")); + m_humidityService->writeCharacteristic(m_humidityConfigurationCharacteristic, QByteArray::fromHex("01")); } void SensorTag::onHumidityServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) { if (characteristic == m_humidityDataCharacteristic) { - updateHumidityValue(value); + processHumidityData(value); // FIXME: Disable measuring // m_humidityService->writeCharacteristic(m_humidityConfigCharacteristic, QByteArray::fromHex("00")); } @@ -298,9 +554,11 @@ void SensorTag::onPressureServiceStateChanged(const QLowEnergyService::ServiceSt } // Data characteristic - m_pressureDataCharacteristic = m_pressureService->characteristic(QBluetoothUuid(QUuid("f000aa41-0451-4000-b000-000000000000"))); + m_pressureDataCharacteristic = m_pressureService->characteristic(pressureDataCharacteristicUuid); if (!m_pressureDataCharacteristic.isValid()) { qCWarning(dcMultiSensor()) << "Invalid pressure data characteristic."; + m_bluetoothDevice->disconnectDevice(); + return; } // Enable notifications @@ -308,36 +566,179 @@ void SensorTag::onPressureServiceStateChanged(const QLowEnergyService::ServiceSt m_pressureService->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100")); // Config characteristic - m_pressureConfigCharacteristic = m_pressureService->characteristic(QBluetoothUuid(QUuid("f000aa42-0451-4000-b000-000000000000"))); - if (!m_pressureConfigCharacteristic.isValid()) { + m_pressureConfigurationCharacteristic = m_pressureService->characteristic(pressureConfigurationCharacteristicUuid); + if (!m_pressureConfigurationCharacteristic.isValid()) { qCWarning(dcMultiSensor()) << "Invalid pressure configuration characteristic."; + m_bluetoothDevice->disconnectDevice(); + return; } + // Period characteristic + m_pressurePeriodCharacteristic = m_pressureService->characteristic(pressurePeriodCharacteristicUuid); + if (!m_pressurePeriodCharacteristic.isValid()) { + qCWarning(dcMultiSensor()) << "Invalid pressure period characteristic."; + m_bluetoothDevice->disconnectDevice(); + return; + } + + configurePeriod(m_pressureService, m_pressurePeriodCharacteristic, m_pressurePeriod); + // Enable measuring - m_pressureService->writeCharacteristic(m_pressureConfigCharacteristic, QByteArray::fromHex("01")); + m_pressureService->writeCharacteristic(m_pressureConfigurationCharacteristic, QByteArray::fromHex("01")); } void SensorTag::onPressureServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) { if (characteristic == m_pressureDataCharacteristic) { - updatePressureValue(value); + processPressureData(value); // FIXME: Disable measuring // m_pressureService->writeCharacteristic(m_pressureConfigCharacteristic, QByteArray::fromHex("00")); } } -void SensorTag::measure() +void SensorTag::onOpticalServiceStateChanged(const QLowEnergyService::ServiceState &state) { - if (!m_bluetoothDevice->connected()) + // Only continue if discovered + if (state != QLowEnergyService::ServiceDiscovered) return; - // TODO: measure using plugintimer to save energy + qCDebug(dcMultiSensor()) << "Optical sensor service discovered."; -// qCDebug(dcMultiSensor()) << "Measure data" << m_bluetoothDevice->name() << m_bluetoothDevice->address().toString(); + 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(); + } + } -// m_infraredService->writeCharacteristic(m_infraredConfigCharacteristic, QByteArray::fromHex("01")); -// m_humidityService->writeCharacteristic(m_humidityConfigCharacteristic, QByteArray::fromHex("01")); -// m_pressureService->writeCharacteristic(m_pressureConfigCharacteristic, QByteArray::fromHex("01")); + // Data characteristic + m_opticalDataCharacteristic = m_opticalService->characteristic(opticalDataCharacteristicUuid); + if (!m_opticalDataCharacteristic.isValid()) { + qCWarning(dcMultiSensor()) << "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(dcMultiSensor()) << "Invalid optical configuration characteristic."; + m_bluetoothDevice->disconnectDevice(); + } + + // Period characteristic + m_opticalPeriodCharacteristic = m_opticalService->characteristic(opticalPeriodCharacteristicUuid); + if (!m_opticalPeriodCharacteristic.isValid()) { + qCWarning(dcMultiSensor()) << "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) { + processOpticalData(value); + // FIXME: Disable measuring + // m_opticalService->writeCharacteristic(m_pressureopticalCharacteristic, QByteArray::fromHex("00")); + } } +void SensorTag::onKeyServiceStateChanged(const QLowEnergyService::ServiceState &state) +{ + // Only continue if discovered + if (state != QLowEnergyService::ServiceDiscovered) + return; + + qCDebug(dcMultiSensor()) << "Key service discovered."; + foreach (const QLowEnergyCharacteristic &characteristic, m_keyService->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_keyDataCharacteristic = m_keyService->characteristic(keyDataCharacteristicUuid); + if (!m_keyDataCharacteristic.isValid()) { + qCWarning(dcMultiSensor()) << "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) { + processKeyData(value); + } +} + +void SensorTag::onMovementServiceStateChanged(const QLowEnergyService::ServiceState &state) +{ + // Only continue if discovered + if (state != QLowEnergyService::ServiceDiscovered) + return; + + qCDebug(dcMultiSensor()) << "Movement sensor service discovered."; + + foreach (const QLowEnergyCharacteristic &characteristic, m_pressureService->characteristics()) { + qCDebug(dcMultiSensor()) << " -->" << characteristic.name() << characteristic.uuid().toString() << characteristic.value(); + foreach (const QLowEnergyDescriptor &desciptor, characteristic.descriptors()) { + qCDebug(dcMultiSensor()) << " -->" << desciptor.name() << desciptor.uuid().toString() << desciptor.value(); + } + } + + // Data characteristic + m_movementDataCharacteristic = m_movementService->characteristic(movementDataCharacteristicUuid); + if (!m_movementDataCharacteristic.isValid()) { + qCWarning(dcMultiSensor()) << "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(dcMultiSensor()) << "Invalid movement configuration characteristic."; + m_bluetoothDevice->disconnectDevice(); + } + + // Period characteristic + m_movementPeriodCharacteristic = m_movementService->characteristic(movementPeriodCharacteristicUuid); + if (!m_movementPeriodCharacteristic.isValid()) { + qCWarning(dcMultiSensor()) << "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) { + processMovementData(value); + } +} diff --git a/multisensor/sensortag.h b/multisensor/sensortag.h index d1a18833..ad98702b 100644 --- a/multisensor/sensortag.h +++ b/multisensor/sensortag.h @@ -1,3 +1,25 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015-2018 Simon Stuerz * + * * + * 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 * + * . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #ifndef SENSORTAG_H #define SENSORTAG_H @@ -7,17 +29,40 @@ #include "extern-plugininfo.h" #include "hardware/bluetoothlowenergy/bluetoothlowenergydevice.h" -static QBluetoothUuid infraredServiceUuid = QBluetoothUuid(QUuid("f000aa00-0451-4000-b000-000000000000")); -static QBluetoothUuid accelerometerServiceUuid = QBluetoothUuid(QUuid("f000aa10-0451-4000-b000-000000000000")); -static QBluetoothUuid humidityServiceUuid = QBluetoothUuid(QUuid("f000aa20-0451-4000-b000-000000000000")); -static QBluetoothUuid magnetometerServiceUuid = QBluetoothUuid(QUuid("f000aa30-0451-4000-b000-000000000000")); -static QBluetoothUuid pressureServiceUuid = QBluetoothUuid(QUuid("f000aa40-0451-4000-b000-000000000000")); -static QBluetoothUuid gyroscopeServiceUuid = QBluetoothUuid(QUuid("f000aa50-0451-4000-b000-000000000000")); -static QBluetoothUuid testServiceUuid = QBluetoothUuid(QUuid("f000aa60-0451-4000-b000-000000000000")); -static QBluetoothUuid otaServiceUuid = QBluetoothUuid(QUuid("f000aac0-0451-4000-b000-000000000000")); -static QBluetoothUuid buttonServiceUuid = QBluetoothUuid(QUuid("0000ffe0-0000-1000-8000-00805f9b34fb")); +// 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")); -// Currently unused services class SensorTag : public QObject { @@ -28,49 +73,93 @@ public: Device *device(); BluetoothLowEnergyDevice *bluetoothDevice(); + void setAccelerometerEnabled(bool enabled); + void setGyroscopeEnabled(bool enabled); + void setMagnetometerEnabled(bool enabled); + void setMeasurementPeriod(int period); + private: Device *m_device; BluetoothLowEnergyDevice *m_bluetoothDevice; // Services - QLowEnergyService *m_infraredService = nullptr; - QLowEnergyService *m_buttonService = nullptr; + QLowEnergyService *m_temperatureService = nullptr; QLowEnergyService *m_humidityService = nullptr; QLowEnergyService *m_pressureService = nullptr; - QLowEnergyService *m_accelerometerService = nullptr; - QLowEnergyService *m_magnetometerService = nullptr; - QLowEnergyService *m_gyroscopeService = nullptr; + QLowEnergyService *m_opticalService = nullptr; + QLowEnergyService *m_keyService = nullptr; + QLowEnergyService *m_movementService = nullptr; // Characteristics - QLowEnergyCharacteristic m_infraredDataCharacteristic; - QLowEnergyCharacteristic m_infraredConfigCharacteristic; - QLowEnergyCharacteristic m_buttonCharacteristic; + QLowEnergyCharacteristic m_temperatureDataCharacteristic; + QLowEnergyCharacteristic m_temperatureConfigurationCharacteristic; + QLowEnergyCharacteristic m_temperaturePeriodCharacteristic; + QLowEnergyCharacteristic m_humidityDataCharacteristic; - QLowEnergyCharacteristic m_humidityConfigCharacteristic; + QLowEnergyCharacteristic m_humidityConfigurationCharacteristic; + QLowEnergyCharacteristic m_humidityPeriodCharacteristic; + QLowEnergyCharacteristic m_pressureDataCharacteristic; - QLowEnergyCharacteristic m_pressureConfigCharacteristic; + QLowEnergyCharacteristic m_pressureConfigurationCharacteristic; + QLowEnergyCharacteristic m_pressurePeriodCharacteristic; + QLowEnergyCharacteristic m_opticalDataCharacteristic; + QLowEnergyCharacteristic m_opticalConfigurationCharacteristic; + QLowEnergyCharacteristic m_opticalPeriodCharacteristic; - void updateInfraredValue(const QByteArray &value); - void updateButtonValue(const QByteArray &value); - void updateHumidityValue(const QByteArray &value); - void updatePressureValue(const QByteArray &value); + QLowEnergyCharacteristic m_keyDataCharacteristic; + + QLowEnergyCharacteristic m_movementDataCharacteristic; + QLowEnergyCharacteristic m_movementConfigurationCharacteristic; + QLowEnergyCharacteristic m_movementPeriodCharacteristic; + + // Measure periods + int m_temperaturePeriod = 2500; + int m_humidityPeriod = 2500; + int m_pressurePeriod = 2500; + int m_opticalPeriod = 2500; + int m_movementPeriod = 500; + + bool m_leftButtonPressed = false; + bool m_rightButtonPressed = false; + bool m_magnetDetected = false; + + // Plugin configs + bool m_accelerometerEnabled = true; + bool m_gyroscopeEnabled = false; + bool m_magnetometerEnabled = false; + + void configurePeriod(QLowEnergyService *serice, const QLowEnergyCharacteristic &characteristic, int measurementPeriod); + void configureMovement(bool gyroscopeEnabled = false, bool accelerometerEnabled = true, bool magnetometerEnabled = true, bool wakeOnMotion = true); + + 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); signals: - void leftKeyPressed(); - void rightKeyPressed(); + void leftButtonPressedChainged(bool pressed); + void rightButtonPressedChainged(bool pressed); + void magnetDetectedChainged(bool detected); private slots: void onConnectedChanged(const bool &connected); void onServiceDiscoveryFinished(); - // Infrared sensor service - void onInfraredServiceStateChanged(const QLowEnergyService::ServiceState &state); - void onInfraredServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value); - - // Button service - void onButtonServiceStateChanged(const QLowEnergyService::ServiceState &state); - void onButtonServiceCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value); + // 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); @@ -80,9 +169,17 @@ private slots: 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); -public slots: - void measure(); + // 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); }; From 3fdad3ba4d8ccf1ce7363b7670e3ed6ec0633ce6 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Fri, 23 Feb 2018 16:26:40 +0100 Subject: [PATCH 02/12] add missing include --- multisensor/sensortag.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/multisensor/sensortag.cpp b/multisensor/sensortag.cpp index 8e331e4e..2b075e6c 100644 --- a/multisensor/sensortag.cpp +++ b/multisensor/sensortag.cpp @@ -22,6 +22,7 @@ #include "sensortag.h" #include "extern-plugininfo.h" +#include "math.h" #include From 66398c3a296a71522ffa63c3da20181cf17c5c77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 23 Feb 2018 17:52:24 +0100 Subject: [PATCH 03/12] Add motion sensor parsing --- multisensor/devicepluginmultisensor.cpp | 47 +++++++++- multisensor/devicepluginmultisensor.h | 2 + multisensor/devicepluginmultisensor.json | 28 ++++-- multisensor/sensortag.cpp | 113 +++++++++++++++++++++-- multisensor/sensortag.h | 5 + 5 files changed, 176 insertions(+), 19 deletions(-) diff --git a/multisensor/devicepluginmultisensor.cpp b/multisensor/devicepluginmultisensor.cpp index e1e9aadb..df77c2da 100644 --- a/multisensor/devicepluginmultisensor.cpp +++ b/multisensor/devicepluginmultisensor.cpp @@ -59,6 +59,8 @@ DevicePluginMultiSensor::~DevicePluginMultiSensor() void DevicePluginMultiSensor::init() { + connect(this, &DevicePluginMultiSensor::configValueChanged, this, &DevicePluginMultiSensor::onPluginConfigurationChanged); + m_reconnectTimer = hardwareManager()->pluginTimerManager()->registerTimer(10); connect(m_reconnectTimer, &PluginTimer::timeout, this, &DevicePluginMultiSensor::onPluginTimer); } @@ -94,15 +96,27 @@ DeviceManager::DeviceSetupStatus DevicePluginMultiSensor::setupDevice(Device *de BluetoothLowEnergyDevice *bluetoothDevice = hardwareManager()->bluetoothLowEnergyManager()->registerDevice(deviceInfo, QLowEnergyController::PublicAddress); SensorTag *sensor = new SensorTag(device, bluetoothDevice, this); + // Preconfigure with plugin configurations + sensor->setAccelerometerEnabled(configValue(MultiSensorAccelerometerEnabledParamTypeId).toBool()); + sensor->setGyroscopeEnabled(configValue(MultiSensorGyroscopeEnabledParamTypeId).toBool()); + sensor->setMagnetometerEnabled(configValue(MultiSensorMagnetometerEnabledParamTypeId).toBool()); + sensor->setMeasurementPeriod(configValue(MultiSensorMeasurementPeriodParamTypeId).toInt()); + sensor->setMeasurementPeriodMovement(configValue(MultiSensorMeasurementPeriodMovementParamTypeId).toInt()); m_sensors.insert(device, sensor); - sensor->bluetoothDevice()->connectDevice(); return DeviceManager::DeviceSetupStatusSuccess; } return DeviceManager::DeviceSetupStatusFailure; } +void DevicePluginMultiSensor::postSetupDevice(Device *device) +{ + // Try to connect right after setup + SensorTag *sensor = m_sensors.value(device); + sensor->bluetoothDevice()->connectDevice(); +} + void DevicePluginMultiSensor::deviceRemoved(Device *device) { @@ -161,3 +175,34 @@ void DevicePluginMultiSensor::onBluetoothDiscoveryFinished() reply->deleteLater(); emit devicesDiscovered(sensortagDeviceClassId, deviceDescriptors); } + +void DevicePluginMultiSensor::onPluginConfigurationChanged(const ParamTypeId ¶mTypeId, const QVariant &value) +{ + qCDebug(dcMultiSensor()) << "Plugin configuration changed" << paramTypeId.toString() << value; + + foreach (SensorTag *sensor, m_sensors.values()) { + if (paramTypeId == MultiSensorAccelerometerEnabledParamTypeId) { + sensor->setAccelerometerEnabled(value.toBool()); + } else if (paramTypeId == MultiSensorGyroscopeEnabledParamTypeId) { + sensor->setGyroscopeEnabled(value.toBool()); + } 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); + } 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); + } + } +} diff --git a/multisensor/devicepluginmultisensor.h b/multisensor/devicepluginmultisensor.h index 22206770..91e055ca 100644 --- a/multisensor/devicepluginmultisensor.h +++ b/multisensor/devicepluginmultisensor.h @@ -46,6 +46,7 @@ public: void init() 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; private: @@ -57,6 +58,7 @@ private: private slots: void onPluginTimer(); void onBluetoothDiscoveryFinished(); + void onPluginConfigurationChanged(const ParamTypeId ¶mTypeId, const QVariant &value); }; #endif // DEVICEPLUGINMULTISENSOR_H diff --git a/multisensor/devicepluginmultisensor.json b/multisensor/devicepluginmultisensor.json index f71831a8..64f71a2d 100644 --- a/multisensor/devicepluginmultisensor.json +++ b/multisensor/devicepluginmultisensor.json @@ -24,15 +24,6 @@ "type": "bool", "defaultValue": false }, - { - "id": "5237c89c-c21d-4d78-ac99-8be661b40da7", - "name": "measurementPeriodMovement", - "displayName": "Measurement period movement sensor", - "type": "int", - "minValue": 10, - "maxValue": 2500, - "defaultValue": 2000 - }, { "id": "c5308565-5dc9-409e-ae99-577c212c7a92", "name": "measurementPeriod", @@ -40,7 +31,26 @@ "type": "int", "minValue": 10, "maxValue": 2500, + "defaultValue": 2000 + }, + { + "id": "5237c89c-c21d-4d78-ac99-8be661b40da7", + "name": "measurementPeriodMovement", + "displayName": "Measurement period movement sensor", + "type": "int", + "minValue": 10, + "maxValue": 2500, "defaultValue": 500 + }, + { + "id": "a3298d16-eea6-4474-9061-90466e92d476", + "name": "movementSensitivity", + "displayName": "Movement sensitivity", + "type": "int", + "unit": "Percentage", + "minValue": 0, + "maxValue": 100, + "defaultValue": 50 } ], "vendors": [ diff --git a/multisensor/sensortag.cpp b/multisensor/sensortag.cpp index 2b075e6c..11555462 100644 --- a/multisensor/sensortag.cpp +++ b/multisensor/sensortag.cpp @@ -24,6 +24,7 @@ #include "extern-plugininfo.h" #include "math.h" +#include #include SensorTag::SensorTag(Device *device, BluetoothLowEnergyDevice *bluetoothDevice, QObject *parent) : @@ -47,7 +48,72 @@ BluetoothLowEnergyDevice *SensorTag::bluetoothDevice() void SensorTag::setAccelerometerEnabled(bool enabled) { + qCDebug(dcMultiSensor()) << "Accelerometer" << (enabled ? "enabled" : "disabled"); + + if (m_accelerometerEnabled == enabled) + return; + m_accelerometerEnabled = enabled; + configureMovement(m_gyroscopeEnabled, m_accelerometerEnabled, m_magnetometerEnabled, true); +} + +void SensorTag::setGyroscopeEnabled(bool enabled) +{ + qCDebug(dcMultiSensor()) << "Gyroscope" << (enabled ? "enabled" : "disabled"); + + if (m_gyroscopeEnabled == enabled) + return; + + m_gyroscopeEnabled = enabled; + configureMovement(m_gyroscopeEnabled, m_accelerometerEnabled, m_magnetometerEnabled, true); +} + +void SensorTag::setMagnetometerEnabled(bool enabled) +{ + qCDebug(dcMultiSensor()) << "Magnetometer" << (enabled ? "enabled" : "disabled"); + + if (m_magnetometerEnabled == enabled) + return; + + m_magnetometerEnabled = enabled; + configureMovement(m_gyroscopeEnabled, m_accelerometerEnabled, m_magnetometerEnabled, true); +} + +void SensorTag::setMeasurementPeriod(int period) +{ + qCDebug(dcMultiSensor()) << "Set sensor measurement period to" << period << "ms"; + + 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(dcMultiSensor()) << "Set movement sensor measurement period to" << period << "ms"; + + 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(percentage) / 100.0; } void SensorTag::configurePeriod(QLowEnergyService *serice, const QLowEnergyCharacteristic &characteristic, int measurementPeriod) @@ -87,12 +153,10 @@ 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 2 Bit ( 0 = 2G, 1 = 4G, 2 = 8G, 3 = 16G) - Default 0 QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); - stream.setByteOrder(QDataStream::BigEndian); + stream.setByteOrder(QDataStream::LittleEndian); stream << configuration; qCDebug(dcMultiSensor()) << "Configure movement sensor" << data.toHex(); @@ -143,6 +207,7 @@ void SensorTag::processHumidityData(const QByteArray &data) 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; @@ -154,6 +219,13 @@ void SensorTag::processPressureData(const QByteArray &data) { Q_ASSERT(data.count() == 6); + QByteArray temperatureData(data.left(3)); + quint32 rawTemperature = static_cast(temperatureData.at(2)); + rawTemperature <<= 8; + rawTemperature |= static_cast(temperatureData.at(1)); + rawTemperature <<= 8; + rawTemperature |= static_cast(temperatureData.at(0)); + QByteArray pressureData(data.right(3)); quint32 rawPressure = static_cast(pressureData.at(2)); rawPressure <<= 8; @@ -161,6 +233,8 @@ void SensorTag::processPressureData(const QByteArray &data) rawPressure <<= 8; rawPressure |= static_cast(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)); } @@ -186,10 +260,11 @@ void SensorTag::processOpticalData(const QByteArray &data) void SensorTag::processMovementData(const QByteArray &data) { - qCDebug(dcMultiSensor()) << "Movement value" << data.toHex(); + 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; @@ -201,12 +276,33 @@ void SensorTag::processMovementData(const QByteArray &data) stream >> magXRaw >> magYRaw >> magZRaw; - // Calculate rotation, unit deg/s, range -250, +250 + // Calculate rotation [deg/s], Range +- 250 double gyroX = static_cast(gyroXRaw) / (65536 / 500); double gyroY = static_cast(gyroYRaw) / (65536 / 500); double gyroZ = static_cast(gyroZRaw) / (65536 / 500); - qCDebug(dcMultiSensor()) << "Gyroscope x:" << gyroX << " y:" << gyroY << " z:" << gyroZ; + double accX = static_cast(accXRaw) / (32768 / m_accelerometerRange); + double accY = static_cast(accYRaw) / (32768 / m_accelerometerRange); + double accZ = static_cast(accZRaw) / (32768 / m_accelerometerRange); + + // Calculate magnetism [uT], Range +- 4900 + double magX = static_cast(magXRaw); + double magY = static_cast(magYRaw); + double magZ = static_cast(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) + + qCDebug(dcMultiSensor()) << accelerometerVector.length(); } void SensorTag::setLeftButtonPressed(bool pressed) @@ -318,7 +414,6 @@ void SensorTag::onServiceDiscoveryFinished() return; } - // IR Temperature if (!m_temperatureService) { m_temperatureService = m_bluetoothDevice->controller()->createServiceObject(temperatureServiceUuid, this); @@ -731,7 +826,7 @@ void SensorTag::onMovementServiceStateChanged(const QLowEnergyService::ServiceSt // Set measurement period configurePeriod(m_movementService, m_movementPeriodCharacteristic, m_movementPeriod); - configureMovement(); + configureMovement(m_gyroscopeEnabled, m_accelerometerEnabled, m_magnetometerEnabled, true); // Enable measuring m_movementService->writeCharacteristic(m_movementConfigurationCharacteristic, QByteArray::fromHex("01")); diff --git a/multisensor/sensortag.h b/multisensor/sensortag.h index ad98702b..29c17fae 100644 --- a/multisensor/sensortag.h +++ b/multisensor/sensortag.h @@ -77,6 +77,8 @@ public: void setGyroscopeEnabled(bool enabled); void setMagnetometerEnabled(bool enabled); void setMeasurementPeriod(int period); + void setMeasurementPeriodMovement(int period); + void setMovementSensitivity(int percentage); private: Device *m_device; @@ -119,6 +121,9 @@ private: int m_pressurePeriod = 2500; int m_opticalPeriod = 2500; int m_movementPeriod = 500; + double m_movementSensitivity = 50; + // Note: possible value: 2G, 4G, 8G, 16G, default 2G + int m_accelerometerRange = 2; bool m_leftButtonPressed = false; bool m_rightButtonPressed = false; From 496db05c4c85a749ab8f6f5b4e9cd7153622fa3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 23 Feb 2018 20:53:01 +0100 Subject: [PATCH 04/12] Add sensor actions --- multisensor/devicepluginmultisensor.cpp | 39 +++-- multisensor/devicepluginmultisensor.h | 2 + multisensor/devicepluginmultisensor.json | 37 +++++ multisensor/sensortag.cpp | 189 ++++++++++++++++++++++- multisensor/sensortag.h | 40 ++++- 5 files changed, 283 insertions(+), 24 deletions(-) diff --git a/multisensor/devicepluginmultisensor.cpp b/multisensor/devicepluginmultisensor.cpp index df77c2da..e356dfd8 100644 --- a/multisensor/devicepluginmultisensor.cpp +++ b/multisensor/devicepluginmultisensor.cpp @@ -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()); } } } diff --git a/multisensor/devicepluginmultisensor.h b/multisensor/devicepluginmultisensor.h index 91e055ca..9b761764 100644 --- a/multisensor/devicepluginmultisensor.h +++ b/multisensor/devicepluginmultisensor.h @@ -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 m_sensors; diff --git a/multisensor/devicepluginmultisensor.json b/multisensor/devicepluginmultisensor.json index 64f71a2d..0acad317 100644 --- a/multisensor/devicepluginmultisensor.json +++ b/multisensor/devicepluginmultisensor.json @@ -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" } ] } diff --git a/multisensor/sensortag.cpp b/multisensor/sensortag.cpp index 11555462..0b2e75f9 100644 --- a/multisensor/sensortag.cpp +++ b/multisensor/sensortag.cpp @@ -24,6 +24,7 @@ #include "extern-plugininfo.h" #include "math.h" +#include #include #include @@ -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(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(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(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(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(gyroYRaw) / (65536 / 500); double gyroZ = static_cast(gyroZRaw) / (65536 / 500); - double accX = static_cast(accXRaw) / (32768 / m_accelerometerRange); - double accY = static_cast(accYRaw) / (32768 / m_accelerometerRange); - double accZ = static_cast(accZRaw) / (32768 / m_accelerometerRange); + double accX = static_cast(accXRaw) / (32768 / static_cast(m_accelerometerRange)); + double accY = static_cast(accYRaw) / (32768 / static_cast(m_accelerometerRange)); + double accZ = static_cast(accZRaw) / (32768 / static_cast(m_accelerometerRange)); // Calculate magnetism [uT], Range +- 4900 double magX = static_cast(magXRaw); @@ -291,7 +393,7 @@ void SensorTag::processMovementData(const QByteArray &data) double magZ = static_cast(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); +} diff --git a/multisensor/sensortag.h b/multisensor/sensortag.h index 29c17fae..b39e4fd3 100644 --- a/multisensor/sensortag.h +++ b/multisensor/sensortag.h @@ -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 From a7d11896367828100d48d7bf0325d8d94617d7ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Sat, 24 Feb 2018 10:48:38 +0100 Subject: [PATCH 05/12] Fix IO service clean up --- multisensor/sensortag.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/multisensor/sensortag.cpp b/multisensor/sensortag.cpp index 0b2e75f9..30c8784e 100644 --- a/multisensor/sensortag.cpp +++ b/multisensor/sensortag.cpp @@ -468,6 +468,7 @@ void SensorTag::onConnectedChanged(const bool &connected) m_opticalService->deleteLater(); m_keyService->deleteLater(); m_movementService->deleteLater(); + m_ioService->deleteLater(); m_temperatureService = nullptr; m_humidityService = nullptr; @@ -475,6 +476,7 @@ void SensorTag::onConnectedChanged(const bool &connected) m_opticalService = nullptr; m_keyService = nullptr; m_movementService = nullptr; + m_ioService = nullptr; } } From 7bf7ed37844e0f16450e110755a52bc79c880c39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Sat, 24 Feb 2018 12:14:46 +0100 Subject: [PATCH 06/12] Improve motion detection --- multisensor/devicepluginmultisensor.json | 3 ++ multisensor/sensortag.cpp | 53 +++++++++++++++++------- multisensor/sensortag.h | 6 ++- 3 files changed, 44 insertions(+), 18 deletions(-) diff --git a/multisensor/devicepluginmultisensor.json b/multisensor/devicepluginmultisensor.json index 0acad317..bac8875a 100644 --- a/multisensor/devicepluginmultisensor.json +++ b/multisensor/devicepluginmultisensor.json @@ -186,6 +186,7 @@ "displayNameEvent": "Green LED power changed", "displayNameAction": "Set green LED power", "type": "bool", + "cached": false, "defaultValue": false, "writable": true }, @@ -196,6 +197,7 @@ "displayNameEvent": "Red LED power changed", "displayNameAction": "Set red LED power", "type": "bool", + "cached": false, "defaultValue": false, "writable": true }, @@ -206,6 +208,7 @@ "displayNameEvent": "Buzzer power changed", "displayNameAction": "Set buzzer power", "type": "bool", + "cached": false, "defaultValue": false, "writable": true } diff --git a/multisensor/sensortag.cpp b/multisensor/sensortag.cpp index 30c8784e..53035da0 100644 --- a/multisensor/sensortag.cpp +++ b/multisensor/sensortag.cpp @@ -55,7 +55,18 @@ void SensorTag::setAccelerometerEnabled(bool enabled) return; m_accelerometerEnabled = enabled; - configureMovement(m_gyroscopeEnabled, m_accelerometerEnabled, m_magnetometerEnabled, true); + configureMovement(); +} + +void SensorTag::setAccelerometerRange(const SensorTag::SensorAccelerometerRange &range) +{ + qCDebug(dcMultiSensor()) << "Accelerometer" << range; + + if (m_accelerometerRange == range) + return; + + m_accelerometerRange = range; + configureMovement(); } void SensorTag::setGyroscopeEnabled(bool enabled) @@ -66,7 +77,7 @@ void SensorTag::setGyroscopeEnabled(bool enabled) return; m_gyroscopeEnabled = enabled; - configureMovement(m_gyroscopeEnabled, m_accelerometerEnabled, m_magnetometerEnabled, true); + configureMovement(); } void SensorTag::setMagnetometerEnabled(bool enabled) @@ -77,7 +88,7 @@ void SensorTag::setMagnetometerEnabled(bool enabled) return; m_magnetometerEnabled = enabled; - configureMovement(m_gyroscopeEnabled, m_accelerometerEnabled, m_magnetometerEnabled, true); + configureMovement(); } void SensorTag::setMeasurementPeriod(int period) @@ -171,33 +182,32 @@ void SensorTag::configurePeriod(QLowEnergyService *serice, const QLowEnergyChara serice->writeCharacteristic(characteristic, payload); } -void SensorTag::configureMovement(bool gyroscopeEnabled, bool accelerometerEnabled, bool magnetometerEnabled, bool wakeOnMotion) +void SensorTag::configureMovement() { if (!m_movementService || !m_movementConfigurationCharacteristic.isValid()) return; quint16 configuration = 0; - if (gyroscopeEnabled) { + if (m_gyroscopeEnabled) { configuration |= (1 << 0); // enable x-axis configuration |= (1 << 1); // enable y-axis configuration |= (1 << 2); // enable z-axis } - if (accelerometerEnabled) { + if (m_accelerometerEnabled) { configuration |= (1 << 3); // enable x-axis configuration |= (1 << 4); // enable y-axis configuration |= (1 << 5); // enable z-axis } - if (magnetometerEnabled) { + if (m_magnetometerEnabled) { configuration |= (1 << 6); // enable all axis } - if (wakeOnMotion) { - configuration |= (1 << 8); // enable - } + // 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) - Default 0 + // Accelerometer range 2 Bit ( 0 = 2G, 1 = 4G, 2 = 8G, 3 = 16G) switch (m_accelerometerRange) { case SensorAccelerometerRange2G: // Bit 9 = 0 @@ -362,7 +372,7 @@ void SensorTag::processOpticalData(const QByteArray &data) void SensorTag::processMovementData(const QByteArray &data) { - qCDebug(dcMultiSensor()) << "--> Movement value" << data.toHex(); + //qCDebug(dcMultiSensor()) << "--> Movement value" << data.toHex(); QByteArray payload(data); QDataStream stream(&payload, QIODevice::ReadOnly); @@ -383,6 +393,7 @@ void SensorTag::processMovementData(const QByteArray &data) double gyroY = static_cast(gyroYRaw) / (65536 / 500); double gyroZ = static_cast(gyroZRaw) / (65536 / 500); + // Calculate acceleration [G], Range +- m_accelerometerRange double accX = static_cast(accXRaw) / (32768 / static_cast(m_accelerometerRange)); double accY = static_cast(accYRaw) / (32768 / static_cast(m_accelerometerRange)); double accZ = static_cast(accZRaw) / (32768 / static_cast(m_accelerometerRange)); @@ -404,11 +415,18 @@ void SensorTag::processMovementData(const QByteArray &data) Q_UNUSED(gyroscopeVector) Q_UNUSED(magnetometerVector) - double limit = m_accelerometerRange * m_movementSensitivity; - bool motionDetected = (accelerometerVector.length() >= limit); - qCDebug(dcMultiSensor()) << accelerometerVector.length() << " | " << limit << (motionDetected ? "motion" : "-"); + // 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) @@ -477,6 +495,8 @@ void SensorTag::onConnectedChanged(const bool &connected) m_keyService = nullptr; m_movementService = nullptr; m_ioService = nullptr; + + m_lastAccelerometerVectorLenght = -99999; } } @@ -956,7 +976,7 @@ void SensorTag::onMovementServiceStateChanged(const QLowEnergyService::ServiceSt // Set measurement period configurePeriod(m_movementService, m_movementPeriodCharacteristic, m_movementPeriod); - configureMovement(m_gyroscopeEnabled, m_accelerometerEnabled, m_magnetometerEnabled, true); + configureMovement(); // Enable measuring m_movementService->writeCharacteristic(m_movementConfigurationCharacteristic, QByteArray::fromHex("01")); @@ -1002,6 +1022,7 @@ void SensorTag::onIoServiceStateChanged(const QLowEnergyService::ServiceState &s m_bluetoothDevice->disconnectDevice(); } + configureIo(); configureSensorMode(SensorModeRemote); configureIo(); } diff --git a/multisensor/sensortag.h b/multisensor/sensortag.h index b39e4fd3..eb233420 100644 --- a/multisensor/sensortag.h +++ b/multisensor/sensortag.h @@ -90,6 +90,7 @@ public: // Configurations void setAccelerometerEnabled(bool enabled); + void setAccelerometerRange(const SensorAccelerometerRange &range); void setGyroscopeEnabled(bool enabled); void setMagnetometerEnabled(bool enabled); void setMeasurementPeriod(int period); @@ -148,15 +149,16 @@ private: int m_opticalPeriod = 2500; int m_movementPeriod = 500; double m_movementSensitivity = 0.5; - // Note: possible value: 2G, 4G, 8G, 16G, default 2G 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_accelerometerEnabled = true; @@ -164,7 +166,7 @@ private: bool m_magnetometerEnabled = false; void configurePeriod(QLowEnergyService *serice, const QLowEnergyCharacteristic &characteristic, int measurementPeriod); - void configureMovement(bool gyroscopeEnabled = false, bool accelerometerEnabled = true, bool magnetometerEnabled = true, bool wakeOnMotion = true); + void configureMovement(); void configureSensorMode(const SensorMode &mode); void configureIo(); From 3c04f0057a1d140b76a904f1927d7bb44ce99c44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Sat, 24 Feb 2018 14:29:33 +0100 Subject: [PATCH 07/12] Fix magnet sensor toggle --- multisensor/sensortag.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/multisensor/sensortag.cpp b/multisensor/sensortag.cpp index 53035da0..2f8223d6 100644 --- a/multisensor/sensortag.cpp +++ b/multisensor/sensortag.cpp @@ -305,7 +305,7 @@ void SensorTag::processKeyData(const QByteArray &data) quint8 flags = static_cast(data.at(0)); setLeftButtonPressed(testBitUint8(flags, 0)); setRightButtonPressed(testBitUint8(flags, 1)); - setMagnetDetected(!testBitUint8(flags, 2)); + setMagnetDetected(testBitUint8(flags, 2)); } void SensorTag::processHumidityData(const QByteArray &data) From c6af7eb04e0b202c77de1059f547aa1f5b7bc16c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Sat, 24 Feb 2018 14:30:30 +0100 Subject: [PATCH 08/12] Update default values for plugin configuration --- multisensor/devicepluginmultisensor.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/multisensor/devicepluginmultisensor.json b/multisensor/devicepluginmultisensor.json index bac8875a..af761ba6 100644 --- a/multisensor/devicepluginmultisensor.json +++ b/multisensor/devicepluginmultisensor.json @@ -40,7 +40,7 @@ "type": "int", "minValue": 10, "maxValue": 2500, - "defaultValue": 500 + "defaultValue": 300 }, { "id": "a3298d16-eea6-4474-9061-90466e92d476", @@ -50,7 +50,7 @@ "unit": "Percentage", "minValue": 0, "maxValue": 100, - "defaultValue": 50 + "defaultValue": 40 } ], "vendors": [ From 431d56d366a5827874f604e70b97e5a742a25e5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Tue, 13 Mar 2018 14:14:39 +0100 Subject: [PATCH 09/12] Temporary commit for nymea migration --- multisensor/devicepluginmultisensor.cpp | 14 +- multisensor/devicepluginmultisensor.json | 28 +++ multisensor/multisensor.plot | 15 ++ multisensor/multisensor.pro | 8 +- multisensor/sensordataprocessor.cpp | 307 +++++++++++++++++++++++ multisensor/sensordataprocessor.h | 71 ++++++ multisensor/sensorfilter.cpp | 156 ++++++++++++ multisensor/sensorfilter.h | 60 +++++ multisensor/sensortag.cpp | 282 ++++++--------------- multisensor/sensortag.h | 49 ++-- 10 files changed, 758 insertions(+), 232 deletions(-) create mode 100644 multisensor/multisensor.plot create mode 100644 multisensor/sensordataprocessor.cpp create mode 100644 multisensor/sensordataprocessor.h create mode 100644 multisensor/sensorfilter.cpp create mode 100644 multisensor/sensorfilter.h diff --git a/multisensor/devicepluginmultisensor.cpp b/multisensor/devicepluginmultisensor.cpp index e356dfd8..0a391cde 100644 --- a/multisensor/devicepluginmultisensor.cpp +++ b/multisensor/devicepluginmultisensor.cpp @@ -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()); diff --git a/multisensor/devicepluginmultisensor.json b/multisensor/devicepluginmultisensor.json index af761ba6..1a2e3689 100644 --- a/multisensor/devicepluginmultisensor.json +++ b/multisensor/devicepluginmultisensor.json @@ -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", diff --git a/multisensor/multisensor.plot b/multisensor/multisensor.plot new file mode 100644 index 00000000..3bcf24b4 --- /dev/null +++ b/multisensor/multisensor.plot @@ -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" + diff --git a/multisensor/multisensor.pro b/multisensor/multisensor.pro index 83fe6c9b..86cba0f8 100644 --- a/multisensor/multisensor.pro +++ b/multisensor/multisensor.pro @@ -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 diff --git a/multisensor/sensordataprocessor.cpp b/multisensor/sensordataprocessor.cpp new file mode 100644 index 00000000..ca841882 --- /dev/null +++ b/multisensor/sensordataprocessor.cpp @@ -0,0 +1,307 @@ +#include "sensordataprocessor.h" +#include "extern-plugininfo.h" +#include "math.h" + +#include +#include +#include +#include + +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(value * 10); + return static_cast(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(rawObjectTemperature) / 4 * scaleFactor; + double ambientTemperature = static_cast(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(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(temperatureData.at(2)); + rawTemperature <<= 8; + rawTemperature |= static_cast(temperatureData.at(1)); + rawTemperature <<= 8; + rawTemperature |= static_cast(temperatureData.at(0)); + + QByteArray pressureData(data.right(3)); + quint32 rawPressure = static_cast(pressureData.at(2)); + rawPressure <<= 8; + rawPressure |= static_cast(pressureData.at(1)); + rawPressure <<= 8; + rawPressure |= static_cast(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(gyroXRaw) / (65536 / 500); + double gyroY = static_cast(gyroYRaw) / (65536 / 500); + double gyroZ = static_cast(gyroZRaw) / (65536 / 500); + + // Calculate acceleration [G], Range +- m_accelerometerRange + double accX = static_cast(accXRaw) / (32768 / static_cast(m_accelerometerRange)); + double accY = static_cast(accYRaw) / (32768 / static_cast(m_accelerometerRange)); + double accZ = static_cast(accZRaw) / (32768 / static_cast(m_accelerometerRange)); + + // Calculate magnetism [uT], Range +- 4900 + double magX = static_cast(magXRaw); + double magY = static_cast(magYRaw); + double magZ = static_cast(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; +} diff --git a/multisensor/sensordataprocessor.h b/multisensor/sensordataprocessor.h new file mode 100644 index 00000000..aba7fe94 --- /dev/null +++ b/multisensor/sensordataprocessor.h @@ -0,0 +1,71 @@ +#ifndef SENSORDATAPROCESSOR_H +#define SENSORDATAPROCESSOR_H + +#include +#include + +#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 diff --git a/multisensor/sensorfilter.cpp b/multisensor/sensorfilter.cpp new file mode 100644 index 00000000..2a69dd0d --- /dev/null +++ b/multisensor/sensorfilter.cpp @@ -0,0 +1,156 @@ +#include "sensorfilter.h" + +#include + +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 SensorFilter::inputData() const +{ + return m_inputData; +} + +QVector 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 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 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(); +} diff --git a/multisensor/sensorfilter.h b/multisensor/sensorfilter.h new file mode 100644 index 00000000..d137ed13 --- /dev/null +++ b/multisensor/sensorfilter.h @@ -0,0 +1,60 @@ +#ifndef SENSORFILTER_H +#define SENSORFILTER_H + +#include +#include + +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 inputData() const; + QVector 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 m_inputData; + QVector m_outputData; + + void addInputValue(double value); + + // Filter methods + double lowPassFilterValue(double value); + double highPassFilterValue(double value); + double averageFilterValue(double value); + +}; + +#endif // SENSORFILTER_H diff --git a/multisensor/sensortag.cpp b/multisensor/sensortag.cpp index 2f8223d6..2854d2c0 100644 --- a/multisensor/sensortag.cpp +++ b/multisensor/sensortag.cpp @@ -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(rawObjectTemperature) / 4 * scaleFactor; - float ambientTemperature = static_cast(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(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(temperatureData.at(2)); - rawTemperature <<= 8; - rawTemperature |= static_cast(temperatureData.at(1)); - rawTemperature <<= 8; - rawTemperature |= static_cast(temperatureData.at(0)); - - QByteArray pressureData(data.right(3)); - quint32 rawPressure = static_cast(pressureData.at(2)); - rawPressure <<= 8; - rawPressure |= static_cast(pressureData.at(1)); - rawPressure <<= 8; - rawPressure |= static_cast(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(gyroXRaw) / (65536 / 500); - double gyroY = static_cast(gyroYRaw) / (65536 / 500); - double gyroZ = static_cast(gyroZRaw) / (65536 / 500); - - // Calculate acceleration [G], Range +- m_accelerometerRange - double accX = static_cast(accXRaw) / (32768 / static_cast(m_accelerometerRange)); - double accY = static_cast(accYRaw) / (32768 / static_cast(m_accelerometerRange)); - double accZ = static_cast(accZRaw) / (32768 / static_cast(m_accelerometerRange)); - - // Calculate magnetism [uT], Range +- 4900 - double magX = static_cast(magXRaw); - double magY = static_cast(magYRaw); - double magZ = static_cast(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(value * 10); - return static_cast(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); -} diff --git a/multisensor/sensortag.h b/multisensor/sensortag.h index eb233420..57037337 100644 --- a/multisensor/sensortag.h +++ b/multisensor/sensortag.h @@ -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 From f40692adf25aec48c290ded22292382825d8975c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Tue, 13 Mar 2018 15:38:54 +0100 Subject: [PATCH 10/12] Move sensor settings to deviceclass --- multisensor/devicepluginmultisensor.cpp | 139 ++++++++++------- multisensor/devicepluginmultisensor.h | 3 +- multisensor/devicepluginmultisensor.json | 190 +++++++++++++---------- multisensor/sensordataprocessor.cpp | 18 +-- multisensor/sensortag.cpp | 8 +- 5 files changed, 203 insertions(+), 155 deletions(-) diff --git a/multisensor/devicepluginmultisensor.cpp b/multisensor/devicepluginmultisensor.cpp index 0a391cde..3a332cbf 100644 --- a/multisensor/devicepluginmultisensor.cpp +++ b/multisensor/devicepluginmultisensor.cpp @@ -59,8 +59,6 @@ DevicePluginMultiSensor::~DevicePluginMultiSensor() void DevicePluginMultiSensor::init() { - connect(this, &DevicePluginMultiSensor::configValueChanged, this, &DevicePluginMultiSensor::onPluginConfigurationChanged); - m_reconnectTimer = hardwareManager()->pluginTimerManager()->registerTimer(10); connect(m_reconnectTimer, &PluginTimer::timeout, this, &DevicePluginMultiSensor::onPluginTimer); } @@ -69,7 +67,7 @@ DeviceManager::DeviceError DevicePluginMultiSensor::discoverDevices(const Device { Q_UNUSED(params) - if (deviceClassId != sensortagDeviceClassId) + if (deviceClassId != sensorTagDeviceClassId) return DeviceManager::DeviceErrorDeviceClassNotFound; if (!hardwareManager()->bluetoothLowEnergyManager()->available()) @@ -87,26 +85,15 @@ DeviceManager::DeviceSetupStatus DevicePluginMultiSensor::setupDevice(Device *de { qCDebug(dcMultiSensor) << "Setting up Multi Sensor" << device->name() << device->params(); - if (device->deviceClassId() == sensortagDeviceClassId) { + if (device->deviceClassId() == sensorTagDeviceClassId) { - QBluetoothAddress address = QBluetoothAddress(device->paramValue(sensortagMacParamTypeId).toString()); - QString name = device->paramValue(sensortagNameParamTypeId).toString(); + QBluetoothAddress address = QBluetoothAddress(device->paramValue(sensorTagMacParamTypeId).toString()); + QString name = device->paramValue(sensorTagNameParamTypeId).toString(); QBluetoothDeviceInfo deviceInfo = QBluetoothDeviceInfo(address, name, 0); BluetoothLowEnergyDevice *bluetoothDevice = hardwareManager()->bluetoothLowEnergyManager()->registerDevice(deviceInfo, QLowEnergyController::PublicAddress); 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()); - sensor->setMeasurementPeriod(configValue(MultiSensorMeasurementPeriodParamTypeId).toInt()); - sensor->setMeasurementPeriodMovement(configValue(MultiSensorMeasurementPeriodMovementParamTypeId).toInt()); - m_sensors.insert(device, sensor); return DeviceManager::DeviceSetupStatusSuccess; @@ -118,6 +105,19 @@ void DevicePluginMultiSensor::postSetupDevice(Device *device) { // Try to connect right after setup SensorTag *sensor = m_sensors.value(device); + + // Configure sensor with state configurations + sensor->setTemperatureSensorEnabled(device->stateValue(sensorTagTemperatureSensorEnabledStateTypeId).toBool()); + sensor->setHumiditySensorEnabled(device->stateValue(sensorTagHumiditySensorEnabledStateTypeId).toBool()); + sensor->setPressureSensorEnabled(device->stateValue(sensorTagPressureSensorEnabledStateTypeId).toBool()); + sensor->setOpticalSensorEnabled(device->stateValue(sensorTagOpticalSensorEnabledStateTypeId).toBool()); + sensor->setAccelerometerEnabled(device->stateValue(sensorTagAccelerometerEnabledStateTypeId).toBool()); + sensor->setGyroscopeEnabled(device->stateValue(sensorTagGyroscopeEnabledStateTypeId).toBool()); + sensor->setMagnetometerEnabled(device->stateValue(sensorTagMagnetometerEnabledStateTypeId).toBool()); + sensor->setMeasurementPeriod(device->stateValue(sensorTagMeasurementPeriodStateTypeId).toInt()); + sensor->setMeasurementPeriodMovement(device->stateValue(sensorTagMeasurementPeriodMovementStateTypeId).toInt()); + + // Connect to the sensor sensor->bluetoothDevice()->connectDevice(); } @@ -135,18 +135,68 @@ void DevicePluginMultiSensor::deviceRemoved(Device *device) 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()); + 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()); + } 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()); + } else if (action.actionTypeId() == sensorTagRedLedActionTypeId) { + sensor->setRedLedPower(action.param(sensorTagRedLedStateParamTypeId).value().toBool()); return DeviceManager::DeviceErrorNoError; - } else if (action.actionTypeId() == sensortagBuzzerImpulseActionTypeId) { + } else if (action.actionTypeId() == sensorTagBuzzerImpulseActionTypeId) { sensor->buzzerImpulse(); return DeviceManager::DeviceErrorNoError; + } else if (action.actionTypeId() == sensorTagTemperatureSensorEnabledActionTypeId) { + bool enabled = action.param(sensorTagTemperatureSensorEnabledStateParamTypeId).value().toBool(); + device->setStateValue(sensorTagTemperatureSensorEnabledStateTypeId, enabled); + sensor->setTemperatureSensorEnabled(enabled); + return DeviceManager::DeviceErrorNoError; + } else if (action.actionTypeId() == sensorTagHumiditySensorEnabledActionTypeId) { + bool enabled = action.param(sensorTagHumiditySensorEnabledStateParamTypeId).value().toBool(); + device->setStateValue(sensorTagHumiditySensorEnabledStateTypeId, enabled); + sensor->setHumiditySensorEnabled(enabled); + return DeviceManager::DeviceErrorNoError; + } else if (action.actionTypeId() == sensorTagPressureSensorEnabledActionTypeId) { + bool enabled = action.param(sensorTagPressureSensorEnabledStateParamTypeId).value().toBool(); + device->setStateValue(sensorTagPressureSensorEnabledStateTypeId, enabled); + sensor->setPressureSensorEnabled(enabled); + return DeviceManager::DeviceErrorNoError; + } else if (action.actionTypeId() == sensorTagOpticalSensorEnabledActionTypeId) { + bool enabled = action.param(sensorTagOpticalSensorEnabledStateParamTypeId).value().toBool(); + device->setStateValue(sensorTagOpticalSensorEnabledStateTypeId, enabled); + sensor->setOpticalSensorEnabled(enabled); + return DeviceManager::DeviceErrorNoError; + } else if (action.actionTypeId() == sensorTagAccelerometerEnabledActionTypeId) { + bool enabled = action.param(sensorTagAccelerometerEnabledStateParamTypeId).value().toBool(); + device->setStateValue(sensorTagAccelerometerEnabledStateTypeId, enabled); + sensor->setAccelerometerEnabled(enabled); + return DeviceManager::DeviceErrorNoError; + } else if (action.actionTypeId() == sensorTagGyroscopeEnabledActionTypeId) { + bool enabled = action.param(sensorTagGyroscopeEnabledStateParamTypeId).value().toBool(); + device->setStateValue(sensorTagGyroscopeEnabledStateTypeId, enabled); + sensor->setGyroscopeEnabled(enabled); + return DeviceManager::DeviceErrorNoError; + } else if (action.actionTypeId() == sensorTagMagnetometerEnabledActionTypeId) { + bool enabled = action.param(sensorTagMagnetometerEnabledStateParamTypeId).value().toBool(); + device->setStateValue(sensorTagMagnetometerEnabledStateTypeId, enabled); + sensor->setMagnetometerEnabled(enabled); + return DeviceManager::DeviceErrorNoError; + } else if (action.actionTypeId() == sensorTagMeasurementPeriodActionTypeId) { + int period = action.param(sensorTagMeasurementPeriodStateParamTypeId).value().toInt(); + device->setStateValue(sensorTagMeasurementPeriodStateTypeId, period); + sensor->setMeasurementPeriod(period); + return DeviceManager::DeviceErrorNoError; + } else if (action.actionTypeId() == sensorTagMeasurementPeriodMovementActionTypeId) { + int period = action.param(sensorTagMeasurementPeriodMovementStateParamTypeId).value().toInt(); + device->setStateValue(sensorTagMeasurementPeriodMovementStateTypeId, period); + sensor->setMeasurementPeriodMovement(period); + return DeviceManager::DeviceErrorNoError; + } else if (action.actionTypeId() == sensorTagMovementSensitivityActionTypeId) { + int sensitivity = action.param(sensorTagMovementSensitivityStateParamTypeId).value().toInt(); + device->setStateValue(sensorTagMovementSensitivityStateTypeId, sensitivity); + sensor->setMovementSensitivity(sensitivity); + return DeviceManager::DeviceErrorNoError; } return DeviceManager::DeviceErrorActionTypeNotFound; @@ -155,7 +205,7 @@ DeviceManager::DeviceError DevicePluginMultiSensor::executeAction(Device *device bool DevicePluginMultiSensor::verifyExistingDevices(const QBluetoothDeviceInfo &deviceInfo) { foreach (Device *device, m_sensors.keys()) { - if (device->paramValue(sensortagMacParamTypeId).toString() == deviceInfo.address().toString()) + if (device->paramValue(sensorTagMacParamTypeId).toString() == deviceInfo.address().toString()) return true; } @@ -177,7 +227,7 @@ void DevicePluginMultiSensor::onBluetoothDiscoveryFinished() if (reply->error() != BluetoothDiscoveryReply::BluetoothDiscoveryReplyErrorNoError) { qCWarning(dcMultiSensor()) << "Bluetooth discovery error:" << reply->error(); reply->deleteLater(); - emit devicesDiscovered(sensortagDeviceClassId, QList()); + emit devicesDiscovered(sensorTagDeviceClassId, QList()); return; } @@ -185,10 +235,10 @@ void DevicePluginMultiSensor::onBluetoothDiscoveryFinished() foreach (const QBluetoothDeviceInfo &deviceInfo, reply->discoveredDevices()) { if (deviceInfo.name().contains("SensorTag")) { if (!verifyExistingDevices(deviceInfo)) { - DeviceDescriptor descriptor(sensortagDeviceClassId, "Sensor Tag", deviceInfo.address().toString()); + DeviceDescriptor descriptor(sensorTagDeviceClassId, "Sensor Tag", deviceInfo.address().toString()); ParamList params; - params.append(Param(sensortagNameParamTypeId, deviceInfo.name())); - params.append(Param(sensortagMacParamTypeId, deviceInfo.address().toString())); + params.append(Param(sensorTagNameParamTypeId, deviceInfo.name())); + params.append(Param(sensorTagMacParamTypeId, deviceInfo.address().toString())); descriptor.setParams(params); deviceDescriptors.append(descriptor); } @@ -196,34 +246,5 @@ void DevicePluginMultiSensor::onBluetoothDiscoveryFinished() } reply->deleteLater(); - emit devicesDiscovered(sensortagDeviceClassId, deviceDescriptors); -} - -void DevicePluginMultiSensor::onPluginConfigurationChanged(const ParamTypeId ¶mTypeId, const QVariant &value) -{ - qCDebug(dcMultiSensor()) << "Plugin configuration changed" << paramTypeId.toString() << value; - - foreach (SensorTag *sensor, m_sensors.values()) { - 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()); - } else if (paramTypeId == MultiSensorMagnetometerEnabledParamTypeId) { - sensor->setMagnetometerEnabled(value.toBool()); - } else if (paramTypeId == MultiSensorMeasurementPeriodParamTypeId) { - sensor->setMeasurementPeriod(value.toInt()); - } else if (paramTypeId == MultiSensorMeasurementPeriodParamTypeId) { - sensor->setMeasurementPeriodMovement(value.toInt()); - } else if (paramTypeId == MultiSensorMovementSensitivityParamTypeId) { - sensor->setMovementSensitivity(value.toInt()); - } - } + emit devicesDiscovered(sensorTagDeviceClassId, deviceDescriptors); } diff --git a/multisensor/devicepluginmultisensor.h b/multisensor/devicepluginmultisensor.h index 9b761764..16d15402 100644 --- a/multisensor/devicepluginmultisensor.h +++ b/multisensor/devicepluginmultisensor.h @@ -1,7 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright (C) 2015-2018 Simon Stuerz * - * Copyright (C) 2016 nicc * * * * This file is part of nymea. * * * @@ -60,7 +59,7 @@ private: private slots: void onPluginTimer(); void onBluetoothDiscoveryFinished(); - void onPluginConfigurationChanged(const ParamTypeId ¶mTypeId, const QVariant &value); + }; #endif // DEVICEPLUGINMULTISENSOR_H diff --git a/multisensor/devicepluginmultisensor.json b/multisensor/devicepluginmultisensor.json index 1a2e3689..34fe1eab 100644 --- a/multisensor/devicepluginmultisensor.json +++ b/multisensor/devicepluginmultisensor.json @@ -1,86 +1,7 @@ { - "displayName": "MultiSensor", + "displayName": "Multi Sensor", "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", - "displayName": "Accelerometer enabled", - "type": "bool", - "defaultValue": true - }, - { - "id": "94517544-cb97-4816-8993-cb4cf2651a1e", - "name": "gyroscopeEnabled", - "displayName": "Gyroscope enabled", - "type": "bool", - "defaultValue": false - }, - { - "id": "96aae111-b1c1-48a1-9b1f-b56efa546d0d", - "name": "magnetometerEnabled", - "displayName": "Magnetometer enabled", - "type": "bool", - "defaultValue": false - }, - { - "id": "c5308565-5dc9-409e-ae99-577c212c7a92", - "name": "measurementPeriod", - "displayName": "Measurement period for enviromental sensors", - "type": "int", - "minValue": 10, - "maxValue": 2500, - "defaultValue": 2000 - }, - { - "id": "5237c89c-c21d-4d78-ac99-8be661b40da7", - "name": "measurementPeriodMovement", - "displayName": "Measurement period movement sensor", - "type": "int", - "minValue": 10, - "maxValue": 2500, - "defaultValue": 300 - }, - { - "id": "a3298d16-eea6-4474-9061-90466e92d476", - "name": "movementSensitivity", - "displayName": "Movement sensitivity", - "type": "int", - "unit": "Percentage", - "minValue": 0, - "maxValue": 100, - "defaultValue": 40 - } - ], "vendors": [ { "id": "2edf543e-dc2c-4693-bb0c-e76c0d305fad", @@ -89,7 +10,7 @@ "deviceClasses": [ { "id": "158a06b6-b27f-4951-957e-6f1e3b44f604", - "name": "sensortag", + "name": "sensorTag", "displayName": "Sensor Tag (CC2650)", "createMethods": ["discovery"], "deviceIcon": "Thermometer", @@ -239,6 +160,113 @@ "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": [ diff --git a/multisensor/sensordataprocessor.cpp b/multisensor/sensordataprocessor.cpp index ca841882..573c9a84 100644 --- a/multisensor/sensordataprocessor.cpp +++ b/multisensor/sensordataprocessor.cpp @@ -99,12 +99,12 @@ void SensorDataProcessor::processTemperatureData(const QByteArray &data) double ambientTemperatureFiltered = m_temperatureFilter->filterValue(ambientTemperature); if (m_objectTemperatureFilter->isReady()) { - m_device->setStateValue(sensortagObjectTemperatureStateTypeId, roundValue(objectTemperatureFiltered)); + 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)); + m_device->setStateValue(sensorTagTemperatureStateTypeId, roundValue(ambientTemperatureFiltered)); } } @@ -135,7 +135,7 @@ void SensorDataProcessor::processHumidityData(const QByteArray &data) double humidityFiltered = m_humidityFilter->filterValue(humidity); if (m_humidityFilter->isReady()) { - m_device->setStateValue(sensortagHumidityStateTypeId, roundValue(humidityFiltered)); + m_device->setStateValue(sensorTagHumidityStateTypeId, roundValue(humidityFiltered)); } } @@ -163,7 +163,7 @@ void SensorDataProcessor::processPressureData(const QByteArray &data) double pressureFiltered = m_pressureFilter->filterValue(rawPressure / 100.0); if (m_pressureFilter->isReady()) { - m_device->setStateValue(sensortagPressureStateTypeId, roundValue(pressureFiltered)); + m_device->setStateValue(sensorTagPressureStateTypeId, roundValue(pressureFiltered)); } } @@ -186,7 +186,7 @@ void SensorDataProcessor::processOpticalData(const QByteArray &data) double luxFiltered = m_opticalFilter->filterValue(lux); if (m_opticalFilter->isReady()) { - m_device->setStateValue(sensortagLightIntensityStateTypeId, qRound(luxFiltered)); + m_device->setStateValue(sensorTagLightIntensityStateTypeId, qRound(luxFiltered)); } logSensorValue(lux, qRound(luxFiltered)); @@ -247,7 +247,7 @@ void SensorDataProcessor::processMovementData(const QByteArray &data) double delta = qAbs(qAbs(m_lastAccelerometerVectorLenght) - qAbs(filteredVectorLength)); bool motionDetected = (delta >= m_movementSensitivity); - m_device->setStateValue(sensortagMovingStateTypeId, motionDetected); + m_device->setStateValue(sensorTagMovingStateTypeId, motionDetected); m_lastAccelerometerVectorLenght = filteredVectorLength; } @@ -271,7 +271,7 @@ void SensorDataProcessor::setLeftButtonPressed(bool pressed) qCDebug(dcMultiSensor()) << "Left button" << (pressed ? "pressed" : "released"); m_leftButtonPressed = pressed; - m_device->setStateValue(sensortagLeftButtonPressedStateTypeId, m_leftButtonPressed); + m_device->setStateValue(sensorTagLeftButtonPressedStateTypeId, m_leftButtonPressed); } void SensorDataProcessor::setRightButtonPressed(bool pressed) @@ -281,7 +281,7 @@ void SensorDataProcessor::setRightButtonPressed(bool pressed) qCDebug(dcMultiSensor()) << "Right button" << (pressed ? "pressed" : "released"); m_rightButtonPressed = pressed; - m_device->setStateValue(sensortagRightButtonPressedStateTypeId, m_rightButtonPressed); + m_device->setStateValue(sensorTagRightButtonPressedStateTypeId, m_rightButtonPressed); } void SensorDataProcessor::setMagnetDetected(bool detected) @@ -291,7 +291,7 @@ void SensorDataProcessor::setMagnetDetected(bool detected) qCDebug(dcMultiSensor()) << "Magnet detector" << (detected ? "active" : "inactive"); m_magnetDetected = detected; - m_device->setStateValue(sensortagMagnetDetectedStateTypeId, m_magnetDetected); + m_device->setStateValue(sensorTagMagnetDetectedStateTypeId, m_magnetDetected); } void SensorDataProcessor::logSensorValue(double originalValue, double filteredValue) diff --git a/multisensor/sensortag.cpp b/multisensor/sensortag.cpp index 2854d2c0..05e77493 100644 --- a/multisensor/sensortag.cpp +++ b/multisensor/sensortag.cpp @@ -190,7 +190,7 @@ void SensorTag::setGreenLedPower(bool power) m_greenLedEnabled = power; qCDebug(dcMultiSensor()) << "Green LED" << (power ? "enabled" : "disabled"); configureIo(); - m_device->setStateValue(sensortagGreenLedStateTypeId, m_greenLedEnabled); + m_device->setStateValue(sensorTagGreenLedStateTypeId, m_greenLedEnabled); } void SensorTag::setRedLedPower(bool power) @@ -198,7 +198,7 @@ void SensorTag::setRedLedPower(bool power) m_redLedEnabled = power; qCDebug(dcMultiSensor()) << "Red LED" << (power ? "enabled" : "disabled"); configureIo(); - m_device->setStateValue(sensortagRedLedStateTypeId, m_redLedEnabled); + m_device->setStateValue(sensorTagRedLedStateTypeId, m_redLedEnabled); } void SensorTag::setBuzzerPower(bool power) @@ -206,7 +206,7 @@ void SensorTag::setBuzzerPower(bool power) m_buzzerEnabled = power; qCDebug(dcMultiSensor()) << "Buzzer" << (power ? "enabled" : "disabled"); configureIo(); - m_device->setStateValue(sensortagBuzzerStateTypeId, m_buzzerEnabled); + m_device->setStateValue(sensorTagBuzzerStateTypeId, m_buzzerEnabled); } void SensorTag::buzzerImpulse() @@ -360,7 +360,7 @@ void SensorTag::setOpticalSensorPower(bool power) void SensorTag::onConnectedChanged(const bool &connected) { qCDebug(dcMultiSensor()) << "Sensor" << m_bluetoothDevice->name() << m_bluetoothDevice->address().toString() << (connected ? "connected" : "disconnected"); - m_device->setStateValue(sensortagConnectedStateTypeId, connected); + m_device->setStateValue(sensorTagConnectedStateTypeId, connected); if (!connected) { // Clean up services From 60a037a8e37b12a774486a28e4d135aea85d6d2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Tue, 13 Mar 2018 16:35:06 +0100 Subject: [PATCH 11/12] Add copyright --- multisensor/sensordataprocessor.cpp | 22 ++++++++++++++++++++++ multisensor/sensordataprocessor.h | 22 ++++++++++++++++++++++ multisensor/sensorfilter.cpp | 22 ++++++++++++++++++++++ multisensor/sensorfilter.h | 23 ++++++++++++++++++++++- 4 files changed, 88 insertions(+), 1 deletion(-) diff --git a/multisensor/sensordataprocessor.cpp b/multisensor/sensordataprocessor.cpp index 573c9a84..414f8dd0 100644 --- a/multisensor/sensordataprocessor.cpp +++ b/multisensor/sensordataprocessor.cpp @@ -1,3 +1,25 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015-2018 Simon Stuerz * + * * + * 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 * + * . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include "sensordataprocessor.h" #include "extern-plugininfo.h" #include "math.h" diff --git a/multisensor/sensordataprocessor.h b/multisensor/sensordataprocessor.h index aba7fe94..2a923f12 100644 --- a/multisensor/sensordataprocessor.h +++ b/multisensor/sensordataprocessor.h @@ -1,3 +1,25 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015-2018 Simon Stuerz * + * * + * 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 * + * . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #ifndef SENSORDATAPROCESSOR_H #define SENSORDATAPROCESSOR_H diff --git a/multisensor/sensorfilter.cpp b/multisensor/sensorfilter.cpp index 2a69dd0d..4d036912 100644 --- a/multisensor/sensorfilter.cpp +++ b/multisensor/sensorfilter.cpp @@ -1,3 +1,25 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015-2018 Simon Stuerz * + * * + * 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 * + * . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #include "sensorfilter.h" #include diff --git a/multisensor/sensorfilter.h b/multisensor/sensorfilter.h index d137ed13..3d9dc91e 100644 --- a/multisensor/sensorfilter.h +++ b/multisensor/sensorfilter.h @@ -1,3 +1,25 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015-2018 Simon Stuerz * + * * + * 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 * + * . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + #ifndef SENSORFILTER_H #define SENSORFILTER_H @@ -54,7 +76,6 @@ private: double lowPassFilterValue(double value); double highPassFilterValue(double value); double averageFilterValue(double value); - }; #endif // SENSORFILTER_H From 38d228f9f2b68bbf910e710bca0547da6a09dd38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 14 Mar 2018 11:19:18 +0100 Subject: [PATCH 12/12] Resort interfaces list of sensortag --- multisensor/devicepluginmultisensor.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/multisensor/devicepluginmultisensor.json b/multisensor/devicepluginmultisensor.json index 34fe1eab..e387337a 100644 --- a/multisensor/devicepluginmultisensor.json +++ b/multisensor/devicepluginmultisensor.json @@ -14,7 +14,7 @@ "displayName": "Sensor Tag (CC2650)", "createMethods": ["discovery"], "deviceIcon": "Thermometer", - "interfaces": ["connectable", "humiditysensor", "temperaturesensor"], + "interfaces": ["temperaturesensor", "humiditysensor", "connectable"], "basicTags": [ "Device", "Sensor"