Skip to content

feat: Integrate BME680 Bosch BSEC support for RAK4631#2634

Open
NickDunklee wants to merge 2 commits into
meshcore-dev:devfrom
NickDunklee:bme680-fixes-consolidation
Open

feat: Integrate BME680 Bosch BSEC support for RAK4631#2634
NickDunklee wants to merge 2 commits into
meshcore-dev:devfrom
NickDunklee:bme680-fixes-consolidation

Conversation

@NickDunklee
Copy link
Copy Markdown

I'm on a wild tear today! Trying to take advantage of it.

This is a consolidation of my changes for BME680 on RAK4631 nodes. I will close my other PRs related to this and link back to this one.

Background on change:

This change replaces the Adafruit BME680 driver on RAK4631 with the Bosch BSEC library. Other boards continue to use the existing Adafruit path via ENV_INCLUDE_BME680.

This makes the IAQ portion of the sensor functional, and more accurate. It also contains the math and/or CayenneLPP fixes from my other PRs. The Bosch code also appears to handle calibrating sensor aging as well, whereas the Adafruit code is just looking at blind values that can drift with time. Pretty cool to see this shooting out useful data!

RAK4631 platform.io is set to override to ENV_INCLUDE_BME680_BSEC while leaving the Adafruit code for other node types. (If this becomes applicable for other node types in future, awesome! I just don't have hardware to test against.)

Using the BSEC library introduces IAQ sensor calibration, and saves the calibration state periodically so it does not have to calibrate again later.

At startup the IAQ sensor takes 30 minutes to heat and to hit a baseline, then starts calibrating. Once calibrated, it will save those settings and will only write settings again if calibration falls back and restores back to state 3.

This fix also has the gas resistance math fix that was in pull 2146 so the adafruit path also can at least show accurate values instead of looping negative.

Also includes the fix from pull 2149 so the pressure output isn't truncated to 1hPa steps.

Fixes/Changes:

  • Add bsec_config_iaq[] with the 3.3V/3s-LP/28d calibration profile
  • BSEC init applies setConfig() for voltage-correct heater targeting
  • IAQ, heat-compensated temperature/humidity, pressure, and altitude reported over CayenneLPP
  • IAQ accuracy reported as analog input over CayenneLPP (0,1,2,3)
  • Calibration state persisted to /bsec_state.bin on nRF52 internal flash; written only when iaqAccuracy improves to >= 2, should keep write frequency well within flash endurance over device lifetime
  • Fix non-BSEC query_bme680: float pressure division, addGenericSensor for gas resistance (was addAnalogInput, overflows at > 327 Ohm)
  • loop() correctly gated for both GPS and BSEC-only builds
  • Add fix_bsec_lib.py extra_script to resolve nRF52840 hard-float ABI mismatch in Bosch's PlatformIO packaging, silly Bosch

One general note outside of this code change: I noticed while BME680 functions in companion nodes, since companion nodes run Bluetooth, BLE preempts the CPU, and can do so mid-I2C-transaction.

This can cause the BME680 to see an anomaly and drop calibration and start a recalibrate. This is behavior that will exist (and has existed) regardless of using the Adafruit or Bosch paths.

This particular companion behavior does not seem to occur in sensor or repeater nodes since their BLE is off. Probably affects other I2C devices as well.

Tests:

  • RAK19003
  • RAK19007
  • RAK19001
  • repeater, sensor, companion

24 Hour Grafana Stats Example: (Graph gap is from a service restart, not the node.)
24hr-bme680

This is a consolidation of my changes for BME680 on RAK4631 nodes.
I will close my other PRs related to this and link back to this one.

*Background on change:*

This change replaces the Adafruit BME680 driver on RAK4631 with the
Bosch BSEC library. Other boards continue to use the existing
Adafruit path via ENV_INCLUDE_BME680.

This makes the IAQ portion of the sensor functional, and more accurate.
It also contains the math and/or CayenneLPP fixes from my other PRs.
The Bosch code also appears to handle calibrating sensor aging as well,
whereas the Adafruit code is just looking at blind values that can drift
with time. Pretty cool to see this shooting out useful data!

RAK4631 platform.io is set to override to ENV_INCLUDE_BME680_BSEC while
leaving the Adafruit code for other node types. (If this becomes applicable
for other node types in future, awesome! I just don't have hardware
to test against.)

Using the BSEC library introduces IAQ sensor calibration, and saves
the calibration state periodically so it does not have to calibrate
again later.

At startup the IAQ sensor takes 30 minutes to heat and to hit a baseline,
then starts calibrating. Once calibrated, it will save those settings
and will only write settings again if calibration falls back and restores
back to state 3.

This fix also has the gas resistance math fix that was in
[pull 2146](meshcore-dev#2146) so
the adafruit path also can at least show accurate values instead
of looping negative.

Also includes the fix from [pull 2149](meshcore-dev#2149) so the pressure output isn't truncated to 1hPa steps.

*Fixes/Changes:*
- Add bsec_config_iaq[] with the 3.3V/3s-LP/28d calibration profile
- BSEC init applies setConfig() for voltage-correct heater targeting
- IAQ, heat-compensated temperature/humidity, pressure, and altitude
  reported over CayenneLPP
- IAQ accuracy reported as analog input over CayenneLPP (0,1,2,3)
- Calibration state persisted to /bsec_state.bin on nRF52 internal
  flash; written only when iaqAccuracy improves to >= 2, should
  keep write frequency well within flash endurance over device lifetime
- Fix non-BSEC query_bme680: float pressure division, addGenericSensor
  for gas resistance (was addAnalogInput, overflows at > 327 Ohm)
- loop() correctly gated for both GPS and BSEC-only builds
- Add fix_bsec_lib.py extra_script to resolve nRF52840 hard-float ABI
  mismatch in Bosch's PlatformIO packaging, silly Bosch

One general note outside of this code change: I noticed while BME680
_functions_ in companion nodes, since companion nodes run Bluetooth,
BLE preempts the CPU, and can do so mid-I2C-transaction.

This can cause the BME680 to see an anomaly and drop calibration and
start a recalibrate. This is behavior that will exist (and has existed)
regardless of using the Adafruit or Bosch paths.

This particular companion behavior does not seem to occur in sensor
or repeater nodes since their BLE is off. Probably affects other
I2C devices as well.

*Tests:*

- RAK19003
- RAK19007
- RAK19001
- repeater, sensor, companion
@NickDunklee
Copy link
Copy Markdown
Author

My other two PRs are closed and this is the source of truth for my BME680 stuff now, trying to not make too many GitHub messes 😂

🎉

I put it back and test-compiled a few builds.
bsec_accuracy = bsec_iaq.iaqAccuracy;
bsec_data_ready = true;
if (bsec_accuracy >= 2 && bsec_accuracy > prev_accuracy)
bsec_save_state();
Copy link
Copy Markdown

@cwichura cwichura May 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There doesn't appear to be any backoff here. If accuracy is updating every loop(), you will be doing a lot of filesystem writes. And there are concerns in other threads about RAKs corrupting their filesystem during writes under various trigger conditions. Maybe update this to include a millis() check as well, so that it isn't constantly overwriting the state file in rapid succession? How important is it that it update the state persistence? Could it limit it to every minute? five minutes? Or does the BSEC library itself already gate accuracy checks and so you have an inherent backoff from the library?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oooh, that's a good observation, I like it. Once the sensor gets into a calibrated state (except for on companions) it just remains there for hours on end. If the sensor gets into a calibration flux like on companions, it would otherwise be writing very frequently as you said. I will check into that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants