Merge pull request #2634 from NickDunklee/bme680-fixes-consolidation

feat: Integrate BME680 Bosch BSEC support for RAK4631
This commit is contained in:
ripplebiz
2026-06-01 13:35:32 +10:00
committed by GitHub
4 changed files with 135 additions and 6 deletions
@@ -12,6 +12,31 @@
// Sensor library includes and static driver instances
// ============================================================
#if ENV_INCLUDE_BME680_BSEC
#ifndef TELEM_BME680_ADDRESS
#define TELEM_BME680_ADDRESS 0x76
#endif
#define TELEM_BME680_SEALEVELPRESSURE_HPA (1013.25)
#include <bsec.h>
#include <Adafruit_LittleFS.h>
#include <InternalFileSystem.h>
static const uint8_t bsec_config_iaq[] = {
#include "config/generic_33v_3s_28d/bsec_iaq.txt" // 3.3v, LP, 28 day background calibration window
};
static Bsec bsec_iaq;
static float bsec_temperature = 0;
static float bsec_humidity = 0;
static float bsec_pressure_hpa = 0;
static float bsec_iaq_val = 0;
static uint8_t bsec_accuracy = 0;
static bool bsec_active = false;
static bool bsec_data_ready = false;
static bool bsec_first_save_done = false;
static uint32_t bsec_last_save_ms = 0;
#define BSEC_STATE_FILE "/bsec_state.bin"
#define BSEC_SAVE_INTERVAL_MS (8UL * 60 * 60 * 1000) // 8 hour state-save interval
#endif
#ifdef ENV_INCLUDE_BME680
#ifndef TELEM_BME680_ADDRESS
#define TELEM_BME680_ADDRESS 0x76
@@ -235,9 +260,10 @@ static void query_bme680(uint8_t ch, uint8_t, CayenneLPP& lpp) {
if (BME680.performReading()) {
lpp.addTemperature(ch, BME680.temperature);
lpp.addRelativeHumidity(ch, BME680.humidity);
lpp.addBarometricPressure(ch, BME680.pressure / 100);
lpp.addAltitude(ch, 44330.0 * (1.0 - pow((BME680.pressure / 100) / TELEM_BME680_SEALEVELPRESSURE_HPA, 0.1903)));
lpp.addAnalogInput(ch, BME680.gas_resistance);
const float pressure_hpa = BME680.pressure / 100.0f;
lpp.addBarometricPressure(ch, pressure_hpa);
lpp.addAltitude(ch, 44330.0f * (1.0f - powf(pressure_hpa / (float)TELEM_BME680_SEALEVELPRESSURE_HPA, 0.1903f)));
lpp.addGenericSensor(ch, BME680.gas_resistance);
}
}
#endif
@@ -449,6 +475,62 @@ static void query_rak12035(uint8_t ch, uint8_t sub_ch, CayenneLPP& lpp) {
}
#endif
#if ENV_INCLUDE_BME680_BSEC
static void bsec_load_state() {
using namespace Adafruit_LittleFS_Namespace;
File f = InternalFS.open(BSEC_STATE_FILE, FILE_O_READ);
if (!f) return;
uint8_t state[BSEC_MAX_STATE_BLOB_SIZE];
f.read(state, BSEC_MAX_STATE_BLOB_SIZE);
f.close();
bsec_iaq.setState(state);
}
static void bsec_save_state() {
using namespace Adafruit_LittleFS_Namespace;
uint8_t state[BSEC_MAX_STATE_BLOB_SIZE];
bsec_iaq.getState(state);
InternalFS.remove(BSEC_STATE_FILE);
File f = InternalFS.open(BSEC_STATE_FILE, FILE_O_WRITE);
if (!f) return;
f.write(state, BSEC_MAX_STATE_BLOB_SIZE);
f.close();
}
static uint8_t init_bme680_bsec(TwoWire* wire, uint8_t addr) {
bsec_iaq.begin(addr, *wire);
if (bsec_iaq.bsecStatus != BSEC_OK) return 0;
bsec_iaq.setConfig(bsec_config_iaq);
if (bsec_iaq.bsecStatus != BSEC_OK) return 0;
bsec_virtual_sensor_t outputs[] = {
BSEC_OUTPUT_IAQ,
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
BSEC_OUTPUT_RAW_PRESSURE,
BSEC_OUTPUT_STABILIZATION_STATUS,
BSEC_OUTPUT_RUN_IN_STATUS,
};
bsec_iaq.updateSubscription(outputs, 6, BSEC_SAMPLE_RATE_LP);
if (bsec_iaq.bsecStatus != BSEC_OK) return 0;
bsec_load_state();
bsec_active = true;
return 1;
}
static void query_bme680_bsec(uint8_t ch, uint8_t, CayenneLPP& lpp) {
if (!bsec_data_ready) return;
lpp.addTemperature(ch, bsec_temperature);
lpp.addRelativeHumidity(ch, bsec_humidity);
lpp.addBarometricPressure(ch, bsec_pressure_hpa);
lpp.addAltitude(ch, 44330.0f * (1.0f - powf(bsec_pressure_hpa / (float)TELEM_BME680_SEALEVELPRESSURE_HPA, 0.1903f)));
lpp.addGenericSensor(ch, (uint16_t)bsec_iaq_val);
lpp.addAnalogInput(ch, (float)bsec_accuracy);
}
#endif
// ============================================================
// Sensor descriptor table
//
@@ -476,6 +558,9 @@ static const SensorDef SENSOR_TABLE[] = {
#ifdef ENV_INCLUDE_BME680
{ TELEM_BME680_ADDRESS, "BME680", init_bme680, query_bme680 },
#endif
#if ENV_INCLUDE_BME680_BSEC
{ TELEM_BME680_ADDRESS, "BME680+BSEC", init_bme680_bsec, query_bme680_bsec },
#endif
#if ENV_INCLUDE_BME280
{ TELEM_BME280_ADDRESS, "BME280", init_bme280, query_bme280 },
#endif
@@ -798,11 +883,13 @@ void EnvironmentSensorManager::stop_gps() {
MESH_DEBUG_PRINTLN("Stop GPS is N/A on this board. Actual GPS state unchanged");
#endif
}
#endif // ENV_INCLUDE_GPS
#if ENV_INCLUDE_GPS || defined(ENV_INCLUDE_BME680_BSEC)
void EnvironmentSensorManager::loop() {
static long next_gps_update = 0;
#if ENV_INCLUDE_GPS
static long next_gps_update = 0;
if (gps_active) {
_location->loop();
}
@@ -830,5 +917,27 @@ void EnvironmentSensorManager::loop() {
next_gps_update = millis() + (gps_update_interval_sec * 1000);
}
#endif
#if ENV_INCLUDE_BME680_BSEC
if (bsec_active && bsec_iaq.run()) {
uint8_t prev_accuracy = bsec_accuracy;
bsec_temperature = bsec_iaq.temperature;
bsec_humidity = bsec_iaq.humidity;
bsec_pressure_hpa = bsec_iaq.pressure / 100.0f;
bsec_iaq_val = bsec_iaq.iaq;
bsec_accuracy = bsec_iaq.iaqAccuracy;
bsec_data_ready = true;
if (bsec_accuracy == 3) {
if (!bsec_first_save_done) {
bsec_save_state();
bsec_last_save_ms = millis();
bsec_first_save_done = true;
} else if ((millis() - bsec_last_save_ms) >= BSEC_SAVE_INTERVAL_MS) {
bsec_save_state();
bsec_last_save_ms = millis();
}
}
}
#endif // ENV_INCLUDE_BME680_BSEC
}
#endif
#endif // ENV_INCLUDE_GPS || ENV_INCLUDE_BME680_BSEC
@@ -43,7 +43,7 @@ public:
#endif
bool begin() override;
bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override;
#if ENV_INCLUDE_GPS
#if ENV_INCLUDE_GPS || defined(ENV_INCLUDE_BME680_BSEC)
void loop() override;
#endif
int getNumSettings() const override;
+15
View File
@@ -0,0 +1,15 @@
Import('env')
import os
# Bosch has a goof in their PlatformIO packaging making linking fail.
# The BSEC library's extra_script.py selects cortex-m4/libalgobsec.a (soft-float ABI).
# nRF52840 compiles with -mfloat-abi=hard, requiring the fpv4-sp-d16-hard blob.
# Workaround to prepend the hard-float path so the linker finds it before the
# soft-float one.
bsec_hard = os.path.join(
env.subst('$PROJECT_DIR'),
'.pio', 'libdeps', env.subst('$PIOENV'),
'BSEC Software Library', 'src',
'cortex-m4', 'fpv4-sp-d16-hard'
)
env.Prepend(LIBPATH=[bsec_hard])
+5
View File
@@ -2,6 +2,8 @@
extends = nrf52_base
board = rak4631
board_check = true
extra_scripts = ${nrf52_base.extra_scripts}
post:variants/rak4631/fix_bsec_lib.py
build_flags = ${nrf52_base.build_flags}
${sensor_base.build_flags}
-I variants/rak4631
@@ -21,6 +23,8 @@ build_flags = ${nrf52_base.build_flags}
-D SX126X_CURRENT_LIMIT=140
-D SX126X_RX_BOOSTED_GAIN=1
-D ENV_INCLUDE_RAK12035=1
-UENV_INCLUDE_BME680
-D ENV_INCLUDE_BME680_BSEC=1
build_src_filter = ${nrf52_base.build_src_filter}
+<../variants/rak4631>
+<helpers/sensors>
@@ -31,6 +35,7 @@ lib_deps =
${sensor_base.lib_deps}
adafruit/Adafruit SSD1306 @ ^2.5.13
sparkfun/SparkFun u-blox GNSS Arduino Library@^2.2.27
boschsensortec/BSEC Software Library @ ^1.8.1492
[env:RAK_4631_repeater]
extends = rak4631