diff --git a/src/helpers/sensors/EnvironmentSensorManager.cpp b/src/helpers/sensors/EnvironmentSensorManager.cpp index c95b1828..d6c1254d 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.cpp +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -21,6 +21,22 @@ static Adafruit_AHTX0 AHTX0; static Adafruit_BME280 BME280; #endif +#if ENV_INCLUDE_BME680 +#ifndef TELEM_BME680_ADDRESS +#define TELEM_BME680_ADDRESS 0x76 // BME680 environmental sensor I2C address +#endif +static Bsec2 BME680; +#define SAMPLING_RATE BSEC_SAMPLE_RATE_ULP +static float rawPressure = 0; +static float rawTemperature = 0; +static float compTemperature = 0; +static float rawHumidity = 0; +static float compHumidity = 0; +static float readIAQ = 0; +static float readStaticIAQ = 0; +static float readCO2 = 0; +#endif + #if ENV_INCLUDE_BMP280 #ifndef TELEM_BMP280_ADDRESS #define TELEM_BMP280_ADDRESS 0x76 // BMP280 environmental sensor I2C address @@ -109,6 +125,50 @@ bool EnvironmentSensorManager::begin() { } #endif + #if ENV_INCLUDE_BME680 + bsecSensor sensorList[5] = { + BSEC_OUTPUT_IAQ, + // BSEC_OUTPUT_RAW_TEMPERATURE, + BSEC_OUTPUT_RAW_PRESSURE, + // BSEC_OUTPUT_RAW_HUMIDITY, + // BSEC_OUTPUT_RAW_GAS, + // BSEC_OUTPUT_STABILIZATION_STATUS, + // BSEC_OUTPUT_RUN_IN_STATUS, + BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE, + BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY, + // BSEC_OUTPUT_STATIC_IAQ, + BSEC_OUTPUT_CO2_EQUIVALENT, + // BSEC_OUTPUT_BREATH_VOC_EQUIVALENT, + // BSEC_OUTPUT_GAS_PERCENTAGE, + // BSEC_OUTPUT_COMPENSATED_GAS + }; + + if(!BME680.begin(TELEM_BME680_ADDRESS, Wire)){ + checkBMEStatus(BME680); + BME680_initialized = false; + return false; + } + + MESH_DEBUG_PRINTLN("Found BME680 at address: %02X", TELEM_BME680_ADDRESS); + BME680_initialized = true; + + if (SAMPLING_RATE == BSEC_SAMPLE_RATE_ULP) + { + BME680.setTemperatureOffset(BSEC_SAMPLE_RATE_ULP); + } + else if (SAMPLING_RATE == BSEC_SAMPLE_RATE_LP) + { + BME680.setTemperatureOffset(TEMP_OFFSET_LP); + } + + if (!BME680.updateSubscription(sensorList, ARRAY_LEN(sensorList), SAMPLING_RATE)) + { + checkBMEStatus(BME680); + } + + BME680.attachCallback(newDataCallback); + #endif + #if ENV_INCLUDE_BMP280 if (BMP280.begin(TELEM_BMP280_ADDRESS)) { MESH_DEBUG_PRINTLN("Found BMP280 at address: %02X", TELEM_BMP280_ADDRESS); @@ -215,6 +275,16 @@ bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, Cayen } #endif + #if ENV_INCLUDE_BME680 + if (BME680_initialized) { + telemetry.addTemperature(TELEM_CHANNEL_SELF, compTemperature); + telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, compHumidity); + telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, rawPressure); + telemetry.addGenericSensor(TELEM_CHANNEL_SELF+1, readIAQ); + telemetry.addConcentration(TELEM_CHANNEL_SELF+1, readCO2); + } + #endif + #if ENV_INCLUDE_BMP280 if (BMP280_initialized) { telemetry.addTemperature(TELEM_CHANNEL_SELF, BMP280.readTemperature()); @@ -289,7 +359,6 @@ bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, Cayen return true; } - int EnvironmentSensorManager::getNumSettings() const { #if ENV_INCLUDE_GPS return gps_detected ? 1 : 0; // only show GPS setting if GPS is detected @@ -329,6 +398,96 @@ bool EnvironmentSensorManager::setSettingValue(const char* name, const char* val return false; // not supported } +#if ENV_INCLUDE_BME680 +void EnvironmentSensorManager::checkBMEStatus(Bsec2 bsec) { + if (bsec.status < BSEC_OK) + { + MESH_DEBUG_PRINTLN("BSEC error code : %f", float(bsec.status)); + } + else if (bsec.status > BSEC_OK) + { + MESH_DEBUG_PRINTLN("BSEC warning code : %f", float(bsec.status)); + } + + if (bsec.sensor.status < BME68X_OK) + { + MESH_DEBUG_PRINTLN("BME68X error code : %f", bsec.sensor.status); + } + else if (bsec.sensor.status > BME68X_OK) + { + MESH_DEBUG_PRINTLN("BME68X warning code : %f", bsec.sensor.status); + } +} + +void EnvironmentSensorManager::newDataCallback(const bme68xData data, const bsecOutputs outputs, Bsec2 bsec) { + if (!outputs.nOutputs) { + MESH_DEBUG_PRINTLN("No new data to report out"); + return; + } + + MESH_DEBUG_PRINTLN("BSEC outputs:\n\tTime stamp = %f", (int) (outputs.output[0].time_stamp / INT64_C(1000000))); + for (uint8_t i = 0; i < outputs.nOutputs; i++) { + const bsecData output = outputs.output[i]; + switch (output.sensor_id) + { + case BSEC_OUTPUT_IAQ: + readIAQ = output.signal; + MESH_DEBUG_PRINTLN("\tIAQ = %f", output.signal); + MESH_DEBUG_PRINTLN("\tIAQ accuracy = %f", output.accuracy); + break; + case BSEC_OUTPUT_RAW_TEMPERATURE: + rawTemperature = output.signal; + MESH_DEBUG_PRINTLN("\tTemperature = %f", output.signal); + break; + case BSEC_OUTPUT_RAW_PRESSURE: + rawPressure = output.signal; + MESH_DEBUG_PRINTLN("\tPressure = %f", output.signal); + break; + case BSEC_OUTPUT_RAW_HUMIDITY: + rawHumidity = output.signal; + MESH_DEBUG_PRINTLN("\tHumidity = %f", output.signal); + break; + case BSEC_OUTPUT_RAW_GAS: + MESH_DEBUG_PRINTLN("\tGas resistance = %f", output.signal); + break; + case BSEC_OUTPUT_STABILIZATION_STATUS: + MESH_DEBUG_PRINTLN("\tStabilization status = %f", output.signal); + break; + case BSEC_OUTPUT_RUN_IN_STATUS: + MESH_DEBUG_PRINTLN("\tRun in status = %f", output.signal); + break; + case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE: + compTemperature = output.signal; + MESH_DEBUG_PRINTLN("\tCompensated temperature = %f", output.signal); + break; + case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY: + compHumidity = output.signal; + MESH_DEBUG_PRINTLN("\tCompensated humidity = %f", output.signal); + break; + case BSEC_OUTPUT_STATIC_IAQ: + readStaticIAQ = output.signal; + MESH_DEBUG_PRINTLN("\tStatic IAQ = %f", output.signal); + break; + case BSEC_OUTPUT_CO2_EQUIVALENT: + readCO2 = output.signal; + MESH_DEBUG_PRINTLN("\tCO2 Equivalent = %f", output.signal); + break; + case BSEC_OUTPUT_BREATH_VOC_EQUIVALENT: + MESH_DEBUG_PRINTLN("\tbVOC equivalent = %f", output.signal); + break; + case BSEC_OUTPUT_GAS_PERCENTAGE: + MESH_DEBUG_PRINTLN("\tGas percentage = %f", output.signal); + break; + case BSEC_OUTPUT_COMPENSATED_GAS: + MESH_DEBUG_PRINTLN("\tCompensated gas = %f", output.signal); + break; + default: + break; + } + } +} +#endif + #if ENV_INCLUDE_GPS void EnvironmentSensorManager::initBasicGPS() { @@ -474,13 +633,27 @@ void EnvironmentSensorManager::stop_gps() { MESH_DEBUG_PRINTLN("Stop GPS is N/A on this board. Actual GPS state unchanged"); } +#endif +#ifndef ENV_INCLUDE_GPS && defined(ENV_INCLUDE_BME680) //if there is no gps but there is bme680 void EnvironmentSensorManager::loop() { - static long next_gps_update = 0; + static long next_update = 0; + + if(BME680_initialized){ + if (!BME680.run()){ + checkBMEStatus(BME680); + } + } + next_update = millis() + 1000; + } +#endif +#if defined(ENV_INCLUDE_GPS) && defined(ENV_INCLUDE_BME680) //if there is both gps and bme680 +void EnvironmentSensorManager::loop() { + static long next_update = 0; _location->loop(); - if (millis() > next_gps_update) { + if (millis() > next_update) { if(gps_active){ #ifndef RAK_BOARD if (_location->isValid()) { @@ -499,11 +672,46 @@ void EnvironmentSensorManager::loop() { node_lon = ((double)_location->getLongitude())/1000000.; MESH_DEBUG_PRINTLN("lat %f lon %f", node_lat, node_lon); } - //else - //MESH_DEBUG_PRINTLN("No valid GPS data"); #endif } - next_gps_update = millis() + 1000; + + if(BME680_initialized){ + if (!BME680.run()){ + checkBMEStatus(BME680); + } + } + next_update = millis() + 1000; } } #endif +#ifndef ENV_INCLUDE_BME680 && defined(ENV_INCLUDE_GPS) //if there is no bme680 but there is gps +void EnvironmentSensorManager::loop() { + static long next_update = 0; + + _location->loop(); + + if (millis() > next_update) { + if(gps_active){ + #ifndef RAK_BOARD + if (_location->isValid()) { + node_lat = ((double)_location->getLatitude())/1000000.; + node_lon = ((double)_location->getLongitude())/1000000.; + MESH_DEBUG_PRINTLN("lat %f lon %f", node_lat, node_lon); + } + #else + if(i2cGPSFlag){ + node_lat = ((double)ublox_GNSS.getLatitude())/10000000.; + node_lon = ((double)ublox_GNSS.getLongitude())/10000000.; + MESH_DEBUG_PRINTLN("lat %f lon %f", node_lat, node_lon); + } + else if (serialGPSFlag && _location->isValid()) { + node_lat = ((double)_location->getLatitude())/1000000.; + node_lon = ((double)_location->getLongitude())/1000000.; + MESH_DEBUG_PRINTLN("lat %f lon %f", node_lat, node_lon); + } + #endif + } + next_update = millis() + 1000; + } +} +#endif \ No newline at end of file diff --git a/src/helpers/sensors/EnvironmentSensorManager.h b/src/helpers/sensors/EnvironmentSensorManager.h index 63c56643..9f95e6ad 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.h +++ b/src/helpers/sensors/EnvironmentSensorManager.h @@ -4,6 +4,10 @@ #include #include +#ifdef ENV_INCLUDE_BME680 +#include +#endif + class EnvironmentSensorManager : public SensorManager { protected: int next_available_channel = TELEM_CHANNEL_SELF + 1; @@ -11,6 +15,7 @@ class EnvironmentSensorManager : public SensorManager { bool AHTX0_initialized = false; bool BME280_initialized = false; bool BMP280_initialized = false; + bool BME680_initialized = false; bool INA3221_initialized = false; bool INA219_initialized = false; bool SHTC3_initialized = false; @@ -32,6 +37,10 @@ class EnvironmentSensorManager : public SensorManager { #endif #endif + #if ENV_INCLUDE_BME680 + static void checkBMEStatus(Bsec2 bsec); + static void newDataCallback(const bme68xData data, const bsecOutputs outputs, Bsec2 bsec); + #endif public: #if ENV_INCLUDE_GPS @@ -41,7 +50,7 @@ class EnvironmentSensorManager : public SensorManager { #endif bool begin() override; bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override; - #if ENV_INCLUDE_GPS + #if ENV_INCLUDE_GPS || ENV_INCLUDE_BME680 void loop() override; #endif int getNumSettings() const override; diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini index 33d3fbc8..ba18b9cd 100644 --- a/variants/rak4631/platformio.ini +++ b/variants/rak4631/platformio.ini @@ -18,13 +18,16 @@ build_flags = ${nrf52_base.build_flags} -D LORA_TX_POWER=22 -D SX126X_CURRENT_LIMIT=140 -D SX126X_RX_BOOSTED_GAIN=1 + -D PIN_BUZZER=WB_IO5 ;for socket D on RAK19007 and RAK19003 -D ENV_INCLUDE_GPS=1 -D ENV_INCLUDE_SHTC3=1 -D ENV_INCLUDE_LPS22HB=1 -D ENV_INCLUDE_INA219=1 + -D ENV_INCLUDE_BME680=1 build_src_filter = ${nrf52_base.build_src_filter} +<../variants/rak4631> + + + lib_deps = ${nrf52_base.lib_deps} adafruit/Adafruit SSD1306 @ ^2.5.13 @@ -33,6 +36,9 @@ lib_deps = arduino-libraries/Arduino_LPS22HB@^1.0.2 adafruit/Adafruit INA219@^1.2.3 sparkfun/SparkFun u-blox GNSS Arduino Library@^2.2.27 + https://github.com/boschsensortec/Bosch-BSEC2-Library + https://github.com/boschsensortec/Bosch-BME68x-Library + end2endzone/NonBlockingRTTTL@^1.3.0 [env:RAK_4631_Repeater] extends = rak4631