diff --git a/README.md b/README.md
index 297c2f1..4d643d3 100644
--- a/README.md
+++ b/README.md
@@ -183,16 +183,20 @@ pio run -e smart-sensor-d1-mini-esp32 -t upload
```
-### Smart sensor with touch display
+### Smart sensor with display
+A humidity and temperature sensor with touch display. Supports
+GC9A01 240x240 round display and CST816S capacitive touch.
-- `smart-sensor-display`
- Humidity and temperature sensor with touch display. For generic *ESP32*,
- GC9A01 240x240 round display, and CST816S capacitive touch
-- `smart-sensor-display-s3`
- Like above but with 1.28" round display and integrated ESP32-S3 on board.
-
+**Generic ESP32**
+```bash
+pio run -e smart-sensor-display -t upload
+```
+**Round display with integrated ESP32-S3**
+```bash
+pio run -e smart-sensor-display-s3 -t upload
+```
### Shutter control
@@ -236,13 +240,10 @@ Just a generic playground project to mess with the library =)
pio run -e playground -t upload
```
-
-
- -`playground-c3`
- Same as above but compiling for *ESP32-C3*
-
-
-
+**Generic ESP32 C3**
+```bash
+pio run -e playground-c3 -t upload
+```
diff --git a/examples/rf-transceiver/rf-transceiver.cpp b/examples/rf-transceiver/rf-transceiver.cpp
index 8636b8b..06ee967 100644
--- a/examples/rf-transceiver/rf-transceiver.cpp
+++ b/examples/rf-transceiver/rf-transceiver.cpp
@@ -42,15 +42,12 @@ void setup() {
homeGenie = HomeGenie::getInstance();
auto miniModule = homeGenie->getDefaultModule();
-
// RCSwitch RF Transmitter
auto rcsTransmitterConfig = new RCS::RFTransmitterConfig(CONFIG_RCSwitchTransmitterPin);
auto rcsTransmitter = new RCS::RFTransmitter(rcsTransmitterConfig);
homeGenie->addAPIHandler(new RCSwitchHandler(rcsTransmitter));
// TODO: homeGenie->addIOHandler(new RCS::RFReceiver());
- // TODO: auto propRawData = new ModuleParameter(IOEventPaths::Receiver_RawData);
- // TODO: miniModule->properties.add(propRawData);
homeGenie->begin();
diff --git a/examples/smart-sensor-display/io/BatterySensor.cpp b/examples/smart-sensor-display/io/BatterySensor.cpp
new file mode 100644
index 0000000..982a11f
--- /dev/null
+++ b/examples/smart-sensor-display/io/BatterySensor.cpp
@@ -0,0 +1,53 @@
+/*
+ * HomeGenie-Mini (c) 2018-2024 G-Labs
+ *
+ *
+ * This file is part of HomeGenie-Mini (HGM).
+ *
+ * HomeGenie-Mini is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HomeGenie-Mini 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HomeGenie-Mini. If not, see .
+ *
+ *
+ * Authors:
+ * - Generoso Martello
+ *
+ */
+
+#include "BatterySensor.h"
+
+namespace IO { namespace Env {
+
+ void BatterySensor::begin() {
+ pinMode(sensorPin, INPUT);
+ }
+ void BatterySensor::loop() {
+ float gpioMax = 4096;
+ float gpioV = 3.3f;
+ float batteryVMax = 3.7f;
+ const float conversionFactor = gpioV / gpioMax * 3.0f;
+ float adv = analogReadMilliVolts(sensorPin);
+ float v = adv * conversionFactor; //adv * (gpioV / gpioMax) * batteryV;
+ float batteryLevel = v / batteryVMax * 100;
+ if (lastBatteryLevel != batteryLevel) {
+ Logger::info("@%s [%s %.2f]", BATTERY_SENSOR_NS_PREFIX, (IOEventPaths::Status_Battery), batteryLevel);
+ sendEvent((const uint8_t*)(IOEventPaths::Status_Battery), (float*)&batteryLevel, IOEventDataType::Float);
+ lastBatteryLevel = batteryLevel;
+ }
+
+ if (batteryLevel > 100) {
+ // Charging
+ Service::PowerManager::setActive();
+ }
+ }
+
+}}
diff --git a/examples/smart-sensor-display/io/BatterySensor.h b/examples/smart-sensor-display/io/BatterySensor.h
new file mode 100644
index 0000000..018c33d
--- /dev/null
+++ b/examples/smart-sensor-display/io/BatterySensor.h
@@ -0,0 +1,57 @@
+/*
+ * HomeGenie-Mini (c) 2018-2024 G-Labs
+ *
+ *
+ * This file is part of HomeGenie-Mini (HGM).
+ *
+ * HomeGenie-Mini is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HomeGenie-Mini 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HomeGenie-Mini. If not, see .
+ *
+ *
+ * Authors:
+ * - Generoso Martello
+ *
+ */
+
+#ifndef HOMEGENIE_MINI_BATTERYSENSOR_H
+#define HOMEGENIE_MINI_BATTERYSENSOR_H
+
+#include
+
+#include "../configuration.h"
+
+#define BATTERY_SENSOR_NS_PREFIX "IO::Env::BatterySensor"
+
+namespace IO { namespace Env {
+
+ class BatterySensor: Task, public IIOEventSender {
+ public:
+ BatterySensor(uint8_t analogPin) {
+ setLoopInterval(5000); // update every 15 seconds
+ sensorPin = analogPin;
+ }
+ void setModule(Module* m) override {
+ IIOEventSender::setModule(m);
+ auto statusBattery = new ModuleParameter(IOEventPaths::Status_Battery);
+ m->properties.add(statusBattery);
+ }
+ void begin() override;
+ void loop() override;
+ private:
+ uint8_t sensorPin;
+ float lastBatteryLevel = 0;
+ };
+
+}}
+
+#endif //HOMEGENIE_MINI_BATTERYSENSOR_H
diff --git a/examples/smart-sensor-display/io/DHTxx.cpp b/examples/smart-sensor-display/io/DHTxx.cpp
index 3365b30..951fbf1 100644
--- a/examples/smart-sensor-display/io/DHTxx.cpp
+++ b/examples/smart-sensor-display/io/DHTxx.cpp
@@ -45,26 +45,31 @@ namespace IO { namespace Env {
// signal value changes
if (currentData.temperature != t) {
Logger::info("@%s [%s %0.2f]", DHTXX_NS_PREFIX, (IOEventPaths::Sensor_Temperature), currentData.temperature);
- sendEvent(domain.c_str(), address.c_str(), (const uint8_t*)(IOEventPaths::Sensor_Temperature), (float_t *)¤tData.temperature, SensorTemperature);
+ sendEvent((const uint8_t*)(IOEventPaths::Sensor_Temperature), (float_t *)¤tData.temperature, SensorTemperature);
}
if (currentData.humidity != h) {
Logger::info("@%s [%s %0.2f]", DHTXX_NS_PREFIX, (IOEventPaths::Sensor_Humidity), currentData.humidity);
- sendEvent(domain.c_str(), address.c_str(), (const uint8_t*)(IOEventPaths::Sensor_Humidity), (float_t *)¤tData.humidity, SensorHumidity);
+ sendEvent((const uint8_t*)(IOEventPaths::Sensor_Humidity), (float_t *)¤tData.humidity, SensorHumidity);
}
Logger::verbose(" > %s::loop() << END", DHTXX_NS_PREFIX);
+ setLoopInterval(SENSOR_SAMPLING_RATE);
}
/// Read temperature and humidity values from one DHTxx.
void DHTxx::readSensorData() {
- dht->read();
- float h = dht->getHumidity();
- float t = dht->getTemperature();
- if (h != DHT_READ_ERROR && t != DHT_READ_ERROR) {
- currentData.temperature = t;
- currentData.humidity = h;
- } else {
+ uint8_t attempts = 5;
+ while (attempts > 0) {
+ dht->read();
+ float h = dht->getHumidity();
+ float t = dht->getTemperature();
+ if (h != DHT_READ_ERROR && t != DHT_READ_ERROR) {
+ currentData.temperature = t;
+ currentData.humidity = h;
+ break;
+ }
// TODO: report error reading sensor data
+ attempts--;
}
}
diff --git a/examples/smart-sensor-display/io/DHTxx.h b/examples/smart-sensor-display/io/DHTxx.h
index 3f7a9dc..8e1aa54 100644
--- a/examples/smart-sensor-display/io/DHTxx.h
+++ b/examples/smart-sensor-display/io/DHTxx.h
@@ -57,15 +57,20 @@ namespace IO { namespace Env {
class DHTxx : Task, public IIOEventSender {
public:
DHTxx(uint8_t dhtType) {
- setLoopInterval(SENSOR_SAMPLING_RATE);
+ setLoopInterval(2000); // initial reading delay
dht = new DHTNEW(inputPin);
dht->setType(dhtType);
}
+ void setModule(Module* m) override {
+ IIOEventSender::setModule(m);
+ auto temperature = new ModuleParameter(IOEventPaths::Sensor_Temperature);
+ m->properties.add(temperature);
+ auto humidity = new ModuleParameter(IOEventPaths::Sensor_Humidity);
+ m->properties.add(humidity);
+ }
void begin() override;
void loop() override;
private:
- String domain = IOEventDomains::HomeAutomation_HomeGenie;
- String address = CONFIG_BUILTIN_MODULE_ADDRESS;
// Set DHTxx pin number
uint8_t inputPin = CONFIG_DHTxx_DataPin;
// Temperature and humidity sensor
diff --git a/examples/smart-sensor-display/io/LightSensor.cpp b/examples/smart-sensor-display/io/LightSensor.cpp
index 052c949..2845b35 100644
--- a/examples/smart-sensor-display/io/LightSensor.cpp
+++ b/examples/smart-sensor-display/io/LightSensor.cpp
@@ -41,7 +41,7 @@ namespace IO { namespace Env {
if (lightLevel != currentLevel) {
currentLevel = lightLevel;
Logger::info("@%s [%s %d]", LIGHTSENSOR_NS_PREFIX, (IOEventPaths::Sensor_Luminance), currentLevel);
- sendEvent(domain.c_str(), address.c_str(), (const uint8_t*)(IOEventPaths::Sensor_Luminance), (uint16_t *)¤tLevel, SensorLight);
+ sendEvent((const uint8_t*)(IOEventPaths::Sensor_Luminance), (uint16_t *)¤tLevel, SensorLight);
}
}
diff --git a/examples/smart-sensor-display/io/LightSensor.h b/examples/smart-sensor-display/io/LightSensor.h
index c9de39d..e9a7d8e 100644
--- a/examples/smart-sensor-display/io/LightSensor.h
+++ b/examples/smart-sensor-display/io/LightSensor.h
@@ -46,13 +46,17 @@ namespace IO { namespace Env {
LightSensor() {
setLoopInterval(LIGHTSENSOR_SAMPLING_RATE);
}
+ void setModule(Module* m) override {
+ IIOEventSender::setModule(m);
+ auto luminance = new ModuleParameter(IOEventPaths::Sensor_Luminance);
+ m->properties.add(luminance);
+ }
+
void begin() override;
void loop() override;
void setInputPin(uint8_t number);
uint16_t getLightLevel();
private:
- String domain = IOEventDomains::HomeAutomation_HomeGenie;
- String address = CONFIG_BUILTIN_MODULE_ADDRESS;
uint8_t inputPin = CONFIG_LightSensorPin; // Analogic input pin A0 (0)
uint16_t currentLevel = 0;
};
diff --git a/examples/smart-sensor-display/io/MotionSensor.cpp b/examples/smart-sensor-display/io/MotionSensor.cpp
new file mode 100644
index 0000000..072dc43
--- /dev/null
+++ b/examples/smart-sensor-display/io/MotionSensor.cpp
@@ -0,0 +1,30 @@
+//
+// Created by gene on 19/02/24.
+//
+
+#include "MotionSensor.h"
+
+namespace IO { namespace Env {
+ void MotionSensor::begin() {
+ pinMode(sensorPin, INPUT_PULLUP);
+ Logger::info("| ✔ %s (PIN=%d)", MOTION_SENSOR_NS_PREFIX, sensorPin);
+ }
+ void MotionSensor::loop() {
+ int motionValue = digitalRead(sensorPin);
+ if (motionValue == HIGH && !motionDetected) {
+ // MOTION DETECTED
+ motionDetected = true;
+ Logger::info("@%s [%s %d]", MOTION_SENSOR_NS_PREFIX, (IOEventPaths::Sensor_MotionDetect), motionValue);
+ sendEvent((const uint8_t*)(IOEventPaths::Sensor_MotionDetect), (int*)&motionValue, IOEventDataType::Number);
+ PowerManager::setActive();
+ } else if (motionValue == LOW && motionDetected) {
+ // MOTION CLEAR
+ motionDetected = false;
+ Logger::info("@%s [%s %d]", MOTION_SENSOR_NS_PREFIX, (IOEventPaths::Sensor_MotionDetect), motionValue);
+ sendEvent((const uint8_t*)(IOEventPaths::Sensor_MotionDetect), (int*)&motionValue, IOEventDataType::Number);
+ } else if (motionDetected) {
+ // MOTION ACTIVE
+ PowerManager::setActive();
+ }
+ }
+}} // Env
diff --git a/examples/smart-sensor-display/io/MotionSensor.h b/examples/smart-sensor-display/io/MotionSensor.h
new file mode 100644
index 0000000..23d7197
--- /dev/null
+++ b/examples/smart-sensor-display/io/MotionSensor.h
@@ -0,0 +1,39 @@
+//
+// Created by gene on 19/02/24.
+//
+
+#ifndef HOMEGENIE_MINI_MOTIONSENSOR_H
+#define HOMEGENIE_MINI_MOTIONSENSOR_H
+
+#include
+
+#include "../configuration.h"
+
+#define MOTION_SENSOR_NS_PREFIX "IO::Env::MotionSensor"
+
+namespace IO { namespace Env {
+
+ using namespace Service;
+
+ class MotionSensor : Task, public IIOEventSender {
+ public:
+ MotionSensor(uint8_t pin) {
+ setLoopInterval(200);
+ sensorPin = pin;
+ }
+ void setModule(Module* m) override {
+ IIOEventSender::setModule(m);
+ auto motionDetect = new ModuleParameter(IOEventPaths::Sensor_MotionDetect);
+ m->properties.add(motionDetect);
+ }
+ void begin() override;
+ void loop() override;
+
+ private:
+ uint8_t sensorPin = 0;
+ bool motionDetected = false;
+ };
+
+}} // Env
+
+#endif //HOMEGENIE_MINI_MOTIONSENSOR_H
diff --git a/examples/smart-sensor-display/io/QMI8658.cpp b/examples/smart-sensor-display/io/QMI8658.cpp
new file mode 100644
index 0000000..7e4fdcf
--- /dev/null
+++ b/examples/smart-sensor-display/io/QMI8658.cpp
@@ -0,0 +1,647 @@
+
+#include "QMI8658.h"
+
+#define QMI8658_SLAVE_ADDR_L 0x6a
+#define QMI8658_SLAVE_ADDR_H 0x6b
+#define QMI8658_printf printf
+
+#define QMI8658_UINT_MG_DPS
+
+enum
+{
+ AXIS_X = 0,
+ AXIS_Y = 1,
+ AXIS_Z = 2,
+
+ AXIS_TOTAL
+};
+
+typedef struct
+{
+ short sign[AXIS_TOTAL];
+ unsigned short map[AXIS_TOTAL];
+} qst_imu_layout;
+
+static unsigned short acc_lsb_div = 0;
+static unsigned short gyro_lsb_div = 0;
+static unsigned short ae_q_lsb_div = (1 << 14);
+static unsigned short ae_v_lsb_div = (1 << 10);
+static unsigned int imu_timestamp = 0;
+static struct QMI8658Config QMI8658_config;
+static unsigned char QMI8658_slave_addr = QMI8658_SLAVE_ADDR_L;
+
+void DEV_I2C_Write_Byte(uint8_t addr, uint8_t reg, uint8_t Value)
+{
+ Wire.beginTransmission(addr);
+ Wire.write(reg);
+ Wire.write(Value);
+ Wire.endTransmission();
+}
+
+void DEV_I2C_Read_nByte(uint8_t addr, uint8_t reg, uint8_t *pData, uint32_t Len)
+{
+ Wire.beginTransmission(addr);
+ Wire.write(reg);
+ Wire.endTransmission();
+
+ Wire.requestFrom(addr, Len);
+
+ uint8_t i = 0;
+ for(i = 0; i < Len; i++) {
+ pData[i] = Wire.read();
+ }
+ Wire.endTransmission();
+}
+
+unsigned char QMI8658_write_reg(unsigned char reg, unsigned char value)
+{
+ unsigned char ret = 0;
+ unsigned int retry = 0;
+
+ while ((!ret) && (retry++ < 5))
+ {
+ DEV_I2C_Write_Byte(QMI8658_slave_addr, reg, value);
+ }
+ return ret;
+}
+
+unsigned char QMI8658_write_regs(unsigned char reg, unsigned char *value, unsigned char len)
+{
+ int i, ret;
+
+ for (i = 0; i < len; i++)
+ {
+ ret = QMI8658_write_reg(reg + i, value[i]);
+ }
+
+ return ret;
+}
+
+unsigned char QMI8658_read_reg(unsigned char reg, unsigned char *buf, unsigned short len)
+{
+ unsigned char ret = 0;
+ unsigned int retry = 0;
+ DEV_I2C_Read_nByte(QMI8658_slave_addr, reg, buf, len);
+
+ return ret;
+}
+
+#if 0
+static qst_imu_layout imu_map;
+
+void QMI8658_set_layout(short layout)
+{
+ if(layout == 0)
+ {
+ imu_map.sign[AXIS_X] = 1;
+ imu_map.sign[AXIS_Y] = 1;
+ imu_map.sign[AXIS_Z] = 1;
+ imu_map.map[AXIS_X] = AXIS_X;
+ imu_map.map[AXIS_Y] = AXIS_Y;
+ imu_map.map[AXIS_Z] = AXIS_Z;
+ }
+ else if(layout == 1)
+ {
+ imu_map.sign[AXIS_X] = -1;
+ imu_map.sign[AXIS_Y] = 1;
+ imu_map.sign[AXIS_Z] = 1;
+ imu_map.map[AXIS_X] = AXIS_Y;
+ imu_map.map[AXIS_Y] = AXIS_X;
+ imu_map.map[AXIS_Z] = AXIS_Z;
+ }
+ else if(layout == 2)
+ {
+ imu_map.sign[AXIS_X] = -1;
+ imu_map.sign[AXIS_Y] = -1;
+ imu_map.sign[AXIS_Z] = 1;
+ imu_map.map[AXIS_X] = AXIS_X;
+ imu_map.map[AXIS_Y] = AXIS_Y;
+ imu_map.map[AXIS_Z] = AXIS_Z;
+ }
+ else if(layout == 3)
+ {
+ imu_map.sign[AXIS_X] = 1;
+ imu_map.sign[AXIS_Y] = -1;
+ imu_map.sign[AXIS_Z] = 1;
+ imu_map.map[AXIS_X] = AXIS_Y;
+ imu_map.map[AXIS_Y] = AXIS_X;
+ imu_map.map[AXIS_Z] = AXIS_Z;
+ }
+ else if(layout == 4)
+ {
+ imu_map.sign[AXIS_X] = -1;
+ imu_map.sign[AXIS_Y] = 1;
+ imu_map.sign[AXIS_Z] = -1;
+ imu_map.map[AXIS_X] = AXIS_X;
+ imu_map.map[AXIS_Y] = AXIS_Y;
+ imu_map.map[AXIS_Z] = AXIS_Z;
+ }
+ else if(layout == 5)
+ {
+ imu_map.sign[AXIS_X] = 1;
+ imu_map.sign[AXIS_Y] = 1;
+ imu_map.sign[AXIS_Z] = -1;
+ imu_map.map[AXIS_X] = AXIS_Y;
+ imu_map.map[AXIS_Y] = AXIS_X;
+ imu_map.map[AXIS_Z] = AXIS_Z;
+ }
+ else if(layout == 6)
+ {
+ imu_map.sign[AXIS_X] = 1;
+ imu_map.sign[AXIS_Y] = -1;
+ imu_map.sign[AXIS_Z] = -1;
+ imu_map.map[AXIS_X] = AXIS_X;
+ imu_map.map[AXIS_Y] = AXIS_Y;
+ imu_map.map[AXIS_Z] = AXIS_Z;
+ }
+ else if(layout == 7)
+ {
+ imu_map.sign[AXIS_X] = -1;
+ imu_map.sign[AXIS_Y] = -1;
+ imu_map.sign[AXIS_Z] = -1;
+ imu_map.map[AXIS_X] = AXIS_Y;
+ imu_map.map[AXIS_Y] = AXIS_X;
+ imu_map.map[AXIS_Z] = AXIS_Z;
+ }
+ else
+ {
+ imu_map.sign[AXIS_X] = 1;
+ imu_map.sign[AXIS_Y] = 1;
+ imu_map.sign[AXIS_Z] = 1;
+ imu_map.map[AXIS_X] = AXIS_X;
+ imu_map.map[AXIS_Y] = AXIS_Y;
+ imu_map.map[AXIS_Z] = AXIS_Z;
+ }
+}
+#endif
+
+void QMI8658_config_acc(enum QMI8658_AccRange range, enum QMI8658_AccOdr odr, enum QMI8658_LpfConfig lpfEnable, enum QMI8658_StConfig stEnable)
+{
+ unsigned char ctl_dada;
+
+ switch (range)
+ {
+ case QMI8658AccRange_2g:
+ acc_lsb_div = (1 << 14);
+ break;
+ case QMI8658AccRange_4g:
+ acc_lsb_div = (1 << 13);
+ break;
+ case QMI8658AccRange_8g:
+ acc_lsb_div = (1 << 12);
+ break;
+ case QMI8658AccRange_16g:
+ acc_lsb_div = (1 << 11);
+ break;
+ default:
+ range = QMI8658AccRange_8g;
+ acc_lsb_div = (1 << 12);
+ }
+ if (stEnable == QMI8658St_Enable)
+ ctl_dada = (unsigned char)range | (unsigned char)odr | 0x80;
+ else
+ ctl_dada = (unsigned char)range | (unsigned char)odr;
+
+ QMI8658_write_reg(QMI8658Register_Ctrl2, ctl_dada);
+ // set LPF & HPF
+ QMI8658_read_reg(QMI8658Register_Ctrl5, &ctl_dada, 1);
+ ctl_dada &= 0xf0;
+ if (lpfEnable == QMI8658Lpf_Enable)
+ {
+ ctl_dada |= A_LSP_MODE_3;
+ ctl_dada |= 0x01;
+ }
+ else
+ {
+ ctl_dada &= ~0x01;
+ }
+ ctl_dada = 0x00;
+ QMI8658_write_reg(QMI8658Register_Ctrl5, ctl_dada);
+ // set LPF & HPF
+}
+
+void QMI8658_config_gyro(enum QMI8658_GyrRange range, enum QMI8658_GyrOdr odr, enum QMI8658_LpfConfig lpfEnable, enum QMI8658_StConfig stEnable)
+{
+ // Set the CTRL3 register to configure dynamic range and ODR
+ unsigned char ctl_dada;
+
+ // Store the scale factor for use when processing raw data
+ switch (range)
+ {
+ case QMI8658GyrRange_32dps:
+ gyro_lsb_div = 1024;
+ break;
+ case QMI8658GyrRange_64dps:
+ gyro_lsb_div = 512;
+ break;
+ case QMI8658GyrRange_128dps:
+ gyro_lsb_div = 256;
+ break;
+ case QMI8658GyrRange_256dps:
+ gyro_lsb_div = 128;
+ break;
+ case QMI8658GyrRange_512dps:
+ gyro_lsb_div = 64;
+ break;
+ case QMI8658GyrRange_1024dps:
+ gyro_lsb_div = 32;
+ break;
+ case QMI8658GyrRange_2048dps:
+ gyro_lsb_div = 16;
+ break;
+ case QMI8658GyrRange_4096dps:
+ gyro_lsb_div = 8;
+ break;
+ default:
+ range = QMI8658GyrRange_512dps;
+ gyro_lsb_div = 64;
+ break;
+ }
+
+ if (stEnable == QMI8658St_Enable)
+ ctl_dada = (unsigned char)range | (unsigned char)odr | 0x80;
+ else
+ ctl_dada = (unsigned char)range | (unsigned char)odr;
+ QMI8658_write_reg(QMI8658Register_Ctrl3, ctl_dada);
+
+ // Conversion from degrees/s to rad/s if necessary
+ // set LPF & HPF
+ QMI8658_read_reg(QMI8658Register_Ctrl5, &ctl_dada, 1);
+ ctl_dada &= 0x0f;
+ if (lpfEnable == QMI8658Lpf_Enable)
+ {
+ ctl_dada |= G_LSP_MODE_3;
+ ctl_dada |= 0x10;
+ }
+ else
+ {
+ ctl_dada &= ~0x10;
+ }
+ ctl_dada = 0x00;
+ QMI8658_write_reg(QMI8658Register_Ctrl5, ctl_dada);
+ // set LPF & HPF
+}
+
+void QMI8658_config_mag(enum QMI8658_MagDev device, enum QMI8658_MagOdr odr)
+{
+ QMI8658_write_reg(QMI8658Register_Ctrl4, device | odr);
+}
+
+void QMI8658_config_ae(enum QMI8658_AeOdr odr)
+{
+ // QMI8658_config_acc(QMI8658AccRange_8g, AccOdr_1000Hz, Lpf_Enable, St_Enable);
+ // QMI8658_config_gyro(QMI8658GyrRange_2048dps, GyrOdr_1000Hz, Lpf_Enable, St_Enable);
+ QMI8658_config_acc(QMI8658_config.accRange, QMI8658_config.accOdr, QMI8658Lpf_Enable, QMI8658St_Disable);
+ QMI8658_config_gyro(QMI8658_config.gyrRange, QMI8658_config.gyrOdr, QMI8658Lpf_Enable, QMI8658St_Disable);
+ QMI8658_config_mag(QMI8658_config.magDev, QMI8658_config.magOdr);
+ QMI8658_write_reg(QMI8658Register_Ctrl6, odr);
+}
+
+unsigned char QMI8658_readStatus0(void)
+{
+ unsigned char status[2];
+
+ QMI8658_read_reg(QMI8658Register_Status0, status, sizeof(status));
+ // printf("status[0x%x 0x%x]\n",status[0],status[1]);
+
+ return status[0];
+}
+/*!
+ * \brief Blocking read of data status register 1 (::QMI8658Register_Status1).
+ * \returns Status byte \see STATUS1 for flag definitions.
+ */
+unsigned char QMI8658_readStatus1(void)
+{
+ unsigned char status;
+
+ QMI8658_read_reg(QMI8658Register_Status1, &status, sizeof(status));
+
+ return status;
+}
+
+float QMI8658_readTemp(void)
+{
+ unsigned char buf[2];
+ short temp = 0;
+ float temp_f = 0;
+
+ QMI8658_read_reg(QMI8658Register_Tempearture_L, buf, 2);
+ temp = ((short)buf[1] << 8) | buf[0];
+ temp_f = (float)temp / 256.0f;
+
+ return temp_f;
+}
+
+void QMI8658_read_acc_xyz(float acc_xyz[3])
+{
+ unsigned char buf_reg[6];
+ short raw_acc_xyz[3];
+
+ QMI8658_read_reg(QMI8658Register_Ax_L, buf_reg, 6); // 0x19, 25
+ raw_acc_xyz[0] = (short)((unsigned short)(buf_reg[1] << 8) | (buf_reg[0]));
+ raw_acc_xyz[1] = (short)((unsigned short)(buf_reg[3] << 8) | (buf_reg[2]));
+ raw_acc_xyz[2] = (short)((unsigned short)(buf_reg[5] << 8) | (buf_reg[4]));
+
+ acc_xyz[0] = (raw_acc_xyz[0] * ONE_G) / acc_lsb_div;
+ acc_xyz[1] = (raw_acc_xyz[1] * ONE_G) / acc_lsb_div;
+ acc_xyz[2] = (raw_acc_xyz[2] * ONE_G) / acc_lsb_div;
+
+ // QMI8658_printf("fis210x acc: %f %f %f\n", acc_xyz[0], acc_xyz[1], acc_xyz[2]);
+}
+
+void QMI8658_read_gyro_xyz(float gyro_xyz[3])
+{
+ unsigned char buf_reg[6];
+ short raw_gyro_xyz[3];
+
+ QMI8658_read_reg(QMI8658Register_Gx_L, buf_reg, 6); // 0x1f, 31
+ raw_gyro_xyz[0] = (short)((unsigned short)(buf_reg[1] << 8) | (buf_reg[0]));
+ raw_gyro_xyz[1] = (short)((unsigned short)(buf_reg[3] << 8) | (buf_reg[2]));
+ raw_gyro_xyz[2] = (short)((unsigned short)(buf_reg[5] << 8) | (buf_reg[4]));
+
+ gyro_xyz[0] = (raw_gyro_xyz[0] * 1.0f) / gyro_lsb_div;
+ gyro_xyz[1] = (raw_gyro_xyz[1] * 1.0f) / gyro_lsb_div;
+ gyro_xyz[2] = (raw_gyro_xyz[2] * 1.0f) / gyro_lsb_div;
+
+ // QMI8658_printf("fis210x gyro: %f %f %f\n", gyro_xyz[0], gyro_xyz[1], gyro_xyz[2]);
+}
+
+void QMI8658_read_xyz(float acc[3], float gyro[3], unsigned int *tim_count)
+{
+ unsigned char buf_reg[12];
+ short raw_acc_xyz[3];
+ short raw_gyro_xyz[3];
+ // float acc_t[3];
+ // float gyro_t[3];
+
+ if (tim_count)
+ {
+ unsigned char buf[3];
+ unsigned int timestamp;
+ QMI8658_read_reg(QMI8658Register_Timestamp_L, buf, 3); // 0x18 24
+ timestamp = (unsigned int)(((unsigned int)buf[2] << 16) | ((unsigned int)buf[1] << 8) | buf[0]);
+ if (timestamp > imu_timestamp)
+ imu_timestamp = timestamp;
+ else
+ imu_timestamp = (timestamp + 0x1000000 - imu_timestamp);
+
+ *tim_count = imu_timestamp;
+ }
+
+ QMI8658_read_reg(QMI8658Register_Ax_L, buf_reg, 12); // 0x19, 25
+ raw_acc_xyz[0] = (short)((unsigned short)(buf_reg[1] << 8) | (buf_reg[0]));
+ raw_acc_xyz[1] = (short)((unsigned short)(buf_reg[3] << 8) | (buf_reg[2]));
+ raw_acc_xyz[2] = (short)((unsigned short)(buf_reg[5] << 8) | (buf_reg[4]));
+
+ raw_gyro_xyz[0] = (short)((unsigned short)(buf_reg[7] << 8) | (buf_reg[6]));
+ raw_gyro_xyz[1] = (short)((unsigned short)(buf_reg[9] << 8) | (buf_reg[8]));
+ raw_gyro_xyz[2] = (short)((unsigned short)(buf_reg[11] << 8) | (buf_reg[10]));
+
+#if defined(QMI8658_UINT_MG_DPS)
+ // mg
+ acc[AXIS_X] = (float)(raw_acc_xyz[AXIS_X] * 1000.0f) / acc_lsb_div;
+ acc[AXIS_Y] = (float)(raw_acc_xyz[AXIS_Y] * 1000.0f) / acc_lsb_div;
+ acc[AXIS_Z] = (float)(raw_acc_xyz[AXIS_Z] * 1000.0f) / acc_lsb_div;
+#else
+ // m/s2
+ acc[AXIS_X] = (float)(raw_acc_xyz[AXIS_X] * ONE_G) / acc_lsb_div;
+ acc[AXIS_Y] = (float)(raw_acc_xyz[AXIS_Y] * ONE_G) / acc_lsb_div;
+ acc[AXIS_Z] = (float)(raw_acc_xyz[AXIS_Z] * ONE_G) / acc_lsb_div;
+#endif
+ // acc[AXIS_X] = imu_map.sign[AXIS_X]*acc_t[imu_map.map[AXIS_X]];
+ // acc[AXIS_Y] = imu_map.sign[AXIS_Y]*acc_t[imu_map.map[AXIS_Y]];
+ // acc[AXIS_Z] = imu_map.sign[AXIS_Z]*acc_t[imu_map.map[AXIS_Z]];
+
+#if defined(QMI8658_UINT_MG_DPS)
+ // dps
+ gyro[0] = (float)(raw_gyro_xyz[0] * 1.0f) / gyro_lsb_div;
+ gyro[1] = (float)(raw_gyro_xyz[1] * 1.0f) / gyro_lsb_div;
+ gyro[2] = (float)(raw_gyro_xyz[2] * 1.0f) / gyro_lsb_div;
+#else
+ // rad/s
+ gyro[AXIS_X] = (float)(raw_gyro_xyz[AXIS_X] * 0.01745f) / gyro_lsb_div; // *pi/180
+ gyro[AXIS_Y] = (float)(raw_gyro_xyz[AXIS_Y] * 0.01745f) / gyro_lsb_div;
+ gyro[AXIS_Z] = (float)(raw_gyro_xyz[AXIS_Z] * 0.01745f) / gyro_lsb_div;
+#endif
+ // gyro[AXIS_X] = imu_map.sign[AXIS_X]*gyro_t[imu_map.map[AXIS_X]];
+ // gyro[AXIS_Y] = imu_map.sign[AXIS_Y]*gyro_t[imu_map.map[AXIS_Y]];
+ // gyro[AXIS_Z] = imu_map.sign[AXIS_Z]*gyro_t[imu_map.map[AXIS_Z]];
+}
+
+void QMI8658_read_xyz_raw(short raw_acc_xyz[3], short raw_gyro_xyz[3], unsigned int *tim_count)
+{
+ unsigned char buf_reg[12];
+
+ if (tim_count)
+ {
+ unsigned char buf[3];
+ unsigned int timestamp;
+ QMI8658_read_reg(QMI8658Register_Timestamp_L, buf, 3); // 0x18 24
+ timestamp = (unsigned int)(((unsigned int)buf[2] << 16) | ((unsigned int)buf[1] << 8) | buf[0]);
+ if (timestamp > imu_timestamp)
+ imu_timestamp = timestamp;
+ else
+ imu_timestamp = (timestamp + 0x1000000 - imu_timestamp);
+
+ *tim_count = imu_timestamp;
+ }
+ QMI8658_read_reg(QMI8658Register_Ax_L, buf_reg, 12); // 0x19, 25
+
+ raw_acc_xyz[0] = (short)((unsigned short)(buf_reg[1] << 8) | (buf_reg[0]));
+ raw_acc_xyz[1] = (short)((unsigned short)(buf_reg[3] << 8) | (buf_reg[2]));
+ raw_acc_xyz[2] = (short)((unsigned short)(buf_reg[5] << 8) | (buf_reg[4]));
+
+ raw_gyro_xyz[0] = (short)((unsigned short)(buf_reg[7] << 8) | (buf_reg[6]));
+ raw_gyro_xyz[1] = (short)((unsigned short)(buf_reg[9] << 8) | (buf_reg[8]));
+ raw_gyro_xyz[2] = (short)((unsigned short)(buf_reg[11] << 8) | (buf_reg[10]));
+}
+
+void QMI8658_read_ae(float quat[4], float velocity[3])
+{
+ unsigned char buf_reg[14];
+ short raw_q_xyz[4];
+ short raw_v_xyz[3];
+
+ QMI8658_read_reg(QMI8658Register_Q1_L, buf_reg, 14);
+ raw_q_xyz[0] = (short)((unsigned short)(buf_reg[1] << 8) | (buf_reg[0]));
+ raw_q_xyz[1] = (short)((unsigned short)(buf_reg[3] << 8) | (buf_reg[2]));
+ raw_q_xyz[2] = (short)((unsigned short)(buf_reg[5] << 8) | (buf_reg[4]));
+ raw_q_xyz[3] = (short)((unsigned short)(buf_reg[7] << 8) | (buf_reg[6]));
+
+ raw_v_xyz[1] = (short)((unsigned short)(buf_reg[9] << 8) | (buf_reg[8]));
+ raw_v_xyz[2] = (short)((unsigned short)(buf_reg[11] << 8) | (buf_reg[10]));
+ raw_v_xyz[2] = (short)((unsigned short)(buf_reg[13] << 8) | (buf_reg[12]));
+
+ quat[0] = (float)(raw_q_xyz[0] * 1.0f) / ae_q_lsb_div;
+ quat[1] = (float)(raw_q_xyz[1] * 1.0f) / ae_q_lsb_div;
+ quat[2] = (float)(raw_q_xyz[2] * 1.0f) / ae_q_lsb_div;
+ quat[3] = (float)(raw_q_xyz[3] * 1.0f) / ae_q_lsb_div;
+
+ velocity[0] = (float)(raw_v_xyz[0] * 1.0f) / ae_v_lsb_div;
+ velocity[1] = (float)(raw_v_xyz[1] * 1.0f) / ae_v_lsb_div;
+ velocity[2] = (float)(raw_v_xyz[2] * 1.0f) / ae_v_lsb_div;
+}
+
+void QMI8658_enableWakeOnMotion(void)
+{
+ unsigned char womCmd[3];
+ enum QMI8658_Interrupt interrupt = QMI8658_Int1;
+ enum QMI8658_InterruptState initialState = QMI8658State_low;
+ enum QMI8658_WakeOnMotionThreshold threshold = QMI8658WomThreshold_low;
+ unsigned char blankingTime = 0x00;
+ const unsigned char blankingTimeMask = 0x3F;
+
+ QMI8658_enableSensors(QMI8658_CTRL7_DISABLE_ALL);
+ QMI8658_config_acc(QMI8658AccRange_2g, QMI8658AccOdr_LowPower_21Hz, QMI8658Lpf_Disable, QMI8658St_Disable);
+
+ womCmd[0] = QMI8658Register_Cal1_L; // WoM Threshold: absolute value in mg (with 1mg/LSB resolution)
+ womCmd[1] = threshold;
+ womCmd[2] = (unsigned char)interrupt | (unsigned char)initialState | (blankingTime & blankingTimeMask);
+ QMI8658_write_reg(QMI8658Register_Cal1_L, womCmd[1]);
+ QMI8658_write_reg(QMI8658Register_Cal1_H, womCmd[2]);
+
+ // QMI8658_doCtrl9Command(Ctrl9_ConfigureWakeOnMotion);
+ QMI8658_enableSensors(QMI8658_CTRL7_ACC_ENABLE);
+ // while(1)
+ //{
+ // QMI8658_read_reg(QMI8658Register_Status1,&womCmd[0],1);
+ // if(womCmd[0]&0x01)
+ // break;
+ // }
+}
+
+void QMI8658_disableWakeOnMotion(void)
+{
+ QMI8658_enableSensors(QMI8658_CTRL7_DISABLE_ALL);
+ QMI8658_write_reg(QMI8658Register_Cal1_L, 0);
+ // QMI8658_doCtrl9Command(Ctrl9_ConfigureWakeOnMotion);
+}
+
+void QMI8658_enableSensors(unsigned char enableFlags)
+{
+ if (enableFlags & QMI8658_CONFIG_AE_ENABLE)
+ {
+ enableFlags |= QMI8658_CTRL7_ACC_ENABLE | QMI8658_CTRL7_GYR_ENABLE;
+ }
+
+ QMI8658_write_reg(QMI8658Register_Ctrl7, enableFlags & QMI8658_CTRL7_ENABLE_MASK);
+}
+
+void QMI8658_Config_apply(struct QMI8658Config const *config)
+{
+ unsigned char fisSensors = config->inputSelection;
+
+ if (fisSensors & QMI8658_CONFIG_AE_ENABLE)
+ {
+ QMI8658_config_ae(config->aeOdr);
+ }
+ else
+ {
+ if (config->inputSelection & QMI8658_CONFIG_ACC_ENABLE)
+ {
+ QMI8658_config_acc(config->accRange, config->accOdr, QMI8658Lpf_Enable, QMI8658St_Disable);
+ }
+ if (config->inputSelection & QMI8658_CONFIG_GYR_ENABLE)
+ {
+ QMI8658_config_gyro(config->gyrRange, config->gyrOdr, QMI8658Lpf_Enable, QMI8658St_Disable);
+ }
+ }
+
+ if (config->inputSelection & QMI8658_CONFIG_MAG_ENABLE)
+ {
+ QMI8658_config_mag(config->magDev, config->magOdr);
+ }
+ QMI8658_enableSensors(fisSensors);
+}
+
+unsigned char QMI8658_init(void)
+{
+ unsigned char QMI8658_chip_id = 0x00;
+ unsigned char QMI8658_revision_id = 0x00;
+ unsigned char QMI8658_slave[2] = {QMI8658_SLAVE_ADDR_L, QMI8658_SLAVE_ADDR_H};
+ unsigned char iCount = 0;
+ int retry = 0;
+
+ while (iCount < 2)
+ {
+ QMI8658_slave_addr = QMI8658_slave[iCount];
+ retry = 0;
+
+ while ((QMI8658_chip_id != 0x05) && (retry++ < 5))
+ {
+
+ QMI8658_read_reg(QMI8658Register_WhoAmI, &QMI8658_chip_id, 1);
+ Serial.print("QMI8658Register_WhoAmI = ");
+ Serial.println(QMI8658_chip_id);
+// QMI8658_printf("QMI8658Register_WhoAmI = 0x%x\n", QMI8658_chip_id);
+ }
+ if (QMI8658_chip_id == 0x05)
+ {
+ break;
+ }
+ iCount++;
+ }
+ QMI8658_read_reg(QMI8658Register_Revision, &QMI8658_revision_id, 1);
+ if (QMI8658_chip_id == 0x05)
+ {
+ Serial.print("QMI8658_init slave = ");
+ Serial.println(QMI8658_slave_addr);
+ Serial.print("nQMI8658Register_WhoAmI = ");
+ Serial.print(QMI8658_chip_id);
+ Serial.print(" ");
+ Serial.println(QMI8658_revision_id);
+// QMI8658_printf("QMI8658_init slave=0x%x \r\nQMI8658Register_WhoAmI=0x%x 0x%x\n", QMI8658_slave_addr, QMI8658_chip_id, QMI8658_revision_id);
+ QMI8658_write_reg(QMI8658Register_Ctrl1, 0x60);
+ QMI8658_config.inputSelection = QMI8658_CONFIG_ACCGYR_ENABLE; // QMI8658_CONFIG_ACCGYR_ENABLE;
+ QMI8658_config.accRange = QMI8658AccRange_8g;
+ QMI8658_config.accOdr = QMI8658AccOdr_1000Hz;
+ QMI8658_config.gyrRange = QMI8658GyrRange_512dps; // QMI8658GyrRange_2048dps QMI8658GyrRange_1024dps
+ QMI8658_config.gyrOdr = QMI8658GyrOdr_1000Hz;
+ QMI8658_config.magOdr = QMI8658MagOdr_125Hz;
+ QMI8658_config.magDev = MagDev_AKM09918;
+ QMI8658_config.aeOdr = QMI8658AeOdr_128Hz;
+
+ QMI8658_Config_apply(&QMI8658_config);
+ if (1)
+ {
+ unsigned char read_data = 0x00;
+ QMI8658_read_reg(QMI8658Register_Ctrl1, &read_data, 1);
+ Serial.print("QMI8658Register_Ctrl1 = ");
+ Serial.println(read_data);
+// QMI8658_printf("QMI8658Register_Ctrl1=0x%x \n", read_data);
+ QMI8658_read_reg(QMI8658Register_Ctrl2, &read_data, 1);
+ Serial.print("QMI8658Register_Ctrl2 = ");
+ Serial.println(read_data);
+// QMI8658_printf("QMI8658Register_Ctrl2=0x%x \n", read_data);
+ QMI8658_read_reg(QMI8658Register_Ctrl3, &read_data, 1);
+ Serial.print("QMI8658Register_Ctrl1 = ");
+ Serial.println(read_data);
+// QMI8658_printf("QMI8658Register_Ctrl3=0x%x \n", read_data);
+ QMI8658_read_reg(QMI8658Register_Ctrl4, &read_data, 1);
+ Serial.print("QMI8658Register_Ctrl1 = ");
+ Serial.println(read_data);
+// QMI8658_printf("QMI8658Register_Ctrl4=0x%x \n", read_data);
+ QMI8658_read_reg(QMI8658Register_Ctrl5, &read_data, 1);
+ Serial.print("QMI8658Register_Ctrl1 = ");
+ Serial.println(read_data);
+// QMI8658_printf("QMI8658Register_Ctrl5=0x%x \n", read_data);
+ QMI8658_read_reg(QMI8658Register_Ctrl6, &read_data, 1);
+ Serial.print("QMI8658Register_Ctrl1 = ");
+ Serial.println(read_data);
+// QMI8658_printf("QMI8658Register_Ctrl6=0x%x \n", read_data);
+ QMI8658_read_reg(QMI8658Register_Ctrl7, &read_data, 1);
+ Serial.print("QMI8658Register_Ctrl1 = ");
+ Serial.println(read_data);
+// QMI8658_printf("QMI8658Register_Ctrl7=0x%x \n", read_data);
+ }
+ // QMI8658_set_layout(2);
+ return 1;
+ }
+ else
+ {
+ Serial.println("QMI8658_init fail");
+ QMI8658_chip_id = 0;
+ return 0;
+ }
+ // return QMI8658_chip_id;
+}
diff --git a/examples/smart-sensor-display/io/QMI8658.h b/examples/smart-sensor-display/io/QMI8658.h
new file mode 100644
index 0000000..43fbade
--- /dev/null
+++ b/examples/smart-sensor-display/io/QMI8658.h
@@ -0,0 +1,491 @@
+#ifndef QMI8658_H
+#define QMI8658_H
+
+#include "Config.h"
+#include "Wire.h"
+
+#define DEV_SDA_PIN (6)
+#define DEV_SCL_PIN (7)
+
+#ifndef M_PI
+#define M_PI (3.14159265358979323846f)
+#endif
+#ifndef ONE_G
+#define ONE_G (9.807f)
+#endif
+
+#define QMI8658_CTRL7_DISABLE_ALL (0x0)
+#define QMI8658_CTRL7_ACC_ENABLE (0x1)
+#define QMI8658_CTRL7_GYR_ENABLE (0x2)
+#define QMI8658_CTRL7_MAG_ENABLE (0x4)
+#define QMI8658_CTRL7_AE_ENABLE (0x8)
+#define QMI8658_CTRL7_GYR_SNOOZE_ENABLE (0x10)
+#define QMI8658_CTRL7_ENABLE_MASK (0xF)
+
+#define QMI8658_CONFIG_ACC_ENABLE QMI8658_CTRL7_ACC_ENABLE
+#define QMI8658_CONFIG_GYR_ENABLE QMI8658_CTRL7_GYR_ENABLE
+#define QMI8658_CONFIG_MAG_ENABLE QMI8658_CTRL7_MAG_ENABLE
+#define QMI8658_CONFIG_AE_ENABLE QMI8658_CTRL7_AE_ENABLE
+#define QMI8658_CONFIG_ACCGYR_ENABLE (QMI8658_CONFIG_ACC_ENABLE | QMI8658_CONFIG_GYR_ENABLE)
+#define QMI8658_CONFIG_ACCGYRMAG_ENABLE (QMI8658_CONFIG_ACC_ENABLE | QMI8658_CONFIG_GYR_ENABLE | QMI8658_CONFIG_MAG_ENABLE)
+#define QMI8658_CONFIG_AEMAG_ENABLE (QMI8658_CONFIG_AE_ENABLE | QMI8658_CONFIG_MAG_ENABLE)
+
+#define QMI8658_STATUS1_CMD_DONE (0x01)
+#define QMI8658_STATUS1_WAKEUP_EVENT (0x04)
+
+enum QMI8658Register
+{
+ /*! \brief FIS device identifier register. */
+ QMI8658Register_WhoAmI = 0, // 0
+ /*! \brief FIS hardware revision register. */
+ QMI8658Register_Revision, // 1
+ /*! \brief General and power management modes. */
+ QMI8658Register_Ctrl1, // 2
+ /*! \brief Accelerometer control. */
+ QMI8658Register_Ctrl2, // 3
+ /*! \brief Gyroscope control. */
+ QMI8658Register_Ctrl3, // 4
+ /*! \brief Magnetometer control. */
+ QMI8658Register_Ctrl4, // 5
+ /*! \brief Data processing settings. */
+ QMI8658Register_Ctrl5, // 6
+ /*! \brief AttitudeEngine control. */
+ QMI8658Register_Ctrl6, // 7
+ /*! \brief Sensor enabled status. */
+ QMI8658Register_Ctrl7, // 8
+ /*! \brief Reserved - do not write. */
+ QMI8658Register_Ctrl8, // 9
+ /*! \brief Host command register. */
+ QMI8658Register_Ctrl9, // 10
+ /*! \brief Calibration register 1 most significant byte. */
+ QMI8658Register_Cal1_L = 11,
+ /*! \brief Calibration register 1 least significant byte. */
+ QMI8658Register_Cal1_H,
+ /*! \brief Calibration register 2 most significant byte. */
+ QMI8658Register_Cal2_L,
+ /*! \brief Calibration register 2 least significant byte. */
+ QMI8658Register_Cal2_H,
+ /*! \brief Calibration register 3 most significant byte. */
+ QMI8658Register_Cal3_L,
+ /*! \brief Calibration register 3 least significant byte. */
+ QMI8658Register_Cal3_H,
+ /*! \brief Calibration register 4 most significant byte. */
+ QMI8658Register_Cal4_L,
+ /*! \brief Calibration register 4 least significant byte. */
+ QMI8658Register_Cal4_H,
+ /*! \brief FIFO control register. */
+ QMI8658Register_FifoCtrl = 19,
+ /*! \brief FIFO data register. */
+ QMI8658Register_FifoData, // 20
+ /*! \brief FIFO status register. */
+ QMI8658Register_FifoStatus, // 21
+ /*! \brief Output data overrun and availability. */
+ QMI8658Register_StatusInt = 45,
+ /*! \brief Output data overrun and availability. */
+ QMI8658Register_Status0,
+ /*! \brief Miscellaneous status register. */
+ QMI8658Register_Status1,
+ /*! \brief timestamp low. */
+ QMI8658Register_Timestamp_L = 48,
+ /*! \brief timestamp low. */
+ QMI8658Register_Timestamp_M,
+ /*! \brief timestamp low. */
+ QMI8658Register_Timestamp_H,
+ /*! \brief tempearture low. */
+ QMI8658Register_Tempearture_L = 51,
+ /*! \brief tempearture low. */
+ QMI8658Register_Tempearture_H,
+ /*! \brief Accelerometer X axis least significant byte. */
+ QMI8658Register_Ax_L = 53,
+ /*! \brief Accelerometer X axis most significant byte. */
+ QMI8658Register_Ax_H,
+ /*! \brief Accelerometer Y axis least significant byte. */
+ QMI8658Register_Ay_L,
+ /*! \brief Accelerometer Y axis most significant byte. */
+ QMI8658Register_Ay_H,
+ /*! \brief Accelerometer Z axis least significant byte. */
+ QMI8658Register_Az_L,
+ /*! \brief Accelerometer Z axis most significant byte. */
+ QMI8658Register_Az_H,
+ /*! \brief Gyroscope X axis least significant byte. */
+ QMI8658Register_Gx_L = 59,
+ /*! \brief Gyroscope X axis most significant byte. */
+ QMI8658Register_Gx_H,
+ /*! \brief Gyroscope Y axis least significant byte. */
+ QMI8658Register_Gy_L,
+ /*! \brief Gyroscope Y axis most significant byte. */
+ QMI8658Register_Gy_H,
+ /*! \brief Gyroscope Z axis least significant byte. */
+ QMI8658Register_Gz_L,
+ /*! \brief Gyroscope Z axis most significant byte. */
+ QMI8658Register_Gz_H,
+ /*! \brief Magnetometer X axis least significant byte. */
+ QMI8658Register_Mx_L = 65,
+ /*! \brief Magnetometer X axis most significant byte. */
+ QMI8658Register_Mx_H,
+ /*! \brief Magnetometer Y axis least significant byte. */
+ QMI8658Register_My_L,
+ /*! \brief Magnetometer Y axis most significant byte. */
+ QMI8658Register_My_H,
+ /*! \brief Magnetometer Z axis least significant byte. */
+ QMI8658Register_Mz_L,
+ /*! \brief Magnetometer Z axis most significant byte. */
+ QMI8658Register_Mz_H,
+ /*! \brief Quaternion increment W least significant byte. */
+ QMI8658Register_Q1_L = 73,
+ /*! \brief Quaternion increment W most significant byte. */
+ QMI8658Register_Q1_H,
+ /*! \brief Quaternion increment X least significant byte. */
+ QMI8658Register_Q2_L,
+ /*! \brief Quaternion increment X most significant byte. */
+ QMI8658Register_Q2_H,
+ /*! \brief Quaternion increment Y least significant byte. */
+ QMI8658Register_Q3_L,
+ /*! \brief Quaternion increment Y most significant byte. */
+ QMI8658Register_Q3_H,
+ /*! \brief Quaternion increment Z least significant byte. */
+ QMI8658Register_Q4_L,
+ /*! \brief Quaternion increment Z most significant byte. */
+ QMI8658Register_Q4_H,
+ /*! \brief Velocity increment X least significant byte. */
+ QMI8658Register_Dvx_L = 81,
+ /*! \brief Velocity increment X most significant byte. */
+ QMI8658Register_Dvx_H,
+ /*! \brief Velocity increment Y least significant byte. */
+ QMI8658Register_Dvy_L,
+ /*! \brief Velocity increment Y most significant byte. */
+ QMI8658Register_Dvy_H,
+ /*! \brief Velocity increment Z least significant byte. */
+ QMI8658Register_Dvz_L,
+ /*! \brief Velocity increment Z most significant byte. */
+ QMI8658Register_Dvz_H,
+ /*! \brief AttitudeEngine reg1. */
+ QMI8658Register_AeReg1 = 87,
+ /*! \brief AttitudeEngine overflow flags. */
+ QMI8658Register_AeOverflow,
+
+ QMI8658Register_I2CM_STATUS = 110
+};
+
+enum QMI8658_Ois_Register
+{
+ /*-----------------------------*/
+ /* Setup and Control Registers */
+ /*-----------------------------*/
+ /*! \brief SPI Endian Selection, and SPI 3/4 Wire */
+ QMI8658_OIS_Reg_Ctrl1 = 0x02, // 2 [0x02] -- Dflt: 0x20
+ /*! \brief Accelerometer control: ODR, Full Scale, Self Test */
+ QMI8658_OIS_Reg_Ctrl2, // 3 [0x03]
+ /*! \brief Gyroscope control: ODR, Full Scale, Self Test */
+ QMI8658_OIS_Reg_Ctrl3, // 4 [0x04]
+ /*! \brief Sensor Data Processing Settings */
+ QMI8658_OIS_Reg_Ctrl5 = 0x06, // 6 [0x06]
+ /*! \brief Sensor enabled status: Enable Sensors */
+ QMI8658_OIS_Reg_Ctrl7 = 0x08, // 8 [0x08]
+ /*-------------------*/
+ /* Status Registers */
+ /*-------------------*/
+ /*! \brief Sensor Data Availability and Lock Register */
+ QMI8658_OIS_Reg_StatusInt = 0x2D, // 45 [0x2D]
+ /*! \brief Output data overrun and availability */
+ QMI8658_OIS_Reg_Status0 = 0x2E, // 46 [0x2E]
+
+ /*-----------------------------------------------------*/
+ /* OIS Sensor Data Output Registers. 16-bit 2's complement */
+ /*-----------------------------------------------------*/
+ /*! \brief Accelerometer X axis least significant byte */
+ QMI8658_OIS_Reg_Ax_L = 0x33, // 53 [0x35]
+ /*! \brief Accelerometer X axis most significant byte */
+ QMI8658_OIS_Reg_Ax_H, // 54 [0x36]
+ /*! \brief Accelerometer Y axis least significant byte */
+ QMI8658_OIS_Reg_Ay_L, // 55 [0x37]
+ /*! \brief Accelerometer Y axis most significant byte */
+ QMI8658_OIS_Reg_Ay_H, // 56 [0x38]
+ /*! \brief Accelerometer Z axis least significant byte */
+ QMI8658_OIS_Reg_Az_L, // 57 [0x39]
+ /*! \brief Accelerometer Z axis most significant byte */
+ QMI8658_OIS_Reg_Az_H, // 58 [0x3A]
+
+ /*! \brief Gyroscope X axis least significant byte */
+ QMI8658_OIS_Reg_Gx_L = 0x3B, // 59 [0x3B]
+ /*! \brief Gyroscope X axis most significant byte */
+ QMI8658_OIS_Reg_Gx_H, // 60 [0x3C]
+ /*! \brief Gyroscope Y axis least significant byte */
+ QMI8658_OIS_Reg_Gy_L, // 61 [0x3D]
+ /*! \brief Gyroscope Y axis most significant byte */
+ QMI8658_OIS_Reg_Gy_H, // 62 [0x3E]
+ /*! \brief Gyroscope Z axis least significant byte */
+ QMI8658_OIS_Reg_Gz_L, // 63 [0x3F]
+ /*! \brief Gyroscope Z axis most significant byte */
+ QMI8658_OIS_Reg_Gz_H, // 64 [0x40]
+};
+
+enum QMI8658_Ctrl9Command
+{
+ QMI8658_Ctrl9_Cmd_NOP = 0X00,
+ QMI8658_Ctrl9_Cmd_GyroBias = 0X01,
+ QMI8658_Ctrl9_Cmd_Rqst_Sdi_Mod = 0X03,
+ QMI8658_Ctrl9_Cmd_WoM_Setting = 0x08,
+ QMI8658_Ctrl9_Cmd_AccelHostDeltaOffset = 0x09,
+ QMI8658_Ctrl9_Cmd_GyroHostDeltaOffset = 0x0A,
+ QMI8658_Ctrl9_Cmd_Dbg_WoM_Data_Enable = 0xF8,
+
+};
+
+enum QMI8658_LpfConfig
+{
+ QMI8658Lpf_Disable, /*!< \brief Disable low pass filter. */
+ QMI8658Lpf_Enable /*!< \brief Enable low pass filter. */
+};
+
+enum QMI8658_HpfConfig
+{
+ QMI8658Hpf_Disable, /*!< \brief Disable high pass filter. */
+ QMI8658Hpf_Enable /*!< \brief Enable high pass filter. */
+};
+
+enum QMI8658_StConfig
+{
+ QMI8658St_Disable, /*!< \brief Disable high pass filter. */
+ QMI8658St_Enable /*!< \brief Enable high pass filter. */
+};
+
+enum QMI8658_LpfMode
+{
+ A_LSP_MODE_0 = 0x00 << 1,
+ A_LSP_MODE_1 = 0x01 << 1,
+ A_LSP_MODE_2 = 0x02 << 1,
+ A_LSP_MODE_3 = 0x03 << 1,
+
+ G_LSP_MODE_0 = 0x00 << 5,
+ G_LSP_MODE_1 = 0x01 << 5,
+ G_LSP_MODE_2 = 0x02 << 5,
+ G_LSP_MODE_3 = 0x03 << 5
+};
+
+enum QMI8658_AccRange
+{
+ QMI8658AccRange_2g = 0x00 << 4, /*!< \brief +/- 2g range */
+ QMI8658AccRange_4g = 0x01 << 4, /*!< \brief +/- 4g range */
+ QMI8658AccRange_8g = 0x02 << 4, /*!< \brief +/- 8g range */
+ QMI8658AccRange_16g = 0x03 << 4 /*!< \brief +/- 16g range */
+};
+
+enum QMI8658_AccOdr
+{
+ QMI8658AccOdr_8000Hz = 0x00, /*!< \brief High resolution 8000Hz output rate. */
+ QMI8658AccOdr_4000Hz = 0x01, /*!< \brief High resolution 4000Hz output rate. */
+ QMI8658AccOdr_2000Hz = 0x02, /*!< \brief High resolution 2000Hz output rate. */
+ QMI8658AccOdr_1000Hz = 0x03, /*!< \brief High resolution 1000Hz output rate. */
+ QMI8658AccOdr_500Hz = 0x04, /*!< \brief High resolution 500Hz output rate. */
+ QMI8658AccOdr_250Hz = 0x05, /*!< \brief High resolution 250Hz output rate. */
+ QMI8658AccOdr_125Hz = 0x06, /*!< \brief High resolution 125Hz output rate. */
+ QMI8658AccOdr_62_5Hz = 0x07, /*!< \brief High resolution 62.5Hz output rate. */
+ QMI8658AccOdr_31_25Hz = 0x08, /*!< \brief High resolution 31.25Hz output rate. */
+ QMI8658AccOdr_LowPower_128Hz = 0x0c, /*!< \brief Low power 128Hz output rate. */
+ QMI8658AccOdr_LowPower_21Hz = 0x0d, /*!< \brief Low power 21Hz output rate. */
+ QMI8658AccOdr_LowPower_11Hz = 0x0e, /*!< \brief Low power 11Hz output rate. */
+ QMI8658AccOdr_LowPower_3Hz = 0x0f /*!< \brief Low power 3Hz output rate. */
+};
+
+enum QMI8658_GyrRange
+{
+ QMI8658GyrRange_32dps = 0 << 4, /*!< \brief +-32 degrees per second. */
+ QMI8658GyrRange_64dps = 1 << 4, /*!< \brief +-64 degrees per second. */
+ QMI8658GyrRange_128dps = 2 << 4, /*!< \brief +-128 degrees per second. */
+ QMI8658GyrRange_256dps = 3 << 4, /*!< \brief +-256 degrees per second. */
+ QMI8658GyrRange_512dps = 4 << 4, /*!< \brief +-512 degrees per second. */
+ QMI8658GyrRange_1024dps = 5 << 4, /*!< \brief +-1024 degrees per second. */
+ QMI8658GyrRange_2048dps = 6 << 4, /*!< \brief +-2048 degrees per second. */
+ QMI8658GyrRange_4096dps = 7 << 4 /*!< \brief +-2560 degrees per second. */
+};
+
+/*!
+ * \brief Gyroscope output rate configuration.
+ */
+enum QMI8658_GyrOdr
+{
+ QMI8658GyrOdr_8000Hz = 0x00, /*!< \brief High resolution 8000Hz output rate. */
+ QMI8658GyrOdr_4000Hz = 0x01, /*!< \brief High resolution 4000Hz output rate. */
+ QMI8658GyrOdr_2000Hz = 0x02, /*!< \brief High resolution 2000Hz output rate. */
+ QMI8658GyrOdr_1000Hz = 0x03, /*!< \brief High resolution 1000Hz output rate. */
+ QMI8658GyrOdr_500Hz = 0x04, /*!< \brief High resolution 500Hz output rate. */
+ QMI8658GyrOdr_250Hz = 0x05, /*!< \brief High resolution 250Hz output rate. */
+ QMI8658GyrOdr_125Hz = 0x06, /*!< \brief High resolution 125Hz output rate. */
+ QMI8658GyrOdr_62_5Hz = 0x07, /*!< \brief High resolution 62.5Hz output rate. */
+ QMI8658GyrOdr_31_25Hz = 0x08 /*!< \brief High resolution 31.25Hz output rate. */
+};
+
+enum QMI8658_AeOdr
+{
+ QMI8658AeOdr_1Hz = 0x00, /*!< \brief 1Hz output rate. */
+ QMI8658AeOdr_2Hz = 0x01, /*!< \brief 2Hz output rate. */
+ QMI8658AeOdr_4Hz = 0x02, /*!< \brief 4Hz output rate. */
+ QMI8658AeOdr_8Hz = 0x03, /*!< \brief 8Hz output rate. */
+ QMI8658AeOdr_16Hz = 0x04, /*!< \brief 16Hz output rate. */
+ QMI8658AeOdr_32Hz = 0x05, /*!< \brief 32Hz output rate. */
+ QMI8658AeOdr_64Hz = 0x06, /*!< \brief 64Hz output rate. */
+ QMI8658AeOdr_128Hz = 0x07, /*!< \brief 128Hz output rate. */
+ /*!
+ * \brief Motion on demand mode.
+ *
+ * In motion on demand mode the application can trigger AttitudeEngine
+ * output samples as necessary. This allows the AttitudeEngine to be
+ * synchronized with external data sources.
+ *
+ * When in Motion on Demand mode the application should request new data
+ * by calling the QMI8658_requestAttitudeEngineData() function. The
+ * AttitudeEngine will respond with a data ready event (INT2) when the
+ * data is available to be read.
+ */
+ QMI8658AeOdr_motionOnDemand = 128
+};
+
+enum QMI8658_MagOdr
+{
+ QMI8658MagOdr_1000Hz = 0x00, /*!< \brief 1000Hz output rate. */
+ QMI8658MagOdr_500Hz = 0x01, /*!< \brief 500Hz output rate. */
+ QMI8658MagOdr_250Hz = 0x02, /*!< \brief 250Hz output rate. */
+ QMI8658MagOdr_125Hz = 0x03, /*!< \brief 125Hz output rate. */
+ QMI8658MagOdr_62_5Hz = 0x04, /*!< \brief 62.5Hz output rate. */
+ QMI8658MagOdr_31_25Hz = 0x05 /*!< \brief 31.25Hz output rate. */
+};
+
+enum QMI8658_MagDev
+{
+ MagDev_AKM09918 = (0 << 3), /*!< \brief AKM09918. */
+};
+
+enum QMI8658_AccUnit
+{
+ QMI8658AccUnit_g, /*!< \brief Accelerometer output in terms of g (9.81m/s^2). */
+ QMI8658AccUnit_ms2 /*!< \brief Accelerometer output in terms of m/s^2. */
+};
+
+enum QMI8658_GyrUnit
+{
+ QMI8658GyrUnit_dps, /*!< \brief Gyroscope output in degrees/s. */
+ QMI8658GyrUnit_rads /*!< \brief Gyroscope output in rad/s. */
+};
+
+struct QMI8658Config
+{
+ /*! \brief Sensor fusion input selection. */
+ unsigned char inputSelection;
+ /*! \brief Accelerometer dynamic range configuration. */
+ enum QMI8658_AccRange accRange;
+ /*! \brief Accelerometer output rate. */
+ enum QMI8658_AccOdr accOdr;
+ /*! \brief Gyroscope dynamic range configuration. */
+ enum QMI8658_GyrRange gyrRange;
+ /*! \brief Gyroscope output rate. */
+ enum QMI8658_GyrOdr gyrOdr;
+ /*! \brief AttitudeEngine output rate. */
+ enum QMI8658_AeOdr aeOdr;
+ /*!
+ * \brief Magnetometer output data rate.
+ *
+ * \remark This parameter is not used when using an external magnetometer.
+ * In this case the external magnetometer is sampled at the FIS output
+ * data rate, or at an integer divisor thereof such that the maximum
+ * sample rate is not exceeded.
+ */
+ enum QMI8658_MagOdr magOdr;
+
+ /*!
+ * \brief Magnetometer device to use.
+ *
+ * \remark This parameter is not used when using an external magnetometer.
+ */
+ enum QMI8658_MagDev magDev;
+};
+
+#define QMI8658_SAMPLE_SIZE (3 * sizeof(short))
+#define QMI8658_AE_SAMPLE_SIZE ((4 + 3 + 1) * sizeof(short) + sizeof(unsigned char))
+struct FisImuRawSample
+{
+ /*! \brief The sample counter of the sample. */
+ unsigned char timestamp[3];
+ /*!
+ * \brief Pointer to accelerometer data in the sample buffer.
+ *
+ * \c NULL if no accelerometer data is available in the buffer.
+ */
+ unsigned char const *accelerometerData;
+ /*!
+ * \brief Pointer to gyroscope data in the sample buffer.
+ *
+ * \c NULL if no gyroscope data is available in the buffer.
+ */
+ unsigned char const *gyroscopeData;
+ /*!
+ * \brief Pointer to magnetometer data in the sample buffer.
+ *
+ * \c NULL if no magnetometer data is available in the buffer.
+ */
+ unsigned char const *magnetometerData;
+ /*!
+ * \brief Pointer to AttitudeEngine data in the sample buffer.
+ *
+ * \c NULL if no AttitudeEngine data is available in the buffer.
+ */
+ unsigned char const *attitudeEngineData;
+ /*! \brief Raw sample buffer. */
+ unsigned char sampleBuffer[QMI8658_SAMPLE_SIZE + QMI8658_AE_SAMPLE_SIZE];
+ /*! \brief Contents of the FIS status 1 register. */
+ unsigned char status1;
+ // unsigned char status0;
+ // unsigned int durT;
+};
+
+struct QMI8658_offsetCalibration
+{
+ enum QMI8658_AccUnit accUnit;
+ float accOffset[3];
+ enum QMI8658_GyrUnit gyrUnit;
+ float gyrOffset[3];
+};
+
+struct QMI8658_sensitivityCalibration
+{
+ float accSensitivity[3];
+ float gyrSensitivity[3];
+};
+
+enum QMI8658_Interrupt
+{
+ /*! \brief FIS INT1 line. */
+ QMI8658_Int1 = (0 << 6),
+ /*! \brief FIS INT2 line. */
+ QMI8658_Int2 = (1 << 6)
+};
+
+enum QMI8658_InterruptState
+{
+ QMI8658State_high = (1 << 7), /*!< Interrupt high. */
+ QMI8658State_low = (0 << 7) /*!< Interrupt low. */
+};
+
+enum QMI8658_WakeOnMotionThreshold
+{
+ QMI8658WomThreshold_high = 128, /*!< High threshold - large motion needed to wake. */
+ QMI8658WomThreshold_low = 32 /*!< Low threshold - small motion needed to wake. */
+};
+
+extern unsigned char QMI8658_write_reg(unsigned char reg, unsigned char value);
+extern unsigned char QMI8658_read_reg(unsigned char reg, unsigned char *buf, unsigned short len);
+extern unsigned char QMI8658_init(void);
+extern void QMI8658_Config_apply(struct QMI8658Config const *config);
+extern void QMI8658_enableSensors(unsigned char enableFlags);
+extern void QMI8658_read_acc_xyz(float acc_xyz[3]);
+extern void QMI8658_read_gyro_xyz(float gyro_xyz[3]);
+extern void QMI8658_read_xyz(float acc[3], float gyro[3], unsigned int *tim_count);
+extern void QMI8658_read_xyz_raw(short raw_acc_xyz[3], short raw_gyro_xyz[3], unsigned int *tim_count);
+extern void QMI8658_read_ae(float quat[4], float velocity[3]);
+extern unsigned char QMI8658_readStatus0(void);
+extern unsigned char QMI8658_readStatus1(void);
+extern float QMI8658_readTemp(void);
+extern void QMI8658_enableWakeOnMotion(void);
+extern void QMI8658_disableWakeOnMotion(void);
+
+#endif
diff --git a/examples/smart-sensor-display/smart-sensor-display.cpp b/examples/smart-sensor-display/smart-sensor-display.cpp
index 4c9a8a1..c512601 100644
--- a/examples/smart-sensor-display/smart-sensor-display.cpp
+++ b/examples/smart-sensor-display/smart-sensor-display.cpp
@@ -27,12 +27,12 @@
*
*/
+#include "configuration.h"
#include
#include
#include
-
//#include
#include
//#include
@@ -41,7 +41,13 @@
#include "display/activities/SensorValuesActivity.h"
#include "io/DHTxx.h"
-//#include "io/LightSensor.h"
+//#include "../smart-sensor/io/LightSensor.h"
+//#include "io/BatterySensor.h"
+#include "io/MotionSensor.h"
+
+// Accelerometer and Gyroscope
+//#include "io/QMI8658.h"
+
using namespace IO::Env;
using namespace Service;
@@ -57,34 +63,49 @@ ModuleParameter* controlModuleParameter = nullptr;
SwitchControlActivity* switchControl;
+Dashboard* dashboard;
+
void setup() {
- homeGenie = HomeGenie::getInstance();
+ //uint8_t batterySensorPin = 1;
+ uint8_t motionSensorPin = 16;
- miniModule = homeGenie->getDefaultModule();
+ PowerManager::setWakeUpGPIO((gpio_num_t)motionSensorPin);
- /*
- // Light sensor
- homeGenie->addIOHandler(new LightSensor());
- auto luminance = new ModuleParameter(IOEventPaths::Sensor_Luminance);
- miniModule->properties.add(luminance);
- //*/
+ homeGenie = HomeGenie::getInstance();
+ miniModule = homeGenie->getDefaultModule();
auto roundDisplay = (new UI::Drivers::RoundDisplay())->getDisplay();
- auto dashboard =
+ dashboard =
new Dashboard(roundDisplay);
if (Config::isDeviceConfigured()) {
+ /*
+ // Battery sensor
+ auto batterySensor = new BatterySensor(batterySensorPin);
+ batterySensor->setModule(miniModule);
+ homeGenie->addIOHandler(batterySensor);
+ //*/
+
+ // Motion sensor
+ auto motionSensor = new MotionSensor(motionSensorPin);
+ motionSensor->setModule(miniModule);
+ homeGenie->addIOHandler(motionSensor);
+
+ /*
+ // Light sensor
+ auto lightSensor = new LightSensor();
+ lightSensor->setModule(miniModule);
+ homeGenie->addIOHandler(lightSensor);
+ //*/
+
// Temperature and humidity sensor
- auto dht = new DHTxx(22);
- homeGenie->addIOHandler(dht);
- auto temperature = new ModuleParameter(IOEventPaths::Sensor_Temperature);
- miniModule->properties.add(temperature);
- auto humidity = new ModuleParameter(IOEventPaths::Sensor_Humidity);
- miniModule->properties.add(humidity);
-
- // add custom properties
+ auto dhtSensor = new DHTxx(22);
+ dhtSensor->setModule(miniModule);
+ homeGenie->addIOHandler(dhtSensor);
+
+ // add custom properties to default module
controlModuleParameter = new ModuleParameter("RemoteControl.EndPoint", Config::getSetting("ctrl-mod"));
miniModule->properties.add(controlModuleParameter);
miniModule->properties.add(new ModuleParameter(
@@ -92,6 +113,7 @@ void setup() {
"module.text:any:switch,light,dimmer,color,shutter:any:uri" // last option can be "uri" or "id"
));
+ // Add activities to UI
auto systemInfo = new SystemInfoActivity();
dashboard->addActivity(systemInfo);
@@ -112,6 +134,9 @@ void setup() {
} else {
+ // On devices with default RAM, activating
+ // Bluetooth will get most of the available RAM,
+ // so we just start the configuration activity
auto systemInfo = new SystemInfoActivity();
dashboard->addActivity(systemInfo);
dashboard->setForegroundActivity(systemInfo);
@@ -120,17 +145,35 @@ void setup() {
homeGenie->begin();
+ /*
+ // Init accel./gyro chip
+ Wire.begin(DEV_SDA_PIN, DEV_SCL_PIN, 400000);
+
+ QMI8658_enableSensors(QMI8658_CONFIG_AE_ENABLE);
+ //QMI8658_enableWakeOnMotion();
+
+ QMI8658_init();
+ //*/
}
void loop()
{
homeGenie->loop();
+ // check if configuration parameters changed
if (controlModuleParameter != nullptr && controlModuleParameter->value != controlModuleUrl) {
controlModuleUrl = controlModuleParameter->value;
switchControl->setModuleUrl(controlModuleUrl);
Config::saveSetting("ctrl-mod", controlModuleUrl);
- IO::Logger::info("Control module set to: %s\n", controlModuleUrl.c_str());
+ IO::Logger::info("Control module set to: %s", controlModuleUrl.c_str());
}
+ /*
+ // Test reading accel/gyro data
+ float acc[3], gyro[3];
+ unsigned int count = 0;
+ QMI8658_read_xyz(acc, gyro, &count);
+ Serial.printf("ACC X %.2f Y %.2f Z %.2f ", acc[0], acc[1], acc[2]);
+ Serial.printf("GYR X %.2f Y %.2f Z %.2f\n", gyro[0], gyro[1], gyro[2]);
+ //*/
}
diff --git a/examples/smart-sensor/io/DS18B20.h b/examples/smart-sensor/io/DS18B20.h
index 736bc01..07ad112 100644
--- a/examples/smart-sensor/io/DS18B20.h
+++ b/examples/smart-sensor/io/DS18B20.h
@@ -50,6 +50,11 @@ namespace IO { namespace Env {
DS18B20() {
setLoopInterval(DS18B20_SAMPLING_RATE);
}
+ void setModule(Module* m) override {
+ IIOEventSender::setModule(m);
+ auto temperature = new ModuleParameter(IOEventPaths::Sensor_Temperature);
+ m->properties.add(temperature);
+ }
void begin() override;
void loop() override;
void setInputPin(uint8_t);
diff --git a/examples/smart-sensor/io/LightSensor.cpp b/examples/smart-sensor/io/LightSensor.cpp
index 052c949..2845b35 100644
--- a/examples/smart-sensor/io/LightSensor.cpp
+++ b/examples/smart-sensor/io/LightSensor.cpp
@@ -41,7 +41,7 @@ namespace IO { namespace Env {
if (lightLevel != currentLevel) {
currentLevel = lightLevel;
Logger::info("@%s [%s %d]", LIGHTSENSOR_NS_PREFIX, (IOEventPaths::Sensor_Luminance), currentLevel);
- sendEvent(domain.c_str(), address.c_str(), (const uint8_t*)(IOEventPaths::Sensor_Luminance), (uint16_t *)¤tLevel, SensorLight);
+ sendEvent((const uint8_t*)(IOEventPaths::Sensor_Luminance), (uint16_t *)¤tLevel, SensorLight);
}
}
diff --git a/examples/smart-sensor/io/LightSensor.h b/examples/smart-sensor/io/LightSensor.h
index c9de39d..e9a7d8e 100644
--- a/examples/smart-sensor/io/LightSensor.h
+++ b/examples/smart-sensor/io/LightSensor.h
@@ -46,13 +46,17 @@ namespace IO { namespace Env {
LightSensor() {
setLoopInterval(LIGHTSENSOR_SAMPLING_RATE);
}
+ void setModule(Module* m) override {
+ IIOEventSender::setModule(m);
+ auto luminance = new ModuleParameter(IOEventPaths::Sensor_Luminance);
+ m->properties.add(luminance);
+ }
+
void begin() override;
void loop() override;
void setInputPin(uint8_t number);
uint16_t getLightLevel();
private:
- String domain = IOEventDomains::HomeAutomation_HomeGenie;
- String address = CONFIG_BUILTIN_MODULE_ADDRESS;
uint8_t inputPin = CONFIG_LightSensorPin; // Analogic input pin A0 (0)
uint16_t currentLevel = 0;
};
diff --git a/examples/smart-sensor/smart-sensor.cpp b/examples/smart-sensor/smart-sensor.cpp
index cc1969b..60c8f58 100644
--- a/examples/smart-sensor/smart-sensor.cpp
+++ b/examples/smart-sensor/smart-sensor.cpp
@@ -45,14 +45,14 @@ void setup() {
auto miniModule = homeGenie->getDefaultModule();
// Temperature sensor
- homeGenie->addIOHandler(new DS18B20());
- auto temperature = new ModuleParameter(IOEventPaths::Sensor_Temperature);
- miniModule->properties.add(temperature);
+ auto temperatureSensor = new DS18B20();
+ temperatureSensor->setModule(miniModule);
+ homeGenie->addIOHandler(temperatureSensor);
// Light sensor
- homeGenie->addIOHandler(new LightSensor());
- auto luminance = new ModuleParameter(IOEventPaths::Sensor_Luminance);
- miniModule->properties.add(luminance);
+ auto lightSensor = new LightSensor();
+ lightSensor->setModule(miniModule);
+ homeGenie->addIOHandler(lightSensor);
homeGenie->begin();
diff --git a/examples/x10-transceiver/io/RFReceiver.cpp b/examples/x10-transceiver/io/RFReceiver.cpp
index f983945..b1193dc 100644
--- a/examples/x10-transceiver/io/RFReceiver.cpp
+++ b/examples/x10-transceiver/io/RFReceiver.cpp
@@ -95,7 +95,7 @@ namespace IO { namespace X10 {
if (isStandardCode || isSecurityCode) {
messageType = isStandardCode ? (uint8_t) 0x20 : (uint8_t) 0x29;
uint8_t data[] = { messageType, byteBuffer[0], byteBuffer[1], (byteBuffer[2]), (byteBuffer[3]) };
- sendEvent(domain.c_str(), address.c_str(), (const uint8_t*)(IOEventPaths::Receiver_RawData), data, IOEventDataType::Undefined);
+ sendEvent((const uint8_t*)(IOEventPaths::Receiver_RawData), data, IOEventDataType::Undefined);
}
receivedCount = -1;
diff --git a/examples/x10-transceiver/io/RFReceiver.h b/examples/x10-transceiver/io/RFReceiver.h
index 6540981..c2d2178 100644
--- a/examples/x10-transceiver/io/RFReceiver.h
+++ b/examples/x10-transceiver/io/RFReceiver.h
@@ -48,8 +48,6 @@ namespace IO { namespace X10 {
void receive();
private:
- String domain = IOEventDomains::HomeAutomation_X10;
- String address = CONFIG_X10RF_MODULE_ADDRESS;
RFReceiverConfig *configuration;
// 32-bit RF message decoding
volatile uint8_t messageType = 0x00;
diff --git a/examples/x10-transceiver/x10-transceiver.cpp b/examples/x10-transceiver/x10-transceiver.cpp
index c3c92af..1348beb 100644
--- a/examples/x10-transceiver/x10-transceiver.cpp
+++ b/examples/x10-transceiver/x10-transceiver.cpp
@@ -51,15 +51,12 @@ void setup() {
homeGenie->addAPIHandler(apiHandler);
// X10 RF RFReceiver
+ auto rfModule = apiHandler->getModule(IO::IOEventDomains::HomeAutomation_X10, CONFIG_X10RF_MODULE_ADDRESS);
auto x10ReceiverConfig = new X10::RFReceiverConfig(CONFIG_X10RFReceiverPin);
auto x10Receiver = new X10::RFReceiver(x10ReceiverConfig);
+ x10Receiver->setModule(rfModule);
homeGenie->addIOHandler(x10Receiver);
- auto propRawData = new ModuleParameter(IOEventPaths::Receiver_RawData);
- auto propCommand = new ModuleParameter(IOEventPaths::Receiver_Command);
- miniModule->properties.add(propRawData);
- miniModule->properties.add(propCommand);
-
homeGenie->begin();
}
diff --git a/platformio.ini b/platformio.ini
index d20c4b8..c6c92f1 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -21,7 +21,6 @@ lib_deps =
ArduinoJson@6.21.4
thijse/ArduinoLog@1.1.1
WebSockets@2.4.1
- OneWire@2.3.8
vortigont/LinkedList@1.5.0
hideakitai/MsgPack
adafruit/TINYXML@1.0.3
@@ -66,6 +65,8 @@ build_flags = -Os -I examples -I src
build_src_filter = + - +
board_build.flash_size = 4MB
board_build.partitions = min_spiffs.csv
+lib_deps = ${env.lib_deps}
+ OneWire@2.3.8
[env:smart-sensor-d1-mini-esp32]
platform = espressif32@6.5.0
@@ -73,12 +74,16 @@ build_flags = -Os -I examples -I src -D MINI_ESP32 -D CONFIG_ServiceButtonPin=16
build_src_filter = + - +
board_build.flash_size = 4MB
board_build.partitions = min_spiffs.csv
+lib_deps = ${env.lib_deps}
+ OneWire@2.3.8
[env:smart-sensor-d1-mini]
platform = espressif8266@2.6.3
board = d1_mini
build_flags = -Os -I examples -I src
build_src_filter = + - +
+lib_deps = ${env.lib_deps}
+ OneWire@2.3.8
lib_ignore =
ESP32Time
ESP32_BleSerial
@@ -86,18 +91,17 @@ lib_ignore =
[env:smart-sensor-display]
platform = espressif32@6.5.0
-build_flags = -Os -I examples -I src
+build_flags = -Os -I examples -I src -D CONFIG_ENABLE_POWER_MANAGER
build_src_filter = + - +
board_build.flash_size = 4MB
board_build.partitions = no_ota.csv
lib_deps = ${env.lib_deps}
- Wire
RobTillaart/DHTNew@0.4.19
[env:smart-sensor-display-s3]
platform = espressif32@6.5.0
board = esp32-s3-devkitc-1
-build_flags = -Os -I examples -I src -D ESP32_S3 -DESP32S3_DEV -DBOARD_HAS_PSRAM
+build_flags = -Os -I examples -I src -D ESP32_S3 -D CONFIG_ENABLE_POWER_MANAGER -DESP32S3_DEV -DBOARD_HAS_PSRAM -D CONFIG_GPIO_OUT={15,17,18}
build_src_filter = + - +
board_build.mcu = esp32s3
board_build.f_cpu = 240000000L
@@ -108,8 +112,7 @@ board_build.flash_mode = qio
board_build.partitions = default_16MB.csv
board_upload.flash_size = 16MB
lib_deps = ${env.lib_deps}
- Wire
- RobTillaart/DHTNew@0.4.19
+ RobTillaart/DHTNew@0.4.19
[env:x10-transceiver]
platform = espressif32@6.5.0
diff --git a/src/HomeGenie.cpp b/src/HomeGenie.cpp
index db21eaa..c1158a1 100644
--- a/src/HomeGenie.cpp
+++ b/src/HomeGenie.cpp
@@ -53,7 +53,10 @@ namespace Service {
addIOHandler(gpioPort);
auto homeGenieHandler = new HomeGenieHandler(gpioPort);
addAPIHandler(homeGenieHandler);
-
+#ifdef CONFIG_ENABLE_POWER_MANAGER
+ PowerManager::setWakeUpInterval(0);
+ PowerManager::init();
+#endif
Logger::info("+ Starting HomeGenie service");
}
@@ -92,6 +95,15 @@ namespace Service {
// TODO: sort of system load index could be obtained by measuring time elapsed for `TaskManager::loop()` method
TaskManager::loop();
+#ifdef CONFIG_ENABLE_POWER_MANAGER
+ if (Config::isDeviceConfigured() && PowerManager::canEnterSleepMode()) {
+
+ // TODO: should gracefully stop all activities and drivers
+
+ PowerManager::sleep();
+ }
+#endif
+
Logger::verbose(":%s loop() << END", HOMEGENIEMINI_NS_PREFIX);
}
diff --git a/src/HomeGenie.h b/src/HomeGenie.h
index de3ff19..2abeab1 100644
--- a/src/HomeGenie.h
+++ b/src/HomeGenie.h
@@ -31,9 +31,14 @@
#define HOMEGENIE_MINI_HOMEGENIE_H
+#ifdef CONFIG_ENABLE_POWER_MANAGER
+#include "PowerManager.h"
+#endif
+
#include "Task.h"
#include "TaskManager.h"
+#include "data/Module.h"
#include "io/gpio/GPIOPort.h"
#include "io/IOEventPaths.h"
#include "io/IOManager.h"
@@ -42,7 +47,6 @@
#include "service/api/APIHandler.h"
#include "service/api/HomeGenieHandler.h"
#include "service/EventRouter.h"
-#include "service/Module.h"
#define HOMEGENIEMINI_NS_PREFIX "Service::HomeGenie"
@@ -50,6 +54,7 @@
namespace Service {
using namespace IO;
+ using namespace Data;
using namespace Net;
using namespace Service::API;
diff --git a/src/PowerManager.cpp b/src/PowerManager.cpp
new file mode 100644
index 0000000..ef2b585
--- /dev/null
+++ b/src/PowerManager.cpp
@@ -0,0 +1,105 @@
+/*
+ * HomeGenie-Mini (c) 2018-2024 G-Labs
+ *
+ *
+ * This file is part of HomeGenie-Mini (HGM).
+ *
+ * HomeGenie-Mini is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HomeGenie-Mini 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HomeGenie-Mini. If not, see .
+ *
+ *
+ * Authors:
+ * - Generoso Martello
+ *
+ */
+
+#ifdef ESP32
+
+#include "PowerManager.h"
+
+#if CONFIG_IDF_TARGET_ESP32
+ #define THRESHOLD 40 /* Greater the value, more the sensitivity */
+#else //ESP32-S2 and ESP32-S3 + default for other chips (to be adjusted) */
+ #define THRESHOLD 5000 /* Lower the value, more the sensitivity */
+#endif
+
+RTC_DATA_ATTR int wakeUpCount = 0;
+
+namespace Service {
+ unsigned long PowerManager::lastUserActivityTs = 0;
+ unsigned long PowerManager::deepSleepTimeoutMs = 30000;
+ // wake up sources
+ unsigned long PowerManager::wakeUpIntervalMs = 0;
+ gpio_num_t PowerManager::wakeUpGPIO = GPIO_NUM_NC;
+ touch_pad_t PowerManager::wakeUpTouchPadPin = TOUCH_PAD_NUM0;
+
+ void PowerManager::init() {
+
+ if (wakeUpCount > 0) {
+
+ esp_sleep_wakeup_cause_t wakeup_reason;
+ wakeup_reason = esp_sleep_get_wakeup_cause();
+ switch(wakeup_reason)
+ {
+ case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
+ case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
+ case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
+ case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
+ case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
+ default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
+ }
+
+ } else {
+
+ // initial setup
+ lastUserActivityTs = millis();
+
+ }
+
+ wakeUpCount++;
+ }
+
+ bool PowerManager::canEnterSleepMode() {
+ return (millis() - lastUserActivityTs > deepSleepTimeoutMs);
+ }
+
+ void PowerManager::sleep() {
+
+ // Configure wake up sources
+
+ // Wakeup on touchpad activity
+// TODO: touchSleepWakeUpEnable(wakeUpTouchPadPin, 40);
+
+ // Wakeup on external GPIO high
+ if (wakeUpGPIO != GPIO_NUM_NC) {
+#ifndef ESP32_C3
+ esp_sleep_enable_ext0_wakeup(wakeUpGPIO, ESP_EXT1_WAKEUP_ANY_HIGH);
+#else
+ esp_deep_sleep_enable_gpio_wakeup(wakeUpGPIO, ESP_GPIO_WAKEUP_GPIO_HIGH);
+#endif
+ }
+
+ // Wakeup after a given interval
+ if (wakeUpIntervalMs > 0) {
+ esp_sleep_enable_timer_wakeup(wakeUpIntervalMs * 1000);
+ }
+
+ // Enter deep sleep mode
+ esp_deep_sleep_start();
+// esp_light_sleep_start();
+
+ }
+
+}
+
+#endif
\ No newline at end of file
diff --git a/src/PowerManager.h b/src/PowerManager.h
new file mode 100644
index 0000000..16d5b0a
--- /dev/null
+++ b/src/PowerManager.h
@@ -0,0 +1,65 @@
+/*
+ * HomeGenie-Mini (c) 2018-2024 G-Labs
+ *
+ *
+ * This file is part of HomeGenie-Mini (HGM).
+ *
+ * HomeGenie-Mini is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HomeGenie-Mini 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HomeGenie-Mini. If not, see .
+ *
+ *
+ * Authors:
+ * - Generoso Martello
+ *
+ */
+
+#ifndef HOMEGENIE_MINI_POWERMANAGER_H
+#define HOMEGENIE_MINI_POWERMANAGER_H
+
+#include "Config.h"
+
+#ifdef ESP32
+
+namespace Service {
+
+ class PowerManager {
+ private:
+ static unsigned long lastUserActivityTs;
+ static unsigned long deepSleepTimeoutMs;
+ static unsigned long wakeUpIntervalMs;
+ static gpio_num_t wakeUpGPIO;
+ static touch_pad_t wakeUpTouchPadPin;
+ PowerManager() {}
+
+ public:
+ static void callback() {}
+ static void init();
+ static bool canEnterSleepMode();
+ static void sleep();
+ static void setActive() {
+ lastUserActivityTs = millis();
+ }
+ static void setWakeUpInterval(unsigned long ms) {
+ wakeUpIntervalMs = ms;
+ }
+ static void setWakeUpGPIO(gpio_num_t gpio) {
+ wakeUpGPIO = gpio;
+ }
+
+ };
+
+}
+
+#endif
+
+#endif //HOMEGENIE_MINI_POWERMANAGER_H
diff --git a/src/service/Module.cpp b/src/data/Module.cpp
similarity index 75%
rename from src/service/Module.cpp
rename to src/data/Module.cpp
index 21f2c5a..f30add9 100644
--- a/src/service/Module.cpp
+++ b/src/data/Module.cpp
@@ -4,6 +4,6 @@
#include "Module.h"
-namespace Service {
+namespace Data {
}
\ No newline at end of file
diff --git a/src/service/Module.h b/src/data/Module.h
similarity index 77%
rename from src/service/Module.h
rename to src/data/Module.h
index e2b037f..10cb790 100644
--- a/src/service/Module.h
+++ b/src/data/Module.h
@@ -5,12 +5,15 @@
#ifndef HOMEGENIE_MINI_MODULE_H
#define HOMEGENIE_MINI_MODULE_H
-#include "io/IOEvent.h"
-#include "net/NetManager.h"
+#include
-namespace Service {
+#include "Config.h"
+#include "net/TimeClient.h"
+#include "io/IOEventData.h"
- using namespace Net;
+namespace Data {
+
+ using namespace IO;
enum ModuleTypes {
Generic = 0,
@@ -26,10 +29,10 @@ namespace Service {
String value;
String updateTime;
void* data;
- IO::IOEventDataType dataType;
+ IOEventDataType dataType;
ModuleParameter() {
- updateTime = NetManager::getTimeClient().getFormattedDate();
+ updateTime = getFormattedDate();
}
ModuleParameter(String name): ModuleParameter() {
this->name = name;
@@ -43,12 +46,16 @@ namespace Service {
}
void setValue(const char* v) {
value = v;
- updateTime = NetManager::getTimeClient().getFormattedDate();
+ updateTime = getFormattedDate();
}
- void setData(void* d, IO::IOEventDataType t) {
+ void setData(void* d, IOEventDataType t) {
data = d;
dataType = t;
}
+ private:
+ String getFormattedDate() {
+ return Net::TimeClient::getTimeClient().getFormattedDate();
+ }
};
class Module {
@@ -59,7 +66,7 @@ namespace Service {
String name;
String description;
LinkedList properties;
- bool setProperty(String pn, String pv, void* data, IO::IOEventDataType dataType) {
+ bool setProperty(String pn, String pv, void* data, IOEventDataType dataType) {
for(int p = 0; p < properties.size(); p++) {
auto param = properties.get(p);
if (param->is(pn.c_str())) {
diff --git a/src/defs.h b/src/defs.h
index eedab2f..803ec5c 100644
--- a/src/defs.h
+++ b/src/defs.h
@@ -61,13 +61,17 @@
#define DISABLE_BLUETOOTH_CLASSIC
#define CONFIG_ServiceButtonPin 4
#define CONFIG_StatusLedPin 0
- #define CONFIG_GPIO_OUT {6}
+ #ifndef CONFIG_GPIO_OUT
+ #define CONFIG_GPIO_OUT {6}
+ #endif
#elif ESP32_S3
#undef DISABLE_BLUETOOTH_LE
#define DISABLE_BLUETOOTH_CLASSIC
#define CONFIG_ServiceButtonPin 21
#define CONFIG_StatusLedPin 33
- #define CONFIG_GPIO_OUT {15,16,17,18}
+ #ifndef CONFIG_GPIO_OUT
+ #define CONFIG_GPIO_OUT {15,16,17,18}
+ #endif
#else
#define DISABLE_BLUETOOTH_LE
// #define DISABLE_BLUETOOTH_CLASSIC
@@ -103,12 +107,12 @@
#define CONFIG_DISPLAY_DC 8
#define CONFIG_DISPLAY_CS 9
-#define CONFIG_DISPLAY_BL 2 // backlight
+#define CONFIG_DISPLAY_BL (2) // backlight
#define CONFIG_TOUCH_PORT 1
#define CONFIG_TOUCH_ADDRESS 0x15
-#define CONFIG_TOUCH_INT 5
+#define CONFIG_TOUCH_INT (-1) /* -1 disabled, or pin 5 */
#define CONFIG_TOUCH_SDA 6
#define CONFIG_TOUCH_SCL 7
#define CONFIG_TOUCH_RST 13
@@ -123,12 +127,12 @@
#define CONFIG_DISPLAY_DC 27
#define CONFIG_DISPLAY_CS 14
-#define CONFIG_DISPLAY_BL 32 // backlight
+#define CONFIG_DISPLAY_BL (32) // backlight
#define CONFIG_TOUCH_PORT 1
#define CONFIG_TOUCH_ADDRESS 0x15
-#define CONFIG_TOUCH_INT 35
+#define CONFIG_TOUCH_INT (-1) /* -1 disabled, or pin 35 */
#define CONFIG_TOUCH_SDA 25
#define CONFIG_TOUCH_SCL 26
#define CONFIG_TOUCH_RST 34
diff --git a/src/io/IOEvent.h b/src/io/IOEvent.h
index c88896e..f6ba4cd 100644
--- a/src/io/IOEvent.h
+++ b/src/io/IOEvent.h
@@ -32,19 +32,14 @@
#include "Config.h"
+#include "data/Module.h"
+#include "IOEventData.h"
+
namespace IO {
- class IIOEventSender;
+ using namespace Data;
- enum IOEventDataType {
- Undefined = 0,
- Number,
- Float,
- UnsignedNumber,
- SensorLight,
- SensorTemperature,
- SensorHumidity
- };
+ class IIOEventSender;
// IIOEventReceiver interface
class IIOEventReceiver {
@@ -55,22 +50,31 @@ namespace IO {
// IIOEventSender interface
class IIOEventSender {
public:
-// const uint8_t* getDomain() { return domain; }
-// const uint8_t* getAddress() { return address; }
virtual void begin() = 0;
void setEventReceiver(IIOEventReceiver *receiver) {
eventReceiver = receiver;
}
+
+ virtual void setModule(Module* m) {
+ module = m;
+ }
virtual void sendEvent(const char *domain, const char *address, const uint8_t *eventPath, void *eventData, IOEventDataType dataType) {
if (eventReceiver != nullptr) {
eventReceiver->onIOEvent(this, domain, address, eventPath, eventData, dataType);
lastEventMs = millis();
}
};
+ virtual void sendEvent(const uint8_t *eventPath, void *eventData, IOEventDataType dataType) {
+ if (eventReceiver != nullptr && module != nullptr) {
+ eventReceiver->onIOEvent(this, module->domain.c_str(), module->address.c_str(), eventPath, eventData, dataType);
+ lastEventMs = millis();
+ }
+ };
protected:
IIOEventReceiver *eventReceiver = nullptr;
unsigned long lastEventMs = 0;
+ const Module* module = nullptr;
};
}
diff --git a/src/io/IOEventData.h b/src/io/IOEventData.h
new file mode 100644
index 0000000..a602a2e
--- /dev/null
+++ b/src/io/IOEventData.h
@@ -0,0 +1,42 @@
+/*
+ * HomeGenie-Mini (c) 2018-2024 G-Labs
+ *
+ *
+ * This file is part of HomeGenie-Mini (HGM).
+ *
+ * HomeGenie-Mini is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HomeGenie-Mini 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HomeGenie-Mini. If not, see .
+ *
+ *
+ * Authors:
+ * - Generoso Martello
+ *
+ */
+
+#ifndef HOMEGENIE_MINI_IOEVENTDATA_H
+#define HOMEGENIE_MINI_IOEVENTDATA_H
+
+namespace IO {
+
+ enum IOEventDataType {
+ Undefined = 0,
+ Number,
+ Float,
+ UnsignedNumber,
+ SensorLight,
+ SensorTemperature,
+ SensorHumidity
+ };
+}
+
+#endif //HOMEGENIE_MINI_IOEVENTDATA_H
diff --git a/src/io/IOEventPaths.h b/src/io/IOEventPaths.h
index 7489c04..db51f41 100644
--- a/src/io/IOEventPaths.h
+++ b/src/io/IOEventPaths.h
@@ -38,6 +38,8 @@ namespace IO {
const char Sensor_Luminance[] PROGMEM = "Sensor.Luminance";
const char Sensor_Temperature[] PROGMEM = "Sensor.Temperature";
const char Sensor_Humidity[] PROGMEM = "Sensor.Humidity";
+ const char Sensor_MotionDetect[] PROGMEM = "Sensor.MotionDetect";
+ const char Status_Battery[] PROGMEM = "Status.Battery";
const char System_BytesFree[] PROGMEM = "System.BytesFree";
}
}
diff --git a/src/io/Logger.cpp b/src/io/Logger.cpp
index c47d1b1..c0bebed 100644
--- a/src/io/Logger.cpp
+++ b/src/io/Logger.cpp
@@ -29,7 +29,7 @@
#include "Logger.h"
-#include "net/NetManager.h"
+#include "net/TimeClient.h"
namespace IO {
@@ -112,7 +112,7 @@ namespace IO {
}
void Logger::timestamp() {
- Serial.printf("[%s] ", Net::NetManager::getTimeClient().getFormattedDate().c_str());
+ Serial.printf("[%s] ", Net::TimeClient::getTimeClient().getFormattedDate().c_str());
}
void Logger::trace(const char *s, ...) {
diff --git a/src/net/HTTPServer.cpp b/src/net/HTTPServer.cpp
index 369a7d9..fa14e5e 100644
--- a/src/net/HTTPServer.cpp
+++ b/src/net/HTTPServer.cpp
@@ -164,9 +164,9 @@ namespace Net {
void HTTPServer::serverSentEvent(WiFiClient &client, String &domain, String &address, String &event, String &value) {
// id: 1548081759906.19
// data: {"Timestamp":"2019-01-21T14:42:39.906194Z","UnixTimestamp":1548081759906.19,"Domain":"HomeAutomation.ZWave","Source":"7","Description":"ZWave Node","Property":"Meter.Watts","Value":0}
- String date = Net::NetManager::getTimeClient().getFormattedDate();
- unsigned long epoch = Net::NetManager::getTimeClient().getEpochTime();
- int ms = Net::NetManager::getTimeClient().getMilliseconds();
+ String date = Net::TimeClient::getTimeClient().getFormattedDate();
+ unsigned long epoch = Net::TimeClient::getTimeClient().getEpochTime();
+ int ms = Net::TimeClient::getTimeClient().getMilliseconds();
client.printf("id: %lu\n", millis());
client.printf(R"(data: {"Timestamp":"%s","UnixTimestamp":%lu%03d,"Description":"","Domain":"%s","Source":"%s","Property":"%s","Value":"%s"})",
date.c_str(), epoch, ms, domain.c_str(), address.c_str(), event.c_str(), value.c_str());
diff --git a/src/net/NetManager.cpp b/src/net/NetManager.cpp
index 64e3b59..82ed594 100644
--- a/src/net/NetManager.cpp
+++ b/src/net/NetManager.cpp
@@ -33,16 +33,6 @@ namespace Net {
using namespace IO;
- // Time sync
- WiFiUDP ntpUDP;
- NTPClient timeClient(ntpUDP);
-#ifdef ESP32
- bool rtcTimeSet = (esp_reset_reason() != ESP_RST_POWERON && esp_reset_reason() != ESP_RST_UNKNOWN);
-#else
- bool rtcTimeSet = false;
-#endif
- long lastTimeCheck = -100000;
-
NetManager::NetManager() {
// TODO: ...
}
@@ -125,15 +115,8 @@ namespace Net {
mqttServer = new MQTTServer();
mqttServer->begin();
#endif
-
- // Initialize a NTPClient to get time
- timeClient.begin();
- // Set offset time in seconds to adjust for your timezone, for example:
- // GMT +1 = 3600
- // GMT +8 = 28800
- // GMT -1 = -3600
- // GMT 0 = 0
- timeClient.setTimeOffset(0);
+ timeClient = new TimeClient();
+ timeClient->begin();
}
@@ -144,35 +127,6 @@ namespace Net {
webSocket->loop();
}
- if (rtcTimeSet) {
-#ifdef ESP32
- if (millis() - lastTimeCheck > 60000) {
- lastTimeCheck = millis();
- if (!timeClient.isUpdated()) {
- // sync TimeClient with RTC
- timeClient.setEpochTime(Config::getRTC()->getLocalEpoch());
- Logger::info("| - TimeClient: synced with RTC");
- }
- }
-#endif
- } else if (WiFi.isConnected() && millis() - lastTimeCheck > 60000) {
- lastTimeCheck = millis();
- if (!timeClient.isUpdated()) {
- if (timeClient.update()) {
- // TimeClient synced with NTP
-#ifdef ESP32
- Config::getRTC()->setTime(timeClient.getEpochTime(), 0);
- rtcTimeSet = true;
- Logger::info("| - RTC updated via TimeClient (NTP)");
-#endif
- } else {
- // NTP Update failed
- digitalWrite(Config::StatusLedPin, HIGH);
- Logger::warn("| x TimeClient: NTP update failed!");
- }
- }
- }
-
Logger::verbose("%s loop() << END", NETMANAGER_LOG_PREFIX);
}
@@ -200,10 +154,6 @@ namespace Net {
return *webSocket;
}
- NTPClient& NetManager::getTimeClient() {
- return timeClient;
- }
-
void NetManager::setRequestHandler(NetRequestHandler* handler) {
netRequestHandler = handler;
}
diff --git a/src/net/NetManager.h b/src/net/NetManager.h
index 470177a..92faf62 100644
--- a/src/net/NetManager.h
+++ b/src/net/NetManager.h
@@ -35,12 +35,9 @@
#else
#include
#endif
-#include
#include
-#include
#include
-#include
#include
#include
@@ -56,6 +53,8 @@
#include
#endif
+#include "TimeClient.h"
+
#define NETMANAGER_LOG_PREFIX "@Net::NetManager"
namespace Net {
@@ -148,7 +147,6 @@ namespace Net {
MQTTServer& getMQTTServer();
#endif
WebSocketsServer& getWebSocketServer();
- static NTPClient& getTimeClient();
void setRequestHandler(NetRequestHandler *);
@@ -181,6 +179,8 @@ namespace Net {
WebSocketsServer *webSocket;
NetRequestHandler* netRequestHandler;
+ TimeClient* timeClient;
+
};
}
diff --git a/src/net/TimeClient.cpp b/src/net/TimeClient.cpp
new file mode 100644
index 0000000..4e63dd9
--- /dev/null
+++ b/src/net/TimeClient.cpp
@@ -0,0 +1,85 @@
+/*
+ * HomeGenie-Mini (c) 2018-2024 G-Labs
+ *
+ *
+ * This file is part of HomeGenie-Mini (HGM).
+ *
+ * HomeGenie-Mini is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HomeGenie-Mini 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HomeGenie-Mini. If not, see .
+ *
+ *
+ * Authors:
+ * - Generoso Martello
+ *
+ *
+ * Releases:
+ * - 2019-01-10 Initial release
+ *
+ */
+
+#include "TimeClient.h"
+
+namespace Net {
+ // Time sync
+ WiFiUDP ntpUDP;
+ NTPClient timeClient(ntpUDP);
+
+ void TimeClient::begin() {
+ // Initialize a NTPClient to get time
+ timeClient.begin();
+ // Set offset time in seconds to adjust for your timezone, for example:
+ // GMT +1 = 3600
+ // GMT +8 = 28800
+ // GMT -1 = -3600
+ // GMT 0 = 0
+ timeClient.setTimeOffset(0);
+ }
+
+ void TimeClient::loop() {
+
+ if (rtcTimeSet) {
+#ifdef ESP32
+ if (millis() - lastTimeCheck > 60000) {
+ lastTimeCheck = millis();
+ if (!timeClient.isUpdated()) {
+ // sync TimeClient with RTC
+ timeClient.setEpochTime(Config::getRTC()->getLocalEpoch());
+ Logger::info("| - TimeClient: synced with RTC");
+ }
+ }
+#endif
+ } else if (WiFi.isConnected() && millis() - lastTimeCheck > 60000) {
+ lastTimeCheck = millis();
+ if (!timeClient.isUpdated()) {
+ if (timeClient.update()) {
+ // TimeClient synced with NTP
+#ifdef ESP32
+ Config::getRTC()->setTime(timeClient.getEpochTime(), 0);
+ rtcTimeSet = true;
+ Logger::info("| - RTC updated via TimeClient (NTP)");
+#endif
+ } else {
+ // NTP Update failed
+ digitalWrite(Config::StatusLedPin, HIGH);
+ Logger::warn("| x TimeClient: NTP update failed!");
+ }
+ }
+ }
+
+ }
+
+ NTPClient& TimeClient::getTimeClient() {
+ return timeClient;
+ }
+
+}
diff --git a/src/net/TimeClient.h b/src/net/TimeClient.h
new file mode 100644
index 0000000..91daa51
--- /dev/null
+++ b/src/net/TimeClient.h
@@ -0,0 +1,64 @@
+/*
+ * HomeGenie-Mini (c) 2018-2024 G-Labs
+ *
+ *
+ * This file is part of HomeGenie-Mini (HGM).
+ *
+ * HomeGenie-Mini is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HomeGenie-Mini 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HomeGenie-Mini. If not, see .
+ *
+ *
+ * Authors:
+ * - Generoso Martello
+ *
+ */
+
+#ifndef HOMEGENIE_MINI_TIMECLIENT_H
+#define HOMEGENIE_MINI_TIMECLIENT_H
+
+#include "Config.h"
+
+#include
+#ifdef ESP8266
+#include
+#else
+#include
+#endif
+#include
+
+#include "io/Logger.h"
+#include "Task.h"
+
+namespace Net {
+ using namespace IO;
+
+ class TimeClient: Task {
+ public:
+ TimeClient() {
+ setLoopInterval(1000);
+ }
+ void begin();
+ void loop() override;
+ static NTPClient& getTimeClient();
+ private:
+#ifdef ESP32
+ bool rtcTimeSet = (esp_reset_reason() != ESP_RST_POWERON && esp_reset_reason() != ESP_RST_UNKNOWN);
+#else
+ bool rtcTimeSet = false;
+#endif
+ long lastTimeCheck = -100000;
+ };
+
+}
+
+#endif //HOMEGENIE_MINI_TIMECLIENT_H
diff --git a/src/service/EventRouter.cpp b/src/service/EventRouter.cpp
index 335e340..b40dc15 100644
--- a/src/service/EventRouter.cpp
+++ b/src/service/EventRouter.cpp
@@ -34,14 +34,16 @@
namespace Service {
void EventRouter::loop() {
+ if (!WiFi.isConnected()) return;
+
// MQTT & SSE Events Queue (dequeue)
for (int i = 0; i < eventsQueue.size(); i++) {
- // route event through MQTT
+
auto m = eventsQueue.pop();
- Logger::verbose(":%s dequeued event >> [domain '%s' address '%s' event '%s']", EVENTROUTER_NS_PREFIX, m.domain.c_str(), m.sender.c_str(), m.event.c_str());
+ Logger::info(":%s dequeued event >> [domain '%s' address '%s' event '%s']", EVENTROUTER_NS_PREFIX, m.domain.c_str(), m.sender.c_str(), m.event.c_str());
#ifndef DISABLE_MQTT
// MQTT
- auto date = NetManager::getTimeClient().getFormattedDate();
+ auto date = TimeClient::getTimeClient().getFormattedDate();
auto topic = String(String(CONFIG_SYSTEM_NAME) + "/" + m.domain + "/" + m.sender + "/event");
auto details = Service::HomeGenie::createModuleParameter(m.event.c_str(), m.value.c_str(), date.c_str());
netManager->getMQTTServer().broadcast(&topic, &details);
@@ -51,8 +53,8 @@ namespace Service {
// WS
if (netManager->getWebSocketServer().connectedClients() > 0) {
- unsigned long epoch = Net::NetManager::getTimeClient().getEpochTime();
- int ms = Net::NetManager::getTimeClient().getMilliseconds();
+ unsigned long epoch = TimeClient::getTimeClient().getEpochTime();
+ int ms = TimeClient::getTimeClient().getMilliseconds();
/*
// Send as clear text
int sz = 1+snprintf(nullptr, 0, R"(data: {"Timestamp":"%s","UnixTimestamp":%lu%03d,"Description":"","Domain":"%s","Source":"%s","Property":"%s","Value":"%s"})",
@@ -74,7 +76,7 @@ namespace Service {
};
packer.packTimestamp(t);
auto epochs = String(epoch) + ms;
- packer.packFloat((Net::NetManager::getTimeClient().getEpochTime() * 1000.0f) + ms);
+ packer.packFloat((TimeClient::getTimeClient().getEpochTime() * 1000.0f) + ms);
packer.pack(m.domain.c_str());
packer.pack(m.sender.c_str());
packer.pack("");
diff --git a/src/service/api/APIHandler.h b/src/service/api/APIHandler.h
index dac4b02..7d3b03a 100644
--- a/src/service/api/APIHandler.h
+++ b/src/service/api/APIHandler.h
@@ -31,7 +31,7 @@
#define HOMEGENIE_MINI_APIHANDLER_H
#include "io/IOEvent.h"
-#include "service/Module.h"
+#include "data/Module.h"
#include "APIRequest.h"
#include "net/NetManager.h"
@@ -39,6 +39,7 @@
namespace Service { namespace API {
using namespace IO;
+ using namespace Data;
using namespace Net;
using namespace Service;
diff --git a/src/ui/Dashboard.cpp b/src/ui/Dashboard.cpp
index 829a7d4..5078b5f 100644
--- a/src/ui/Dashboard.cpp
+++ b/src/ui/Dashboard.cpp
@@ -92,6 +92,7 @@ void Dashboard::loop() {
activity->pointerMove(tp.x, tp.y);
}
}
+ Service::PowerManager::setActive();
} else if (pointerDown) {
pointerDown = false;
gestureHelper->pointerUp(tp.x, tp.y);
@@ -160,25 +161,10 @@ void Dashboard::onPan(PanEvent e) {
activity->pan(e);
if (activityList.size() > 1 && (e.touchPoint.direction == TOUCH_DIRECTION_LEFT || e.touchPoint.direction == TOUCH_DIRECTION_RIGHT)) {
- int nextActivityIndex = 0;
-
- if (e.touchPoint.shiftX > 0) {
- if (currentActivityIndex + 1 < activityList.size()) {
- nextActivityIndex = currentActivityIndex + 1;
- }
- } else {
- if (currentActivityIndex - 1 >= 0) {
- nextActivityIndex = currentActivityIndex - 1;
- } else {
- nextActivityIndex = activityList.size() - 1;
- }
- }
-
- auto next = activityList.get(nextActivityIndex);
+ auto next = (e.touchPoint.shiftX > 0) ? getNextActivity() : getPreviousActivity();
if (next != nextActivity && nextActivity != nullptr) {
nextActivity->pause();
}
-
nextActivity = next;
nextActivity->resume();
nextActivity->setDrawOffset(e.touchPoint.shiftX + (float)display->width()*(e.touchPoint.shiftX > 0 ? -1 : 1), 0);
@@ -195,5 +181,21 @@ void Dashboard::onTouch(PointerEvent e) {
void Dashboard::onRelease(PointerEvent e) {
}
+Activity* Dashboard::getNextActivity() {
+ int nextActivityIndex = 0;
+ if (currentActivityIndex + 1 < activityList.size()) {
+ nextActivityIndex = currentActivityIndex + 1;
+ }
+ return activityList.get(nextActivityIndex);
+}
+Activity* Dashboard::getPreviousActivity() {
+ unsigned int prevActivityIndex;
+ if (currentActivityIndex - 1 >= 0) {
+ prevActivityIndex = currentActivityIndex - 1;
+ } else {
+ prevActivityIndex = activityList.size() - 1;
+ }
+ return activityList.get(prevActivityIndex);
+}
#endif // DISABLE_UI
diff --git a/src/ui/Dashboard.h b/src/ui/Dashboard.h
index 2458197..efa6316 100644
--- a/src/ui/Dashboard.h
+++ b/src/ui/Dashboard.h
@@ -34,6 +34,7 @@
#include
#include "Task.h"
+#include "PowerManager.h"
#include "io/Logger.h"
#include "drivers/RoundDisplay.h"
@@ -72,6 +73,8 @@ class Dashboard: public Task, public GestureListener {
Activity* getForegroundActivity();
void setForegroundActivity(Activity*);
+ Activity* getNextActivity();
+ Activity* getPreviousActivity();
void addActivity(Activity* activity);
void onTap(PointerEvent e) override;
diff --git a/src/ui/drivers/RoundDisplay.cpp b/src/ui/drivers/RoundDisplay.cpp
index 400b3ba..3e911c9 100644
--- a/src/ui/drivers/RoundDisplay.cpp
+++ b/src/ui/drivers/RoundDisplay.cpp
@@ -90,8 +90,8 @@ namespace UI { namespace Drivers {
cfg.x_max = 239;
cfg.y_min = 0;
cfg.y_max = 239;
- cfg.pin_int = CONFIG_TOUCH_INT; // N.C.
- //cfg.bus_shared = true;
+ cfg.pin_int = CONFIG_TOUCH_INT;
+ cfg.bus_shared = true;
cfg.offset_rotation = 0;
// SPI
@@ -108,7 +108,7 @@ namespace UI { namespace Drivers {
cfg.pin_sda = CONFIG_TOUCH_SDA;
cfg.pin_scl = CONFIG_TOUCH_SCL;
cfg.pin_rst = CONFIG_TOUCH_RST;
- //cfg.freq = 400000;
+ cfg.freq = 400000;
_touch_instance.config(cfg);
_panel_instance.setTouch(&_touch_instance);