Bosch Sensortec Community

    cancel
    Showing results for 
    Search instead for 
    Did you mean: 
    SOLVED

    Permanent use for BME680 with ESP32

    Permanent use for BME680 with ESP32

    Jo_Felus
    Member

    Hello,
    I would like to use the BME680 sensor with an ESP32.
    Programming will be done with the BSEC library in Arduino IDE.
    The ESP32 should not only evaluate the sensor, but also take over other control tasks (relays, inputs,..).
    If there is an error in the process, the ESP32 restarts, which results in the BME680 arriving back in IAQ state 0.
    The power supply for the sensor is not interrupted when the ESP32 is restarted.

    Is it possible to run the sensor endlessly so that it is always operational without reinitializing it?
    After re-initialization it takes a relatively long time before the sensor outputs usable data.

    I hope you can understand my problem and maybe have a tip.

    4 REPLIES 4

    BSTRobin
    Community Moderator
    Community Moderator

    Hi Jo_Felus,

    Github code includes examples of saving BSEC status and loading BSEC status. Save the BSEC status before restart, and load the BSEC status after restart.
    updateState();
    loadState();
    https://github.com/boschsensortec/BSEC-Arduino-library/blob/master/examples/basic_config_state/basic...

    Hello Robin,

    thank you for your answer.. next time I'll look at all the examples.
    But I have tried out the load and update function. After restarting the ESP32 the IAQ state goes directly to 0. 
    It look like, it doesn't overwrite the state. I printed the eeprom data (after the four Sensor has IAQ state 3) and there were a lot of hex information.

    Do I anything wrong?
    Here is my IDE code:

    #include <EEPROM.h>
    #include "bsec.h"
    #include <Wire.h>
    
    #define TCAADDR 0x70
    
    void tcaselect(uint8_t i) {
      if (i > 7) return;
    
      Wire.beginTransmission(TCAADDR);
      Wire.write(1 << i);
      Wire.endTransmission();
    }
    
    /* Configure the BSEC library with information about the sensor
        18v/33v = Voltage at Vdd. 1.8V or 3.3V
        3s/300s = BSEC operating mode, BSEC_SAMPLE_RATE_LP or BSEC_SAMPLE_RATE_ULP
        4d/28d = Operating age of the sensor in days
        generic_18v_3s_4d
        generic_18v_3s_28d
        generic_18v_300s_4d
        generic_18v_300s_28d
        generic_33v_3s_4d
        generic_33v_3s_28d
        generic_33v_300s_4d
        generic_33v_300s_28d
    */
    const uint8_t bsec_config_iaq[] = {
    #include "config/generic_33v_3s_4d/bsec_iaq.txt"
    };
    
    #define STATE_SAVE_PERIOD UINT32_C(60000)  // 360 minutes - 4 times a day
    #define N_SENSORS 4
    
    // Helper functions declarations
    void checkIaqSensorStatus(void);
    void errLeds(void);
    void loadState(void);
    void updateState(void);
    
    // Create objects of the class Bsec
    Bsec iaqSensor1, iaqSensor2, iaqSensor3, iaqSensor4;
    uint8_t bsecState1[BSEC_MAX_STATE_BLOB_SIZE], bsecState2[BSEC_MAX_STATE_BLOB_SIZE], bsecState3[BSEC_MAX_STATE_BLOB_SIZE], bsecState4[BSEC_MAX_STATE_BLOB_SIZE];
    uint16_t stateUpdateCounter = 0;
    
    String output;
    
    // Entry point for the example
    void setup(void) {
      EEPROM.begin((N_SENSORS * BSEC_MAX_STATE_BLOB_SIZE) + 1);  // 1st address for the length of one state
      Serial.begin(115200);
      Wire.begin();
      tcaselect(0);
      iaqSensor1.begin(0x77, Wire);
      tcaselect(1);
      iaqSensor2.begin(0x77, Wire);
      tcaselect(2);
      iaqSensor3.begin(0x77, Wire);
      tcaselect(3);
      iaqSensor4.begin(0x77, Wire);
    
      tcaselect(0);
      output = "\nBSEC library version " + String(iaqSensor1.version.major) + "." + String(iaqSensor1.version.minor) + "." + String(iaqSensor1.version.major_bugfix) + "." + String(iaqSensor1.version.minor_bugfix);
      Serial.println(output);
      checkIaqSensorStatus();
      tcaselect(0);
      iaqSensor1.setConfig(bsec_config_iaq);
      tcaselect(1);
      iaqSensor2.setConfig(bsec_config_iaq);
      tcaselect(2);
      iaqSensor3.setConfig(bsec_config_iaq);
      tcaselect(3);
      iaqSensor4.setConfig(bsec_config_iaq);
      checkIaqSensorStatus();
    
      loadState();
    
      bsec_virtual_sensor_t sensorList[3] = {
        BSEC_OUTPUT_IAQ,
        BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
        BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
      };
    
      tcaselect(0);
      iaqSensor1.updateSubscription(sensorList, 3, BSEC_SAMPLE_RATE_LP);
      tcaselect(1);
      iaqSensor2.updateSubscription(sensorList, 3, BSEC_SAMPLE_RATE_LP);
      tcaselect(2);
      iaqSensor3.updateSubscription(sensorList, 3, BSEC_SAMPLE_RATE_LP);
      tcaselect(3);
      iaqSensor4.updateSubscription(sensorList, 3, BSEC_SAMPLE_RATE_LP);
      checkIaqSensorStatus();
    
      // Print the header
      output = "Sensor, Timestamp [ms], raw temperature [°C], pressure [hPa], raw relative humidity [%], gas [Ohm], IAQ, IAQ accuracy, temperature [°C], relative humidity [%]";
      Serial.println(output);
    }
    
    // Function that is looped forever
    void loop(void) {
      unsigned long time_trigger = millis();
      if (iaqSensor1.run()) {  // If new data is available
        output = "1, " + String("EINS: ");
        output += ", " + String(iaqSensor1.iaq);
        output += ", " + String(iaqSensor1.iaqAccuracy);
        output += ", " + String(iaqSensor1.temperature);
        output += ", " + String(iaqSensor1.humidity);
        Serial.println(output);
        updateState();
      } else {
        checkIaqSensorStatus();
      }
      tcaselect(1);
      if (iaqSensor2.run()) {  // If new data is available
        output = "2, " + String("ZWEI: ");
        output += ", " + String(iaqSensor2.iaq);
        output += ", " + String(iaqSensor2.iaqAccuracy);
        output += ", " + String(iaqSensor2.temperature);
        output += ", " + String(iaqSensor2.humidity);
        Serial.println(output);
        updateState();
      } else {
        checkIaqSensorStatus();
      }
      tcaselect(2);
      if (iaqSensor3.run()) {  // If new data is available
        output = "1, " + String("DREI: ");
        output += ", " + String(iaqSensor3.iaq);
        output += ", " + String(iaqSensor3.iaqAccuracy);
        output += ", " + String(iaqSensor3.temperature);
        output += ", " + String(iaqSensor3.humidity);
        Serial.println(output);
        updateState();
      } else {
        checkIaqSensorStatus();
      }
      tcaselect(3);
      if (iaqSensor4.run()) {  // If new data is available
        output = "2, " + String("VIER: ");
        output += ", " + String(iaqSensor4.iaq);
        output += ", " + String(iaqSensor4.iaqAccuracy);
        output += ", " + String(iaqSensor4.temperature);
        output += ", " + String(iaqSensor4.humidity);
        Serial.println(output);
        updateState();
      } else {
        checkIaqSensorStatus();
      }
    }
    
    // Helper function definitions
    void checkIaqSensorStatus(void) {
      tcaselect(0);
      if (iaqSensor1.status != BSEC_OK) {
        if (iaqSensor1.status < BSEC_OK) {
          output = "BSEC1 error code : " + String(iaqSensor1.status);
          Serial.println(output);
          // for (;;)
          errLeds(); /* Halt in case of failure */
        } else {
          output = "BSEC warning code : " + String(iaqSensor1.status);
          Serial.println(output);
        }
      }
    
      if (iaqSensor1.bme680Status != BME680_OK) {
        if (iaqSensor1.bme680Status < BME680_OK) {
          output = "BME6801 error code : " + String(iaqSensor1.bme680Status);
          Serial.println(output);
          // for (;;)
          errLeds(); /* Halt in case of failure */
        } else {
          output = "BME680 warning code : " + String(iaqSensor1.bme680Status);
          Serial.println(output);
        }
      }
      iaqSensor1.status = BSEC_OK;
      tcaselect(1);
      if (iaqSensor2.status != BSEC_OK) {
        if (iaqSensor2.status < BSEC_OK) {
          output = "BSEC error code : " + String(iaqSensor2.status);
          Serial.println(output);
          // for (;;)
          errLeds(); /* Halt in case of failure */
        } else {
          output = "BSEC warning code : " + String(iaqSensor2.status);
          Serial.println(output);
        }
      }
    
      if (iaqSensor2.bme680Status != BME680_OK) {
        if (iaqSensor2.bme680Status < BME680_OK) {
          output = "BME680 error code : " + String(iaqSensor2.bme680Status);
          Serial.println(output);
          // for (;;)
          errLeds(); /* Halt in case of failure */
        } else {
          output = "BME680 warning code : " + String(iaqSensor2.bme680Status);
          Serial.println(output);
        }
      }
      iaqSensor2.status = BSEC_OK;
      tcaselect(2);
      if (iaqSensor3.status != BSEC_OK) {
        if (iaqSensor3.status < BSEC_OK) {
          output = "BSEC1 error code : " + String(iaqSensor3.status);
          Serial.println(output);
          // for (;;)
          errLeds(); /* Halt in case of failure */
        } else {
          output = "BSEC warning code : " + String(iaqSensor3.status);
          Serial.println(output);
        }
      }
    
      if (iaqSensor3.bme680Status != BME680_OK) {
        if (iaqSensor3.bme680Status < BME680_OK) {
          output = "BME6801 error code : " + String(iaqSensor3.bme680Status);
          Serial.println(output);
          // for (;;)
          errLeds(); /* Halt in case of failure */
        } else {
          output = "BME680 warning code : " + String(iaqSensor3.bme680Status);
          Serial.println(output);
        }
      }
      iaqSensor3.status = BSEC_OK;
      tcaselect(3);
      if (iaqSensor4.status != BSEC_OK) {
        if (iaqSensor4.status < BSEC_OK) {
          output = "BSEC error code : " + String(iaqSensor4.status);
          Serial.println(output);
          // for (;;)
          errLeds(); /* Halt in case of failure */
        } else {
          output = "BSEC warning code : " + String(iaqSensor4.status);
          Serial.println(output);
        }
      }
    
      if (iaqSensor4.bme680Status != BME680_OK) {
        if (iaqSensor4.bme680Status < BME680_OK) {
          output = "BME680 error code : " + String(iaqSensor4.bme680Status);
          Serial.println(output);
          for (;;)
            errLeds(); /* Halt in case of failure */
        } else {
          output = "BME680 warning code : " + String(iaqSensor4.bme680Status);
          Serial.println(output);
        }
      }
      iaqSensor4.status = BSEC_OK;
    }
    
    void errLeds(void) {
      pinMode(LED_BUILTIN, OUTPUT);
      digitalWrite(LED_BUILTIN, HIGH);
      delay(100);
      digitalWrite(LED_BUILTIN, LOW);
      delay(100);
    }
    
    void loadState(void) {
      if (EEPROM.read(0) == BSEC_MAX_STATE_BLOB_SIZE) {
        // Existing state in EEPROM
        Serial.println("Reading state from EEPROM");
    
        for (uint8_t i = 0; i < BSEC_MAX_STATE_BLOB_SIZE; i++) {
          bsecState1[i] = EEPROM.read(i + 1);
          bsecState2[i] = EEPROM.read(i + 1 + BSEC_MAX_STATE_BLOB_SIZE);
          bsecState3[i] = EEPROM.read(i + 1 + BSEC_MAX_STATE_BLOB_SIZE + BSEC_MAX_STATE_BLOB_SIZE);
          bsecState4[i] = EEPROM.read(i + 1 + BSEC_MAX_STATE_BLOB_SIZE + BSEC_MAX_STATE_BLOB_SIZE + BSEC_MAX_STATE_BLOB_SIZE);
          //Serial.println(String(bsecState1[i], HEX) + ", " + String(bsecState2[i], HEX) + ", " + String(bsecState3[i], HEX) + ", " + String(bsecState4[i], HEX));
        }
        tcaselect(0);
        iaqSensor1.setState(bsecState1);
        tcaselect(1);
        iaqSensor2.setState(bsecState2);
        tcaselect(2);
        iaqSensor3.setState(bsecState3);
        tcaselect(3);
        iaqSensor4.setState(bsecState4);
        checkIaqSensorStatus();
      } else {
        // Erase the EEPROM with zeroes
        Serial.println("Erasing EEPROM");
    
        for (uint16_t i = 0; i < (N_SENSORS * BSEC_MAX_STATE_BLOB_SIZE) + 1; i++) {
          EEPROM.write(i, 0);
        }
    
        EEPROM.commit();
      }
    }
    
    void updateState(void) {
      bool update = false;
      /* Set a trigger to save the state. Here, the state is saved every STATE_SAVE_PERIOD with the first state being saved once the algorithm achieves full calibration, i.e. iaqAccuracy = 3 */
      if (stateUpdateCounter == 0) {
        if ((iaqSensor1.iaqAccuracy >= 3) || (iaqSensor2.iaqAccuracy >= 3) || (iaqSensor3.iaqAccuracy >= 3) || (iaqSensor4.iaqAccuracy >= 3)) {
          update = true;
          stateUpdateCounter++;
        }
      } else {
        /* Update every STATE_SAVE_PERIOD milliseconds */
        if ((stateUpdateCounter * STATE_SAVE_PERIOD) < millis()) {
          update = true;
          stateUpdateCounter++;
        }
      }
    
      if (update) {
        tcaselect(0);
        iaqSensor1.getState(bsecState1);
        tcaselect(1);
        iaqSensor2.getState(bsecState2);
        tcaselect(2);
        iaqSensor3.getState(bsecState3);
        tcaselect(3);
        iaqSensor4.getState(bsecState4);
        checkIaqSensorStatus();
    
        Serial.println("Writing state(s) to EEPROM");
    
        for (uint16_t i = 0; i < BSEC_MAX_STATE_BLOB_SIZE; i++) {
          EEPROM.write(i + 1, bsecState1[i]);
          EEPROM.write(i + 1 + BSEC_MAX_STATE_BLOB_SIZE, bsecState2[i]);
          EEPROM.write(i + 1 + BSEC_MAX_STATE_BLOB_SIZE + BSEC_MAX_STATE_BLOB_SIZE, bsecState3[i]);
          EEPROM.write(i + 1 + BSEC_MAX_STATE_BLOB_SIZE + BSEC_MAX_STATE_BLOB_SIZE + BSEC_MAX_STATE_BLOB_SIZE, bsecState4[i]);
          // Serial.println(String(bsecState1[i], HEX) + ", " + String(bsecState2[i], HEX) + ", " + String(bsecState3[i], HEX) + ", " + String(bsecState4[i], HEX));
        }
    
        EEPROM.write(0, BSEC_MAX_STATE_BLOB_SIZE);
        EEPROM.commit();
      }
    }

     

    BSTRobin
    Community Moderator
    Community Moderator

    After loading the BSEC status, you need to wait for the sensor to stabilize. Refer to the BSEC status in the integration document.

    BSEC OUTPUT RUN IN STATUS.png

    Thank you!
    I pratcied ESP32 restarts and could see that after 5 minutes IAQ state jumped from 0 to 3.

    Icon--AD-black-48x48Icon--address-consumer-data-black-48x48Icon--appointment-black-48x48Icon--back-left-black-48x48Icon--calendar-black-48x48Icon--center-alignedIcon--Checkbox-checkIcon--clock-black-48x48Icon--close-black-48x48Icon--compare-black-48x48Icon--confirmation-black-48x48Icon--dealer-details-black-48x48Icon--delete-black-48x48Icon--delivery-black-48x48Icon--down-black-48x48Icon--download-black-48x48Ic-OverlayAlertIcon--externallink-black-48x48Icon-Filledforward-right_adjustedIcon--grid-view-black-48x48IC_gd_Check-Circle170821_Icons_Community170823_Bosch_Icons170823_Bosch_Icons170821_Icons_CommunityIC-logout170821_Icons_Community170825_Bosch_Icons170821_Icons_CommunityIC-shopping-cart2170821_Icons_CommunityIC-upIC_UserIcon--imageIcon--info-i-black-48x48Icon--left-alignedIcon--Less-minimize-black-48x48Icon-FilledIcon--List-Check-grennIcon--List-Check-blackIcon--List-Cross-blackIcon--list-view-mobile-black-48x48Icon--list-view-black-48x48Icon--More-Maximize-black-48x48Icon--my-product-black-48x48Icon--newsletter-black-48x48Icon--payment-black-48x48Icon--print-black-48x48Icon--promotion-black-48x48Icon--registration-black-48x48Icon--Reset-black-48x48Icon--right-alignedshare-circle1Icon--share-black-48x48Icon--shopping-bag-black-48x48Icon-shopping-cartIcon--start-play-black-48x48Icon--store-locator-black-48x48Ic-OverlayAlertIcon--summary-black-48x48tumblrIcon-FilledvineIc-OverlayAlertwhishlist