new file mode 100644
@@ -0,0 +1,106 @@
+import sensor from '@ohos.sensor';
+import JsDataStore from '../QtCore/JsDataStore'
+
+export default class JsSensor {
+ private pointerId = 0;
+
+ public constructor(id) {
+ this.pointerId = id;
+ }
+
+ /* Hz转ns,周期为1 */
+ private hertz2ns(rate: Number) {
+ /* f=1/T (其中f是指赫兹,T是指以秒为单位的时间)*/
+ let ns = (1 / Number(rate)) * 1000000000;
+ return ns;
+ }
+
+ /* ns转Hz,周期为1 */
+ private ns2hertz(ns: Number) {
+ /* f=1/T (其中f是指赫兹,T是指以秒为单位的时间)*/
+ let hz = 1 / (Number(ns) / 1000000000);
+ return hz;
+ }
+
+ stop(type: sensor.SensorId) {
+ try {
+ sensor.off(Number(type));
+ } catch (error) {
+ console.error(`Failed to invoke off. Code: ${error.code}, message: ${error.message}`);
+ }
+ }
+
+ /* 开始订阅传感器数据 */
+ async start(type: sensor.SensorId, rate: Number) {
+ try {
+ this.stop(type);
+ let ns = this.hertz2ns(rate);
+ let max = await this.maxSamplePeriod(type);
+ let min = await this.minSamplePeriod(type);
+ let iv = Math.max(Math.min(max, ns), min);
+
+ sensor.on(Number(type), (data) => {
+ JsDataStore.getQtNativeModule("QtSensors").DataAcception(this.pointerId, JSON.stringify(data));
+ }, { interval: iv });
+ } catch (error) {
+ console.error(`Failed to invoke on. Code: ${error.code}, message: ${error.message}`);
+ }
+ }
+
+ /* 获取指定传感器信息 */
+ async description(type: sensor.SensorId) {
+ try {
+ let info = await sensor.getSingleSensor(type);
+ let des = JSON.stringify(info);
+ console.info('Succeeded in getting sensor: ' + des);
+ return des;
+ } catch (e) {
+ console.error(`Failed to get singleSensor . Code: ${e.code}, message: ${e.message}`);
+ }
+ }
+
+ async sensorName(type: sensor.SensorId) {
+ let s = await sensor.getSingleSensor(type);
+ return s.sensorName;
+ }
+
+ async vendorName(type: sensor.SensorId) {
+ let s = await sensor.getSingleSensor(type);
+ return s.vendorName;
+ }
+
+ async firmwareVersion(type: sensor.SensorId) {
+ let s = await sensor.getSingleSensor(type);
+ return s.firmwareVersion;
+ }
+
+ async hardwareVersion(type: sensor.SensorId) {
+ let s = await sensor.getSingleSensor(type);
+ return s.hardwareVersion;
+ }
+
+ async maxRange(type: sensor.SensorId) {
+ let s = await sensor.getSingleSensor(type);
+ return s.maxRange;
+ }
+
+ async minSamplePeriod(type: sensor.SensorId) {
+ let s = await sensor.getSingleSensor(type);
+ return this.ns2hertz(s.minSamplePeriod);
+ }
+
+ async maxSamplePeriod(type: sensor.SensorId) {
+ let s = await sensor.getSingleSensor(type);
+ return this.ns2hertz(s.minSamplePeriod);
+ }
+
+ async precision(type: sensor.SensorId) {
+ let s = await sensor.getSingleSensor(type);
+ return s.precision;
+ }
+
+ async power(type: sensor.SensorId) {
+ let s = await sensor.getSingleSensor(type);
+ return s.minSamplePeriod;
+ }
+}
new file mode 100644
@@ -0,0 +1,18 @@
+import sensor from '@ohos.sensor';
+
+export default class JsSensorManager {
+
+ /* 获取所有传感器类型Id */
+ async sensorIds() {
+ let s: Array<String> = new Array();
+ try {
+ let sr = await sensor.getSensorList();
+ for (let data of sr) {
+ s.push(String(data.sensorId));
+ }
+ } catch (e) {
+ console.error(`Failed to get sensorList. Code: ${e.code}, message: ${e.message}`);
+ }
+ return s;
+ }
+}
\ No newline at end of file
new file mode 100644
@@ -0,0 +1,26 @@
+import { JsQtModule, ObjectBuilder } from '../QtCore/JsQtModule';
+import JsDataStore from '../QtCore/JsDataStore';
+import JsSensor from './JsSensor';
+import JsSensorManager from './JsSensorManager';
+
+class JsNfcModule extends JsQtModule {
+
+ public constructor() {
+ super()
+ this.moduleJsObjects.set("JsSensor", new ObjectBuilder<[number]>((id: number) =>{
+ return new JsSensor(id);
+ }));
+ this.moduleJsObjects.set("JsSensorManager", new ObjectBuilder<[]>(() =>{
+ return new JsSensorManager();
+ }));
+ this.loadQtModule();
+ }
+
+ async loadQtModule(): Promise<void> {
+ let module = await import ("libplugins_sensors_qtsensors_openharmony.so");
+ let QtSensors = module.default;
+ JsDataStore.addQtNativeModule("QtSensors", QtSensors);
+ }
+}
+
+export default new JsNfcModule;
\ No newline at end of file
new file mode 100644
@@ -0,0 +1,11 @@
+TEMPLATE = aux
+
+CONFIG -= qt
+
+templates.files += $$files($$PWD/native/QtSensors/*.ts, true)
+templates.path = $$[QT_INSTALL_PREFIX]/openharmony/qtsensors
+templates.base = $$PWD
+
+INSTALLS += templates
+
+OTHER_FILES += $$templates.files
new file mode 100644
@@ -0,0 +1,143 @@
+#include <QDebug>
+#include <QObject>
+#include <qcompass.h>
+#include <QJsonObject>
+#include <qgyroscope.h>
+#include <QJsonDocument>
+#include <QJsonParseError>
+#include <qmagnetometer.h>
+#include <qsensorplugin.h>
+#include <qsensorbackend.h>
+#include <qsensormanager.h>
+#include <qaccelerometer.h>
+#include <qrotationsensor.h>
+#include <qdistancesensor.h>
+#include <qhumiditysensor.h>
+#include <qpressuresensor.h>
+#include <qproximitysensor.h>
+#include <qorientationsensor.h>
+#include <qambientlightsensor.h>
+#include <qambienttemperaturesensor.h>
+
+#include "sensormanager.h"
+#include "sensorbackend.h"
+#include <napi/native_api.h>
+#include "openharmonylight.h"
+#include "openharmonyrotation.h"
+#include "openharmonyhumidity.h"
+#include "openharmonypressure.h"
+#include "openharmonyproximity.h"
+#include "openharmonygyroscope.h"
+#include "openharmonytemperature.h"
+#include "openharmonymagnetometer.h"
+#include "openharmonyaccelerometer.h"
+#include "QtCore/qopenharmonydefines.h"
+
+namespace {
+const char OPenHarmonyCompassId[] = "openharmony.synthetic.compass";
+}
+
+class OPenHarmonySensorPlugin : public QObject, public QSensorPluginInterface,
+ public QSensorBackendFactory
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "com.qt-project.Qt.QSensorPluginInterface/1.0" FILE "plugin.json")
+ Q_INTERFACES(QSensorPluginInterface)
+
+public:
+ void registerSensors() override
+ {
+ bool accelerometer = false;
+ bool magnetometer = false;
+ const QList<int> &ids = SensorManager::instance()->sensorIds();
+ for (int sensor : qAsConst(ids)) {
+ switch (sensor) {
+ case E_BAROMETER:
+ QSensorManager::registerBackend(QPressureSensor::type, QByteArray::number(sensor), this);
+ break;
+ case E_ACCELEROMETER:
+ m_accelerationModes |= OPenHarmonyAccelerometer::Accelerometer;
+ QSensorManager::registerBackend(QAccelerometer::type, QByteArray::number(sensor), this);
+ accelerometer = true;
+ break;
+ case E_LINEAR_ACCELEROMETER:
+ m_accelerationModes |= OPenHarmonyAccelerometer::LinearAcceleration;
+ //QSensorManager::registerBackend(QAccelerometer::type, QByteArray::number(sensor), this);
+ break;
+ case E_GRAVITY:
+ m_accelerationModes |= OPenHarmonyAccelerometer::Gravity;
+ //QSensorManager::registerBackend(QAccelerometer::type, QByteArray::number(sensor), this);
+ break;
+ case E_HUMIDITY:
+ QSensorManager::registerBackend(QHumiditySensor::type, QByteArray::number(sensor), this);
+ break;
+ case E_PROXIMITY:
+ QSensorManager::registerBackend(QProximitySensor::type, QByteArray::number(sensor), this);
+ break;
+ case E_GYROSCOPE:
+ QSensorManager::registerBackend(QGyroscope::type, QByteArray::number(sensor), this);
+ break;
+ case E_ORIENTATION:
+ /*FIXME 通过加速度传感器实现? */
+ //QSensorManager::registerBackend(QOrientationSensor::type, QByteArray::number(sensor), this);
+ break;
+ case E_ROTATION_VECTOR:
+ QSensorManager::registerBackend(QRotationSensor::type, QByteArray::number(sensor), this);
+ break;
+ case E_AMBIENT_LIGHT:
+ QSensorManager::registerBackend(QAmbientLightSensor::type, QByteArray::number(sensor), this);
+ break;
+ case E_MAGNETIC_FIELD:
+ QSensorManager::registerBackend(QMagnetometer::type, QByteArray::number(sensor), this);
+ magnetometer = true;
+ break;
+ case E_AMBIENT_TEMPERATURE:
+ QSensorManager::registerBackend(QAmbientTemperatureSensor::type, QByteArray::number(sensor), this);
+ break;
+ default:
+ break;
+ }
+ }
+#if 0
+ /* NOTE 现在的js回调机制不支持
+ * 罗盘通过加速度和磁场传感器组合实现
+ */
+ if (accelerometer && magnetometer)
+ QSensorManager::registerBackend(QCompass::type, OPenHarmonyCompassId, this);
+#endif
+ }
+
+ QSensorBackend *createBackend(QSensor *sensor) override
+ {
+ /* TODO QCompass */
+ int id = sensor->identifier().toInt();
+ switch (id) {
+ case E_BAROMETER:
+ return new OPenHarmonyPressure(id, sensor);
+ case E_ACCELEROMETER:
+ return new OPenHarmonyAccelerometer(m_accelerationModes, sensor);
+ case E_GYROSCOPE:
+ return new OPenHarmonyGyroscope(id, sensor);
+ case E_PROXIMITY:
+ return new OPenHarmonyProximity(id, sensor);
+ case E_AMBIENT_LIGHT:
+ return new OPenHarmonyLight(id, sensor);
+ case E_MAGNETIC_FIELD:
+ return new OPenHarmonyMagnetometer(id, sensor);
+ case E_HUMIDITY:
+ return new OPenHarmonyHumidity(id, sensor);
+ case E_ROTATION_VECTOR:
+ return new OPenHarmonyRotation(id, sensor);
+ case E_AMBIENT_TEMPERATURE:
+ return new OPenHarmonyTemperature(id, sensor);
+ default:
+ break;
+ }
+ return Q_NULLPTR;
+ }
+
+private:
+ int m_accelerationModes = 0;
+};
+
+#include "main.moc"
new file mode 100644
@@ -0,0 +1,38 @@
+TARGET = qtsensors_openharmony
+QT = core-private sensors
+
+LIBS += -lohsensor
+
+OTHER_FILES = plugin.json
+
+SOURCES += \
+ main.cpp \
+ openharmonyaccelerometer.cpp \
+ openharmonygyroscope.cpp \
+ openharmonyhumidity.cpp \
+ openharmonylight.cpp \
+ openharmonymagnetometer.cpp \
+ openharmonypressure.cpp \
+ openharmonyproximity.cpp \
+ openharmonyrotation.cpp \
+ openharmonytemperature.cpp \
+ sensormanager.cpp
+
+
+PLUGIN_TYPE = sensors
+PLUGIN_CLASS_NAME = OPenHarmonySensorPlugin
+load(qt_plugin)
+
+HEADERS += \
+ openharmonyaccelerometer.h \
+ openharmonygyroscope.h \
+ openharmonyhumidity.h \
+ openharmonylight.h \
+ openharmonymagnetometer.h \
+ openharmonypressure.h \
+ openharmonyproximity.h \
+ openharmonyrotation.h \
+ openharmonytemperature.h \
+ sensorbackend.h \
+ sensormanager.h
+
new file mode 100644
@@ -0,0 +1,71 @@
+#include <QDebug>
+#include <QJsonValue>
+#include <QJsonObject>
+
+#include "openharmonyaccelerometer.h"
+
+OPenHarmonyAccelerometer::OPenHarmonyAccelerometer(int accelerationModes, QSensor *sensor, QObject *parent)
+ : SensorBackend<QAccelerometerReading>(E_ACCELEROMETER, sensor, parent)
+ , m_accelerationModes(accelerationModes)
+{
+ auto accelerometer = qobject_cast<QAccelerometer *>(sensor);
+ if (accelerometer) {
+ connect(accelerometer, &QAccelerometer::accelerationModeChanged,
+ this, &OPenHarmonyAccelerometer::applyAccelerationMode);
+ applyAccelerationMode(accelerometer->accelerationMode());
+ }
+}
+
+bool OPenHarmonyAccelerometer::isFeatureSupported(QSensor::Feature feature) const
+{
+ return (feature == QSensor::AccelerationMode) ? m_accelerationModes == AllModes : SensorBackend<QAccelerometerReading>::isFeatureSupported(feature);
+}
+
+void OPenHarmonyAccelerometer::dataReceived(const QJsonObject &json)
+{
+ double x = json.value("x").toDouble();
+ double y = json.value("y").toDouble();
+ double z = json.value("z").toDouble();
+
+ if (sensor()->skipDuplicates() && qFuzzyCompare(m_reader.x(), x) &&
+ qFuzzyCompare(m_reader.y(), y) &&
+ qFuzzyCompare(m_reader.z(), z)) {
+ return;
+ }
+
+ double timestamp = json.value("timestamp").toDouble();
+ m_reader.setTimestamp(quint64(timestamp));
+ m_reader.setX(x);
+ m_reader.setY(y);
+ m_reader.setZ(z);
+
+ newReadingAvailable();
+}
+
+void OPenHarmonyAccelerometer::applyAccelerationMode(QAccelerometer::AccelerationMode accelerationMode)
+{
+ switch (accelerationMode) {
+ case QAccelerometer::Gravity:
+ if (!(m_accelerationModes & Gravity)) {
+ qWarning() << "Gravity sensor missing";
+ return;
+ }
+ setSensorType(E_GRAVITY);
+ break;
+ case QAccelerometer::User:
+ if (!(m_accelerationModes & LinearAcceleration)) {
+ qWarning() << "Linear acceleration sensor missing";
+ return;
+ }
+ setSensorType(E_LINEAR_ACCELEROMETER);
+ break;
+ case QAccelerometer::Combined:
+ if (!(m_accelerationModes & Accelerometer)) {
+ qWarning() << "Accelerometer sensor missing";
+ return;
+ }
+ setSensorType(E_ACCELEROMETER);
+ break;
+ }
+}
+
new file mode 100644
@@ -0,0 +1,32 @@
+#ifndef OPENHARMONYACCELEROMETER_H
+#define OPENHARMONYACCELEROMETER_H
+
+#include <qaccelerometer.h>
+
+#include "sensorbackend.h"
+
+class OPenHarmonyAccelerometer : public SensorBackend<QAccelerometerReading>
+{
+ Q_OBJECT
+
+public:
+ enum AccelerationModes {
+ Accelerometer = 1,
+ Gravity = 2,
+ LinearAcceleration = 4,
+ AllModes = (Accelerometer | Gravity | LinearAcceleration)
+ };
+ OPenHarmonyAccelerometer(int accelerationModes, QSensor *sensor, QObject *parent = nullptr);
+ bool isFeatureSupported(QSensor::Feature feature) const override;
+
+protected Q_SLOTS:
+ void dataReceived(const QJsonObject &json) override;
+
+private:
+ void applyAccelerationMode(QAccelerometer::AccelerationMode accelerationMode);
+
+private:
+ int m_accelerationModes;
+};
+
+#endif // OPENHARMONYACCELEROMETER_H
new file mode 100644
@@ -0,0 +1,33 @@
+#include <qmath.h>
+#include <QJsonValue>
+#include <QJsonObject>
+
+#include "openharmonygyroscope.h"
+
+OPenHarmonyGyroscope::OPenHarmonyGyroscope(int type, QSensor *sensor, QObject *parent)
+: SensorBackend<QGyroscopeReading>(type, sensor, parent)
+{
+
+}
+
+void OPenHarmonyGyroscope::dataReceived(const QJsonObject &json)
+{
+ double x = qRadiansToDegrees(json.value("x").toDouble());
+ double y = qRadiansToDegrees(json.value("y").toDouble());
+ double z = qRadiansToDegrees(json.value("z").toDouble());
+ double timestamp = json.value("timestamp").toDouble();
+
+ if (sensor()->skipDuplicates() && qFuzzyCompare(m_reader.x(), x) &&
+ qFuzzyCompare(m_reader.y(), y) &&
+ qFuzzyCompare(m_reader.z(), z)) {
+ return;
+ }
+
+ m_reader.setTimestamp(quint64(timestamp));
+ m_reader.setX(x);
+ m_reader.setY(y);
+ m_reader.setZ(z);
+
+ newReadingAvailable();
+}
+
new file mode 100644
@@ -0,0 +1,18 @@
+#ifndef OPENHARMONYGYROSCOPE_H
+#define OPENHARMONYGYROSCOPE_H
+
+#include <qgyroscope.h>
+
+#include "sensorbackend.h"
+
+class OPenHarmonyGyroscope : public SensorBackend<QGyroscopeReading>
+{
+ Q_OBJECT
+public:
+ OPenHarmonyGyroscope(int type, QSensor *sensor, QObject *parent = nullptr);
+
+protected Q_SLOTS:
+ void dataReceived(const QJsonObject &json) override;
+};
+
+#endif // OPENHARMONYGYROSCOPE_H
new file mode 100644
@@ -0,0 +1,25 @@
+#include <QJsonValue>
+#include <QJsonObject>
+
+#include "openharmonyhumidity.h"
+
+OPenHarmonyHumidity::OPenHarmonyHumidity(int type, QSensor *sensor, QObject *parent)
+ : SensorBackend<QHumidityReading>(type, sensor, parent)
+{
+
+}
+
+void OPenHarmonyHumidity::dataReceived(const QJsonObject &json)
+{
+ qreal humidity = json.value("humidity").toDouble();
+
+ if (sensor()->skipDuplicates() && qFuzzyCompare(humidity, m_reader.relativeHumidity()))
+ return;
+
+ double timestamp = json.value("timestamp").toDouble();
+ m_reader.setTimestamp(quint64(timestamp));
+ m_reader.setAbsoluteHumidity(0.f);
+ m_reader.setRelativeHumidity(humidity);
+ newReadingAvailable();
+}
+
new file mode 100644
@@ -0,0 +1,18 @@
+#ifndef OPENHARMONYHUMIDITY_H
+#define OPENHARMONYHUMIDITY_H
+
+#include <qhumiditysensor.h>
+
+#include "sensorbackend.h"
+
+class OPenHarmonyHumidity : public SensorBackend<QHumidityReading>
+{
+ Q_OBJECT
+public:
+ OPenHarmonyHumidity(int type, QSensor *sensor, QObject *parent = nullptr);
+
+protected Q_SLOTS:
+ void dataReceived(const QJsonObject &json) override;
+};
+
+#endif // OPENHARMONYHUMIDITY_H
new file mode 100644
@@ -0,0 +1,23 @@
+#include <QJsonValue>
+#include <QJsonObject>
+
+#include "openharmonylight.h"
+
+OPenHarmonyLight::OPenHarmonyLight(int type, QSensor *sensor, QObject *parent)
+ : SensorBackend<QLightReading>(type, sensor, parent)
+{
+
+}
+
+void OPenHarmonyLight::dataReceived(const QJsonObject &json)
+{
+ double intensity = json.value("intensity").toDouble();
+
+ if (sensor()->skipDuplicates() && qFuzzyCompare(m_reader.lux(), intensity))
+ return;
+
+ double timestamp = json.value("timestamp").toDouble();
+ m_reader.setTimestamp(quint64(timestamp));
+ m_reader.setLux(qreal(intensity));
+ newReadingAvailable();
+}
new file mode 100644
@@ -0,0 +1,18 @@
+#ifndef OPENHARMONYLIGHT_H
+#define OPENHARMONYLIGHT_H
+
+#include <qlightsensor.h>
+
+#include "sensorbackend.h"
+
+class OPenHarmonyLight : public SensorBackend<QLightReading>
+{
+ Q_OBJECT
+public:
+ OPenHarmonyLight(int type, QSensor *sensor, QObject *parent = nullptr);
+
+protected Q_SLOTS:
+ void dataReceived(const QJsonObject &json) override;
+};
+
+#endif // OPENHARMONYLIGHT_H
new file mode 100644
@@ -0,0 +1,32 @@
+#include <QJsonValue>
+#include <QJsonObject>
+#include "openharmonymagnetometer.h"
+
+OPenHarmonyMagnetometer::OPenHarmonyMagnetometer(int type, QSensor *sensor, QObject *parent)
+ : SensorBackend<QMagnetometerReading>(type, sensor, parent)
+{
+
+}
+
+void OPenHarmonyMagnetometer::dataReceived(const QJsonObject &json)
+{
+ double x = json.value("x").toDouble();
+ double y = json.value("y").toDouble();
+ double z = json.value("z").toDouble();
+
+ if (sensor()->skipDuplicates() && qFuzzyCompare(m_accuracy, m_reader.calibrationLevel()) &&
+ qFuzzyCompare(x, m_reader.x()) &&
+ qFuzzyCompare(y, m_reader.y()) &&
+ qFuzzyCompare(z, m_reader.z())) {
+ return;
+ }
+
+ m_reader.setCalibrationLevel(m_accuracy);
+ double timestamp = json.value("timestamp").toDouble();
+ m_reader.setTimestamp(quint64(timestamp));
+ m_reader.setX(x);
+ m_reader.setY(y);
+ m_reader.setZ(z);
+ newReadingAvailable();
+}
+
new file mode 100644
@@ -0,0 +1,18 @@
+#ifndef OPENHARMONYMAGNETOMETER_H
+#define OPENHARMONYMAGNETOMETER_H
+
+#include <qmagnetometer.h>
+
+#include "sensorbackend.h"
+
+class OPenHarmonyMagnetometer : public SensorBackend<QMagnetometerReading>
+{
+ Q_OBJECT
+public:
+ OPenHarmonyMagnetometer(int type, QSensor *sensor, QObject *parent = nullptr);
+
+protected Q_SLOTS:
+ void dataReceived(const QJsonObject &json) override;
+};
+
+#endif // OPENHARMONYMAGNETOMETER_H
new file mode 100644
@@ -0,0 +1,22 @@
+#include <QJsonObject>
+#include <QJsonValue>
+
+#include "openharmonypressure.h"
+
+OPenHarmonyPressure::OPenHarmonyPressure(int type, QSensor *sensor, QObject *parent)
+ : SensorBackend<QPressureReading>(type, sensor, parent)
+{
+
+}
+
+void OPenHarmonyPressure::dataReceived(const QJsonObject &json)
+{
+ auto pressurePa = json.value("pressure").toDouble();
+ if (sensor()->skipDuplicates() && qFuzzyCompare(pressurePa, m_reader.pressure()))
+ return;
+
+ double timestamp = json.value("timestamp").toDouble();
+ m_reader.setTimestamp(quint64(timestamp));
+ m_reader.setPressure(pressurePa);
+ newReadingAvailable();
+}
new file mode 100644
@@ -0,0 +1,18 @@
+#ifndef OPENHARMONYPRESSURE_H
+#define OPENHARMONYPRESSURE_H
+
+#include <qpressuresensor.h>
+
+#include "sensorbackend.h"
+
+class OPenHarmonyPressure : public SensorBackend<QPressureReading>
+{
+ Q_OBJECT
+public:
+ OPenHarmonyPressure(int type, QSensor *sensor, QObject *parent = nullptr);
+
+protected Q_SLOTS:
+ void dataReceived(const QJsonObject &json) override;
+};
+
+#endif // OPENHARMONYPRESSURE_H
new file mode 100644
@@ -0,0 +1,28 @@
+#include <QJsonValue>
+#include <QJsonObject>
+
+#include "openharmonyproximity.h"
+
+OPenHarmonyProximity::OPenHarmonyProximity(int type, QSensor *sensor, QObject *parent)
+ : SensorBackend<QProximityReading>(type, sensor, parent)
+{
+ m_maximumRange = m_jsSensor->maxRange(m_type);
+
+ // if we can't get the range, we arbitrarily define anything closer than 10 cm as "close"
+ if (m_maximumRange <= 0)
+ m_maximumRange = 10.0;
+}
+
+void OPenHarmonyProximity::dataReceived(const QJsonObject &json)
+{
+ qreal distance = json.value("distance").toDouble();
+ bool close = distance < m_maximumRange;
+ if (sensor()->skipDuplicates() && close == m_reader.close())
+ return;
+
+ double timestamp = json.value("timestamp").toDouble();
+ m_reader.setTimestamp(quint64(timestamp));
+ m_reader.setClose(close);
+ newReadingAvailable();
+}
+
new file mode 100644
@@ -0,0 +1,21 @@
+#ifndef OPENHARMONYPROXIMITY_H
+#define OPENHARMONYPROXIMITY_H
+
+#include <qproximitysensor.h>
+
+#include "sensorbackend.h"
+
+class OPenHarmonyProximity : public SensorBackend<QProximityReading>
+{
+ Q_OBJECT
+public:
+ OPenHarmonyProximity(int type, QSensor *sensor, QObject *parent = nullptr);
+
+protected Q_SLOTS:
+ void dataReceived(const QJsonObject &json) override;
+
+private:
+ qreal m_maximumRange;
+};
+
+#endif // OPENHARMONYPROXIMITY_H
new file mode 100644
@@ -0,0 +1,29 @@
+#include <QtMath>
+#include <QJsonValue>
+#include <QJsonObject>
+
+#include "openharmonyrotation.h"
+
+OPenHarmonyRotation::OPenHarmonyRotation(int type, QSensor *sensor, QObject *parent)
+ : SensorBackend<QRotationReading>(type, sensor, parent)
+{
+
+}
+
+void OPenHarmonyRotation::dataReceived(const QJsonObject &json)
+{
+ qreal rz = -qRadiansToDegrees(json.value("x").toDouble()); //corresponds to x
+ qreal rx = -qRadiansToDegrees(json.value("y").toDouble()); //corresponds to y
+ qreal ry = qRadiansToDegrees(json.value("z").toDouble()); //corresponds to z
+ if (sensor()->skipDuplicates() && qFuzzyCompare(m_reader.x(), rx) &&
+ qFuzzyCompare(m_reader.y(), ry) &&
+ qFuzzyCompare(m_reader.z(), rz)) {
+ return;
+ }
+
+ double timestamp = json.value("timestamp").toDouble();
+ m_reader.setTimestamp(quint64(timestamp));
+ m_reader.setFromEuler(rx, ry, rz);
+ newReadingAvailable();
+}
+
new file mode 100644
@@ -0,0 +1,18 @@
+#ifndef OPENHARMONYROTATION_H
+#define OPENHARMONYROTATION_H
+
+#include <qrotationsensor.h>
+
+#include "sensorbackend.h"
+
+class OPenHarmonyRotation : public SensorBackend<QRotationReading>
+{
+ Q_OBJECT
+public:
+ OPenHarmonyRotation(int type, QSensor *sensor, QObject *parent = nullptr);
+
+protected Q_SLOTS:
+ void dataReceived(const QJsonObject &json) override;
+};
+
+#endif // OPENHARMONYROTATION_H
new file mode 100644
@@ -0,0 +1,23 @@
+#include <QJsonValue>
+#include <QJsonObject>
+
+#include "openharmonytemperature.h"
+
+OPenHarmonyTemperature::OPenHarmonyTemperature(int type, QSensor *sensor, QObject *parent)
+ : SensorBackend<QAmbientTemperatureReading>(type, sensor, parent)
+{
+
+}
+
+void OPenHarmonyTemperature::dataReceived(const QJsonObject &json)
+{
+ qreal temperature = json.value("temperature").toDouble();
+ if (sensor()->skipDuplicates() && qFuzzyCompare(m_reader.temperature(), temperature))
+ return;
+
+ double timestamp = json.value("timestamp").toDouble();
+ m_reader.setTimestamp(quint64(timestamp));
+ m_reader.setTemperature(temperature); // in degree Celsius
+ newReadingAvailable();
+}
+
new file mode 100644
@@ -0,0 +1,18 @@
+#ifndef OPENHARMONYTEMPERATURE_H
+#define OPENHARMONYTEMPERATURE_H
+
+#include <qambienttemperaturesensor.h>
+
+#include "sensorbackend.h"
+
+class OPenHarmonyTemperature : public SensorBackend<QAmbientTemperatureReading>
+{
+ Q_OBJECT
+public:
+ OPenHarmonyTemperature(int type, QSensor *sensor, QObject *parent = nullptr);
+
+protected Q_SLOTS:
+ void dataReceived(const QJsonObject &json) override;
+};
+
+#endif // OPENHARMONYTEMPERATURE_H
new file mode 100644
@@ -0,0 +1 @@
+{ "Keys": [ "openharmony" ] }
new file mode 100644
@@ -0,0 +1,91 @@
+#ifndef SENSORBACKEND_H
+#define SENSORBACKEND_H
+
+#include <QUuid>
+#include <QSensorBackend>
+
+#include "sensormanager.h"
+
+class SensorBackendBase : public QSensorBackend
+{
+public:
+ SensorBackendBase(QSensor *sensor, QObject *parent = nullptr)
+ : QSensorBackend(sensor, parent)
+ , m_jsSensor(Q_NULLPTR)
+ {
+ QString tempUuid = QUuid::createUuid().toString();
+ tempUuid.chop(1); //remove trailing '}'
+ tempUuid.remove(0,1); //remove first '{'
+
+ m_jsSensor = SensorManager::instance()->createJsSensor(tempUuid, this);
+ }
+
+public Q_SLOTS:
+ virtual void dataReceived(const QJsonObject &json) = 0;
+
+protected:
+ QSharedPointer<JsSensor> m_jsSensor;
+};
+
+template <typename T>
+class SensorBackend : public SensorBackendBase
+{
+public:
+ explicit SensorBackend(int type, QSensor *sensor, QObject *parent = nullptr) : m_type(0)
+ , SensorBackendBase{ sensor, parent }
+ {
+ setReading<T>(&m_reader);
+ setSensorType(type);
+ m_accuracy = m_jsSensor->precision(type);
+ addDataRate(m_jsSensor->minSamplePeriod(type),
+ m_jsSensor->maxSamplePeriod(type));
+ addOutputRange(0, m_jsSensor->maxRange(type), m_accuracy);
+ }
+
+ ~SensorBackend() override
+ {
+ stop();
+ }
+
+ void setSensorType(int type)
+ {
+ m_type = type;
+ bool started = m_started;
+ if (started)
+ stop();
+
+ setDescription(m_jsSensor->description(type));
+ if (started)
+ start();
+ }
+
+ virtual void start() override
+ {
+ m_jsSensor->start(m_type, sensor()->dataRate());
+ m_started = true;
+ }
+
+ virtual void stop() override
+ {
+ m_jsSensor->stop(m_type);
+ m_started = false;
+ }
+
+ bool isFeatureSupported(QSensor::Feature feature) const override
+ {
+ switch (feature) {
+ case QSensor::SkipDuplicates:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+protected:
+ T m_reader;
+ int m_type;
+ qreal m_accuracy = 0.0f;
+ bool m_started = false;
+};
+
+#endif // SENSORBACKEND_H
new file mode 100644
@@ -0,0 +1,306 @@
+#include <QJsonDocument>
+#include <QJsonParseError>
+#include <QJsonObject>
+
+#include <sstream>
+#include <iomanip>
+#include <cctype>
+#include <cmath>
+
+#include "sensormanager.h"
+#include "sensors/oh_sensor.h"
+#include <private/qopenharmony_p.h>
+
+JsSensor::JsSensor(const QString &uuid, SensorBackendBase *backend)
+ :QJsModule("@ohos.sensor")
+ , m_uuid(uuid)
+ , m_backend(backend)
+{
+}
+
+JsSensor::~JsSensor()
+{
+ delete m_backend;
+ m_backend = nullptr;
+}
+
+
+static int hertz2ns(int rate) {
+ if (rate == 0)
+ return 0;
+ return static_cast<int>(1.0 / rate * 1000000000);
+}
+
+static qreal ns2hertz(qreal ns) {
+ if (std::fabs(ns) < 1e-10 || ns < 0)
+ return 0.0;
+ return 1e9 / ns;
+}
+
+Napi::Object JsSensor::getSingleSensor(int id) const
+{
+ return QtOh::runOnJsUIThreadWithResult([&, this](){
+ return call("getSingleSensorSync", {Napi::Number::New(env(), id)}).As<Napi::Object>();
+ });
+}
+
+qreal JsSensor::power(int id) const
+{
+ Napi::Object sensor = getSingleSensor(id);
+ return QtOh::runOnJsUIThreadWithResult([&](){
+ return sensor.Get("power").ToNumber().DoubleValue();
+ });
+}
+
+QString JsSensor::name(int id) const
+{
+ Napi::Object sensor = getSingleSensor(id);
+ return QtOh::runOnJsUIThreadWithResult([&](){
+ return QString::fromStdString(sensor.Get("sensorName").ToString());
+ });
+}
+
+qreal JsSensor::maxRange(int id) const
+{
+ Napi::Object sensor = getSingleSensor(id);
+ return QtOh::runOnJsUIThreadWithResult([&](){
+ return sensor.Get("maxRange").ToNumber().DoubleValue();
+ });
+}
+
+qreal JsSensor::precision(int id) const
+{
+ Napi::Object sensor = getSingleSensor(id);
+ return QtOh::runOnJsUIThreadWithResult([&](){
+ return sensor.Get("precision").ToNumber().DoubleValue();
+ });
+}
+
+QString JsSensor::vendorName(int id) const
+{
+ Napi::Object sensor = getSingleSensor(id);
+ return QtOh::runOnJsUIThreadWithResult([&](){
+ return QString::fromStdString(sensor.Get("vendorName").ToString());
+ });
+}
+
+QString JsSensor::description(int id) const
+{
+ Napi::Object sensor = getSingleSensor(id);
+ return QtOh::runOnJsUIThreadWithResult([&](){
+ return QString::fromStdString(sensor.Get("description").ToString());
+ });
+}
+
+qreal JsSensor::minSamplePeriod(int id) const
+{
+ Napi::Object sensor = getSingleSensor(id);
+ return QtOh::runOnJsUIThreadWithResult([&](){
+ return ns2hertz(sensor.Get("minSamplePeriod").ToNumber().DoubleValue());
+ });
+}
+
+qreal JsSensor::maxSamplePeriod(int id) const
+{
+ Napi::Object sensor = getSingleSensor(id);
+ return QtOh::runOnJsUIThreadWithResult([&](){
+ return ns2hertz(sensor.Get("maxSamplePeriod").ToNumber().DoubleValue());
+ });
+}
+
+QString JsSensor::firmwareVersion(int id) const
+{
+ Napi::Object sensor = getSingleSensor(id);
+ return QtOh::runOnJsUIThreadWithResult([&](){
+ return QString::fromStdString(sensor.Get("firmwareVersion").ToString());
+ });
+}
+
+void JsSensor::stop(int id)
+{
+ QtOh::runOnJsUIThreadNoWait([&, this](){
+ call("off", {Napi::Number::New(env(), id)});
+ });
+}
+
+static void escape_json_string(const std::string& input, std::ostringstream& output) {
+ for (char c : input) {
+ switch (c) {
+ case '"': output << "\\\""; break;
+ case '\\': output << "\\\\"; break;
+ case '/': output << "\\/"; break;
+ case '\b': output << "\\b"; break;
+ case '\f': output << "\\f"; break;
+ case '\n': output << "\\n"; break;
+ case '\r': output << "\\r"; break;
+ case '\t': output << "\\t"; break;
+ default:
+ if (static_cast<unsigned char>(c) < 0x20 || c == 0x7F) {
+ output << "\\u00"
+ << std::hex << std::setw(2) << std::setfill('0')
+ << static_cast<int>(static_cast<unsigned char>(c));
+ } else {
+ output << c;
+ }
+ }
+ }
+}
+
+static void serialize_napi_value(const Napi::Value& val, std::ostringstream& output) {
+ Napi::Env env = val.Env();
+
+ if (val.IsString()) {
+ output << '"';
+ escape_json_string(val.As<Napi::String>().Utf8Value(), output);
+ output << '"';
+ }
+ else if (val.IsNumber()) {
+ double num = val.As<Napi::Number>().DoubleValue();
+ if (num == static_cast<int64_t>(num) &&
+ (num > 9007199254740991 || num < -9007199254740991)) {
+ output << '"' << static_cast<int64_t>(num) << '"';
+ } else {
+ output << num;
+ }
+ }
+ else if (val.IsBoolean()) {
+ output << (val.As<Napi::Boolean>() ? "true" : "false");
+ }
+ else if (val.IsNull() || val.IsUndefined()) {
+ output << "null";
+ }
+ else if (val.IsArray()) {
+ Napi::Array arr = val.As<Napi::Array>();
+ output << '[';
+ for (uint32_t i = 0; i < arr.Length(); i++) {
+ if (i > 0) output << ',';
+ serialize_napi_value(arr[i], output);
+ }
+ output << ']';
+ }
+ else if (val.IsObject()) {
+ if (val.IsBuffer()) {
+ output << "\"<Buffer>";
+ output << val.As<Napi::Buffer<char>>().Length();
+ output << " bytes>\"";
+ }else {
+ Napi::Object obj = val.As<Napi::Object>();
+ output << '{';
+
+ Napi::Array keys = obj.GetPropertyNames();
+ bool first = true;
+
+ for (uint32_t i = 0; i < keys.Length(); i++) {
+ Napi::Value key = keys[i];
+ if (!key.IsString()) continue;
+
+ std::string keyStr = key.As<Napi::String>().Utf8Value();
+ Napi::Value value = obj.Get(key);
+
+ // 跳过undefined值
+ if (value.IsUndefined()) continue;
+
+ if (!first) output << ',';
+ first = false;
+
+ output << '"';
+ escape_json_string(keyStr, output);
+ output << "\":";
+ serialize_napi_value(value, output);
+ }
+ output << '}';
+ }
+ }
+ else if (val.IsFunction()) {
+ output << "\"<Function>\"";
+ }
+ else if (val.IsPromise()) {
+ output << "\"<Promise>\"";
+ }
+ else {
+ output << "\"<UnsupportedType>\"";
+ }
+}
+
+static QByteArray convertNapiObjectToQByteArray(const Napi::Object& obj) {
+ std::ostringstream jsonStream;
+ jsonStream << std::boolalpha;
+
+ serialize_napi_value(obj, jsonStream);
+
+ std::string jsonStr = jsonStream.str();
+ return QByteArray(jsonStr.c_str(), jsonStr.size());
+}
+
+void JsSensor::start(int id, int rate)
+{
+ stop(id);
+ QtOh::runOnJsUIThreadNoWait([&, this](){
+ Napi::Function callback = Napi::Function::New(env(), [this](const Napi::CallbackInfo& info) {
+ Napi::Object responseData = info[0].As<Napi::Object>();
+ QByteArray jsonData = convertNapiObjectToQByteArray(responseData);
+ if(m_backend){
+ QJsonParseError err;
+ const QJsonDocument &doc = QJsonDocument::fromJson(jsonData, &err);
+ if (QJsonParseError::NoError == err.error){
+ QMetaObject::invokeMethod((QObject *)m_backend, "dataReceived", Qt::QueuedConnection, Q_ARG(QJsonObject, doc.object()));
+ }
+ }
+ });
+ call("on", {Napi::Number::New(env(), id), callback, Napi::Number::New(env(), hertz2ns(rate))});
+ });
+}
+
+QString JsSensor::hardwareVersion(int id) const
+{
+ Napi::Object sensor = getSingleSensor(id);
+ return QString::fromStdString(sensor.Get("hardwareVersion").ToString());
+}
+
+SensorManager::SensorManager()
+{
+}
+
+QList<int> SensorManager::sensorIds() const
+{
+ QList<int> ns;
+ uint32_t count = 0;
+ int32_t ret = OH_Sensor_GetInfos(nullptr, &count);
+ if (ret != SENSOR_SUCCESS) {
+ return ns;
+ }
+ ns.reserve(count);
+
+ Sensor_Info **sensors = OH_Sensor_CreateInfos(count);
+ if (sensors == nullptr) {
+ return ns;
+ }
+ ret = OH_Sensor_GetInfos(sensors, &count);
+ if (ret != SENSOR_SUCCESS) {
+ return ns;
+ }
+
+ for (uint32_t i = 0; i < count; ++i) {
+ Sensor_Type sensorType;
+ ret = OH_SensorInfo_GetType(sensors[i], &sensorType);
+ if (ret != SENSOR_SUCCESS) {
+ return ns;
+ }
+ ns.append((int)sensorType);
+ }
+
+ OH_Sensor_DestroyInfos(sensors, count);
+ return ns;
+}
+
+QSharedPointer<SensorManager> &SensorManager::instance()
+{
+ static QSharedPointer<SensorManager> s{ new SensorManager() };
+ return s;
+}
+
+QSharedPointer<JsSensor> SensorManager::createJsSensor(const QString &uuid, SensorBackendBase *backend)
+{
+ JsSensor *s = new JsSensor(uuid, backend);
+ return QSharedPointer<JsSensor>(s);
+}
new file mode 100644
@@ -0,0 +1,68 @@
+#ifndef SENSORMANAGER_H
+#define SENSORMANAGER_H
+
+#include <QSharedPointer>
+#include <QJsModule>
+
+/* NOTE 鸿蒙和Qt传感器匹配的项
+ * Qt对前端传感器模块进行了封装
+ * 鸿蒙提供的传感器模块接口不是
+ * 完全匹配,需要转换
+ */
+enum {
+ E_GRAVITY = 257, /* 重力传感器<--->QAccelerometer */
+ E_HUMIDITY = 13, /* 湿度传感器<--->QHumiditySensor */
+ E_BAROMETER = 8, /* 气压传感器<--->QPressureSensor */
+ E_GYROSCOPE = 2, /* 陀螺仪传感器<--->QGyroscope */
+ E_PROXIMITY = 12, /* 接近光传感器<--->QDistanceSensor */
+ E_ORIENTATION = 256, /* 方向传感器<--->QOrientationSensor */
+ E_ACCELEROMETER = 1, /* 加速度传感器<--->QAccelerometer */
+ E_AMBIENT_LIGHT = 5, /* 环境光传感器<--->QAmbientLightSensor */
+ E_MAGNETIC_FIELD = 6, /* 磁场传感器<--->QMagnetometer */
+ E_ROTATION_VECTOR = 259, /* 旋转矢量传感器<--->QRotationSensor */
+ E_AMBIENT_TEMPERATURE = 260, /* 环境温度传感器<--->QAmbientTemperatureSensor */
+ E_LINEAR_ACCELEROMETER = 258, /* 线性加速度传感器<--->QAccelerometer */
+};
+
+class SensorBackendBase;
+
+class JsSensor : public QJsModule
+{
+ QString m_uuid;
+
+ friend class SensorManager;
+public:
+ JsSensor(const QString &uuid, SensorBackendBase *backend);
+ ~JsSensor();
+
+ qreal power(int id) const;
+ QString name(int id) const;
+ qreal maxRange(int id) const;
+ qreal precision(int id) const;
+ QString vendorName(int id) const;
+ QString description(int id) const;
+ qreal minSamplePeriod(int id) const;
+ qreal maxSamplePeriod(int id) const;
+ QString firmwareVersion(int id) const;
+ QString hardwareVersion(int id) const;
+
+ void stop(int id);
+ void start(int id, int rate);
+
+private:
+ Napi::Object getSingleSensor(int id) const;
+
+ SensorBackendBase *m_backend;
+};
+
+class SensorManager
+{
+ SensorManager();
+
+public:
+ QList<int> sensorIds() const;
+ static QSharedPointer<SensorManager> &instance();
+ QSharedPointer<JsSensor> createJsSensor(const QString &uuid, SensorBackendBase *backend);
+};
+
+#endif // SENSORMANAGER_H
@@ -5,6 +5,10 @@ android {
isEmpty(SENSORS_PLUGINS): SENSORS_PLUGINS = android generic
}
+openharmony {
+ isEmpty(SENSORS_PLUGINS): SENSORS_PLUGINS = openharmony generic
+}
+
qtConfig(sensorfw) {
isEmpty(SENSORS_PLUGINS): SENSORS_PLUGINS = sensorfw generic
}
@@ -39,6 +43,7 @@ isEmpty(SENSORS_PLUGINS)|contains(SENSORS_PLUGINS, simulator):qtHaveModule(simul
isEmpty(SENSORS_PLUGINS)|contains(SENSORS_PLUGINS, linux):linux:SUBDIRS += linux
isEmpty(SENSORS_PLUGINS)|contains(SENSORS_PLUGINS, iio-sensor-proxy):linux:qtHaveModule(dbus):SUBDIRS += iio-sensor-proxy
isEmpty(SENSORS_PLUGINS)|contains(SENSORS_PLUGINS, android):android:SUBDIRS += android
+isEmpty(SENSORS_PLUGINS)|contains(SENSORS_PLUGINS, openharmony):openharmony:SUBDIRS += openharmony
isEmpty(SENSORS_PLUGINS)|contains(SENSORS_PLUGINS, sensorfw):sensorfw:SUBDIRS += sensorfw
isEmpty(SENSORS_PLUGINS)|contains(SENSORS_PLUGINS, sensortag):linux:SUBDIRS += sensortag
isEmpty(SENSORS_PLUGINS)|contains(SENSORS_PLUGINS, ios):darwin:SUBDIRS += ios
@@ -53,7 +53,10 @@ QT_BEGIN_NAMESPACE
typedef QHash<QByteArray,QSensorBackendFactory*> FactoryForIdentifierMap;
typedef QHash<QByteArray,FactoryForIdentifierMap> BackendIdentifiersForTypeMap;
-static QLoggingCategory sensorsCategory("qt.sensors");
+#ifndef Q_OS_OPENHARMONY
+ static QLoggingCategory sensorsCategory("qt.sensors");
+#endif
+
class QSensorManagerPrivate : public QObject
{
@@ -101,14 +104,14 @@ public:
if (config.isEmpty()) return; // QStandardPaths is broken?
config += QLatin1String("/QtProject/Sensors.conf");
#endif
- qCDebug(sensorsCategory) << "Loading config from" << config;
+ qDebug() << "Loading config from" << config;
if (!QFile::exists(config)) {
- qCDebug(sensorsCategory) << "There is no config file" << config;
+ qDebug() << "There is no config file" << config;
return;
}
QFile cfgfile(config);
if (!cfgfile.open(QFile::ReadOnly)) {
- qCWarning(sensorsCategory) << "Can't open config file" << config;
+ qWarning() << "Can't open config file" << config;
return;
}
@@ -176,9 +179,9 @@ Q_GLOBAL_STATIC(QSensorManagerPrivate, sensorManagerPrivate)
static void initPlugin(QObject *o, bool warnOnFail = true)
{
- qCDebug(sensorsCategory) << "Init plugin" << o;
+ qDebug() << "Init plugin" << o;
if (!o) {
- qCWarning(sensorsCategory) << "Null plugin" << o;
+ qWarning() << "Null plugin" << o;
return;
}
@@ -186,7 +189,7 @@ static void initPlugin(QObject *o, bool warnOnFail = true)
if (!d) return; // hardly likely but just in case...
if (d->seenPlugins.contains(o)) {
- qCDebug(sensorsCategory) << "Plugin is seen" << o;
+ qDebug() << "Plugin is seen" << o;
return;
}
@@ -197,11 +200,11 @@ static void initPlugin(QObject *o, bool warnOnFail = true)
QSensorPluginInterface *plugin = qobject_cast<QSensorPluginInterface*>(o);
if (plugin) {
- qCDebug(sensorsCategory) << "Register sensors for " << plugin;
+ qDebug() << "Register sensors for " << plugin;
d->seenPlugins.insert(o);
plugin->registerSensors();
} else if (warnOnFail) {
- qCWarning(sensorsCategory) << "Can't cast to plugin" << o;
+ qWarning() << "Can't cast to plugin" << o;
}
}
@@ -16,3 +16,6 @@ plugins.subdir = plugins
plugins.target = sub-plugins
plugins.depends = sensors
+#SUBDIRS += openharmony
+#openharmony.subdir = openharmony
+#openharmony.target = sub-openharmony