Bosch Sensortec Community

    cancel
    Showing results for 
    Search instead for 
    Did you mean: 

    BME680

    BME680

    liangtao
    Occasional Visitor

    With the BME680 sensor, can the IAQ in BSEC change the acquisition frequency to 1 minute, or the interval can only be 3 seconds or 300 seconds?

    9 REPLIES 9

    handytech
    Community Moderator
    Community Moderator

    @elcaron wrote:

    I woulld like to have my ESP32 sleeping as much as possible, since it causes a very noticable temperature offset, but on the other hand have temperature updates at least every 2 minutes.


    If the offset due to your system is know and relatively constant, you can feed this offset to BSEC using the BSEC_INPUT_HEATSOURCE input, and BSEC will compensated for it in the compensated outputs.


    @elcaron wrote:

    It was mentioned that T/H/P could be configured LP, and the gas sensor ULP. How would I do that?


    To do so, simply use the BSEC_SAMPLE_RATE_LP sample rate for T/P/H and BSEC_SAMPLE_RATE_ULP for the gas based outputs in bsec_update_subscription().


    @elcaron wrote:

    Well, it is constant, it is polled every 2min (withconfig/generic_33v_3s_4d/bsec_iaq.txt setting). But I guess that should read "Every 3s interval has to be read"?


    The typical expectation would be to run all the outputs in either ULP or LP mode (therefore everything every 300s or 3s respectively), unless in the configuration just mentioned above.

    I have a few questions concerning using the bsec-IAQ in MCU sleep mode..

    In the library, you have a delay_ms that uses delay() function from Arduino… how is this used? Do I need to be concern about this when the MCU sleeps? if so, it would be nice if you would make this function __weak__ so that it can be overwritten in the main program.

    What is the relationship of sensor.nextCall to MCU sleep timing?

    Should BEC  state ONLY be saved if IAQ>3?

    If I run your “BME680-basic_config_state.ino”, modified for FRAM memory, and using Serial Port 1, it works just fine and converges on an IAQ of 3 in a 1 hour or less.

    I also acquired an ESP32 board and attach a BME680 to run your example code. Works fine..

    I have a SAMD21 M0 MCU on a customer’s board with a BME680 and a FRAM (EEPROM like) NV memory..

    I have been unable to get my test code to acquire an IAQ of anything other than zero when I attempted to sleep or delay for a fixed time… I based the code on the ESP32 example, but have been unable to make it work properly.

    I’m sure it’s something I’m missing or do not understand about using the BEQ library. Any ideas??

    Note: On thing that I did notice, was in bsec.h, nextCall is an int64_t, as time is always positive in this case, I suggest that it should be an uint64_t, and for consistency, so should outputTimestamp.  Also callTimeMs in bsec.cpp

     

    Thanks

    ~~~~~~~~~~~~~~~~~~~~~~~

    Sensor: RT: 25.69, P: 1002.22, RH: 61.61, Gas: 81.36, IAQ: 154.46, Q: 0, T: 25.68, H: 61.66
    *Writing state to FRAM
    ***Going to sleep until: 946697746
    ***Wakeing up at: 946697747
    **CurentTime: 946697747
    **nextRunTime: 946697757
    *Reading state from FRAM
    **iaqTime: 12947000
    **nextRunTime: 946697757
    **nextCall: 12950000
    Sensor: RT: 25.70, P: 1002.20, RH: 61.61, Gas: 81.60, IAQ: 154.46, Q: 0, T: 25.69, H: 61.63
    *Writing state to FRAM
    ***Going to sleep until: 946697757
    ***Wakeing up at: 946697758
    **CurentTime: 946697758
    **nextRunTime: 946697768
    *Reading state from FRAM
    **iaqTime: 12958000
    **nextRunTime: 946697768
    **nextCall: 12961000
    Sensor: RT: 25.70, P: 1002.20, RH: 61.62, Gas: 81.20, IAQ: 154.46, Q: 0, T: 25.69, H: 61.64
    *Writing state to FRAM
    ***Going to sleep until: 946697768
    ***Wakeing up at: 946697769
    **CurentTime: 946697769
    **nextRunTime: 946697779
    *Reading state from FRAM
    **iaqTime: 12969000
    **nextRunTime: 946697779
    **nextCall: 12972000
    Sensor: RT: 25.71, P: 1002.20, RH: 61.55, Gas: 81.52, IAQ: 154.46, Q: 0, T: 25.70, H: 61.55
    *Writing state to FRAM
    ***Going to sleep until: 946697779

    /* *****************************************************************************
     * 
     * *****************************************************************************
     *
     *  CHANGE LOG:
     *
     *    DATE         REV  DESCRIPTION
     *    -----------  ---  ----------------------------------------------------------
     *    01-Aug-2020  1.0  TRL - First Build of test version
     *   
     *
     *    Notes:  1)  Tested with Arduino 1.8.13
     *            2)  Tested using a Feather M0 SAMD21 CPU
     *            3)  Using a 64k Fram via I2C
     *            4)  Requires a SAMD21 Feather M0 varient.h file
     *
     *    Todo:   1)  Add support for Flash as EEPROM to use when FRAM is not avilable
     *            2) 
     *            3) 
     * 
     * 
     * 
     *  We need to define a FRAM map for this project:
     *  
     *  Function          Size        Base address  Note:
     *  bsec_blob         1 + 139     0x00          1st byte is a flag, need to reserve ~150 bytes
     *  
     *  
     *  tom@lafleur.us
     * 
     ****************************************************************************** */
    
     /* ************************************************************* */
    #define SKETCHNAME    "BME680-sleep test"
    #define SKETCHVERSION "Ver: 1.0b"
    
    #include <Wire.h>
    #include <RTCZero.h>              // https://github.com/arduino-libraries/RTCZero
    #include <FRAM_MB85RC_I2C.h>      // https://github.com/sosandroid/FRAM_MB85RC_I2C 
    #include <bsec.h>                 // https://github.com/BoschSensortec/BSEC-Arduino-library
    
    // Include EEPROM-like API for FlashStorage
    //#include <FlashAsEEPROM.h>      // https://www.arduinolibraries.info/libraries/flash-storage
    
    #define MyDelay                   // if this is defined, we will delay and not sleep...
    //#define DumpBLOB                  // will print out bsec state BLOB on save and get
    
    /* 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"
    };
    
    // Create an object of the class Bsec
    Bsec      iaqSensor;
    uint8_t   bsecState[BSEC_MAX_STATE_BLOB_SIZE] = {0};
    
    // Creating object for FRAM chip
    FRAM_MB85RC_I2C   FRAM;
    
    // Creating object for RTC
    RTCZero           rtc;
    
    // Require by bsec
    String output;                                
    
    // functions forward declarations
    void doSleep(uint32_t sTime);
    bool CheckSensor(void);
    void getState(void);
    void saveState(void);
    
    
    // Global variables....
    const char CompileDate[32]    = __DATE__ ", " __TIME__;
    uint64_t   nextRunTime        = 0;
    
    // Projects defines
    #define BME680_ADDRESS       (0x77)           // I2C device address of the BME680 sensor
    #define BSEC_ADDR             0               // base location in FRAM of bsec-blob... blob size is 139 bytes
    #define TX_Interval           1               // in minutes
    
    #ifndef ADAFRUIT_FEATHER_M0 
    #error Requires a Feather M0 varient.h file
    #endif
    
    
    /* ************************************************************** */
    /* ************************************************************** */
    void setup(void)
    {  
        Serial.begin (115200);              // Initialize USB/serial connection ( will disconnect when we sleep...)
        Serial1.begin(115200);              // debug port
        delay(2000); 
    
    #ifdef MyDelay    
        Serial1.printf("\n\nStarted with delay: %s\n%s\n%s\n", SKETCHNAME, SKETCHVERSION, CompileDate);
    #else
        Serial1.printf("\n\nStarted with sleep: %s\n%s\n%s\n", SKETCHNAME, SKETCHVERSION, CompileDate);
    #endif
    
        Wire.begin();
        FRAM.begin();
        rtc.begin(true);                 // initialize the realtime clock (RTC), reset time...
        
        Serial1.printf("**curTime: %lu sec\n", rtc.getEpoch() );
        
    // Start BME680
        iaqSensor.begin(BME680_ADDRESS, Wire);
        if (!CheckSensor()) { Serial1.printf("Failed to init BME680, check wiring!\n"); }
        
        Serial1.printf("\nBSEC library version %d.%d.%d.%d\n",
                               iaqSensor.version.major,
                               iaqSensor.version.minor,
                               iaqSensor.version.major_bugfix,
                               iaqSensor.version.minor_bugfix
                               );
    
        iaqSensor.setConfig(bsec_config_iaq);         // set operation mode
        if (!CheckSensor()) { Serial1.printf("Failed to set BME680 config!\n"); }
        
    //  loadCalibrationData();                        // load pass calabration data if available
        getState();                                   // laod pass operational state from FRAM if available
        if (!CheckSensor()) { Serial1.printf("Failed to set BME680 state!\n"); }
        
        bsec_virtual_sensor_t sensorList[10] = {
          BSEC_OUTPUT_RAW_TEMPERATURE,
          BSEC_OUTPUT_RAW_PRESSURE,
          BSEC_OUTPUT_RAW_HUMIDITY,
          BSEC_OUTPUT_RAW_GAS,
          BSEC_OUTPUT_IAQ,
          BSEC_OUTPUT_STATIC_IAQ,
          BSEC_OUTPUT_CO2_EQUIVALENT,
          BSEC_OUTPUT_BREATH_VOC_EQUIVALENT,
          BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
          BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
        };
    
      iaqSensor.updateSubscription(sensorList, sizeof(sensorList) / sizeof(sensorList[0]), BSEC_SAMPLE_RATE_LP);    // BSEC_SAMPLE_RATE_ULP
      if (!CheckSensor()) { Serial1.printf("Failed to update iaq subscription!\n"); }
    }
    
    
    /* ************************************************************** */
    /* ************************************************************** */
    void loop(void)
    { 
    
      nextRunTime = ( (10) + rtc.getEpoch() );    // 10 sec...
      
      //nextRunTime = ( (TX_Interval * 60) + rtc.getEpoch() );       // get current time, add delay = next run time in sec
      Serial1.printf("**CurentTime:  %lu\n", rtc.getEpoch());
      Serial1.printf("**nextRunTime: %lu\n", nextRunTime);
    
      getState();                                                  // reload beq data to device as we have just woken up......  
      if (!CheckSensor()) { Serial1.printf("Failed to set BME680 state!\n"); }
    
    
      uint64_t iaqTime = (uint64_t) ((rtc.getEpoch() - 946684800l) * 1000);
      
      Serial1.printf("**iaqTime: %lu\n",iaqTime);
      if (iaqSensor.run(iaqTime ))                   // start the sensor with current time from RTC in ms, wait for data
      {                                                            // If new data is available  
        
        Serial1.printf("**nextRunTime: %lu\n", nextRunTime );
        Serial1.printf("**nextCall:    %lu\n", iaqSensor.nextCall );
        
        if (!CheckSensor()) { Serial1.printf("*Data not valid!\n"); }
    
        output = String("Sensor");
        output += ": RT: "  + String(iaqSensor.rawTemperature);
        output += ", P: "   + String(iaqSensor.pressure/100);
        output += ", RH: "  + String(iaqSensor.rawHumidity);
        output += ", Gas: " + String(iaqSensor.gasResistance/1000);
        output += "k, IAQ: " + String(iaqSensor.iaq);
        output += ", Q: "   + String(iaqSensor.iaqAccuracy);
        output += ", T: "   + String(iaqSensor.temperature);
        output += ", H: "   + String(iaqSensor.humidity);
        Serial1.println(output);
    
        saveState();                                                // save beq data here prior to sleep
        Serial1.printf("***Going to sleep until: %lu\n", nextRunTime); 
              
          doSleep(nextRunTime);                                     // deep sleep for x seconds
    
        Serial1.printf("***Wakeing up at:        %lu\n", (uint64_t) rtc.getEpoch());
      }
    }
    
    
    /* ************************************************************** */
    void doSleep(uint32_t sTime) 
    {
    #ifdef MyDelay
        while ( rtc.getEpoch() <= sTime ) { delay(1); }     // this will fake sleeping for testing...
    #else
        rtc.setAlarmEpoch(sTime);               // set new alarm time in seconds    
        rtc.enableAlarm(rtc.MATCH_HHMMSS);      // currently only checking for HMS, not days or years
        rtc.standbyMode();                      // bring CPU into deep sleep mode (until woken up by the RTC alarm)
    #endif
    }
    
    
    /* ************************************************************** */
    bool CheckSensor() 
    {
      if (iaqSensor.status < BSEC_OK) 
      {
        Serial1.printf("BSEC error, status %d!", iaqSensor.status);
        return false;
        
      } else
      if (iaqSensor.status > BSEC_OK) 
      {
        Serial1.printf("BSEC warning, status %d!", iaqSensor.status);
      }
    
      if (iaqSensor.bme680Status < BME680_OK) 
      {
        Serial1.printf("Sensor error, bme680_status %d!", iaqSensor.bme680Status);
        return false;
        
      } else if (iaqSensor.bme680Status > BME680_OK) 
      {
        Serial1.printf("Sensor warning, status %d!", iaqSensor.bme680Status);
      }
      return true;
    }
    
    
    /* ************************************************************** */
    void getState(void)
    {
      uint8_t Blob_Size;                              // its less that 256 bytes in size
      FRAM.readByte(BSEC_ADDR, &Blob_Size);
      if (Blob_Size == BSEC_MAX_STATE_BLOB_SIZE)      // for now, see if we have blob size in FRAM... (should be CRC16 in future...) 
      {
        // we have an Existing state in FRAM
        Serial1.printf("*Reading state from FRAM\n");
    
        for (uint32_t i = 0; i < BSEC_MAX_STATE_BLOB_SIZE; i++) 
        {
          uint8_t rdata;
          FRAM.readByte(i + 1, &rdata);
          bsecState[i] = rdata;
    #ifdef DumpBLOB      
          Serial1.printf("%02x ", rdata);
          if (i % 16 == 15) { Serial1.print("\n"); }
          if ( i == (BSEC_MAX_STATE_BLOB_SIZE -1 )) { Serial1.print("\n"); }
    #endif 
        }
        
        iaqSensor.setState(bsecState);
        CheckSensor();
      } else
       
      {
        // Erase the FRAM with zeroes
        Serial1.printf("*Erasing FRAM\n");
    
        for (uint32_t i = BSEC_ADDR; i < BSEC_MAX_STATE_BLOB_SIZE + 1; i++)
          FRAM.writeByte(i, 0);
      }
    }
    
    
    /* ************************************************************** */
    void saveState(void)
    {
        iaqSensor.getState(bsecState);
        CheckSensor();  
        Serial1.printf("*Writing state to FRAM\n");
        for (uint32_t i = BSEC_ADDR; i < BSEC_MAX_STATE_BLOB_SIZE ; i++) 
        {
          FRAM.writeByte(i + 1, bsecState[i]);
    #ifdef DumpBLOB      
          Serial1.printf("%02x ", bsecState[i]);
          if (i % 16 == 15) { Serial1.print("\n"); }
          if ( i == (BSEC_MAX_STATE_BLOB_SIZE -1 )) { Serial1.print("\n"); }
    #endif  
        }   
    
        FRAM.writeByte(BSEC_ADDR, BSEC_MAX_STATE_BLOB_SIZE);        // save blob size as flag... (should be CRC16 in future...) 
    }
    
    /* ********************* The End ******************************** */
    /* ************************************************************** */
    

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~

     

     

     

     

    /* *****************************************************************************
     * 
     * *****************************************************************************
     *
     *  CHANGE LOG:
     *
     *    DATE         REV  DESCRIPTION
     *    -----------  ---  ----------------------------------------------------------
     *    01-Aug-2020  1.0  TRL - First Build of test version
     *   
     *
     *    Notes:  1)  Tested with Arduino 1.8.13
     *            2)  Tested using a Feather M0 SAMD21 CPU
     *            3)  Using a 64k Fram via I2C
     *            4)  Requires a SAMD21 Feather M0 varient.h file
     *
     *    Todo:   1)  Add support for Flash as EEPROM to use when FRAM is not avilable
     *            2) 
     *            3) 
     * 
     * 
     * 
     *  We need to define a FRAM map for this project:
     *  
     *  Function          Size        Base address  Note:
     *  bsec_blob         1 + 139     0x00          1st byte is a flag, need to reserve ~150 bytes
     *  
     *  
     *  tom@lafleur.us
     * 
     ****************************************************************************** */
    
     /* ************************************************************* */
    #define SKETCHNAME    "BME680-sleep test"
    #define SKETCHVERSION "Ver: 1.0b"
    
    #include <Wire.h>
    #include <RTCZero.h>              // https://github.com/arduino-libraries/RTCZero
    #include <FRAM_MB85RC_I2C.h>      // https://github.com/sosandroid/FRAM_MB85RC_I2C 
    #include <bsec.h>                 // https://github.com/BoschSensortec/BSEC-Arduino-library
    
    // Include EEPROM-like API for FlashStorage
    //#include <FlashAsEEPROM.h>      // https://www.arduinolibraries.info/libraries/flash-storage
    
    #define MyDelay                   // if this is defined, we will delay and not sleep...
    //#define DumpBLOB                  // will print out bsec state BLOB on save and get
    
    /* 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"
    };
    
    // Create an object of the class Bsec
    Bsec      iaqSensor;
    uint8_t   bsecState[BSEC_MAX_STATE_BLOB_SIZE] = {0};
    
    // Creating object for FRAM chip
    FRAM_MB85RC_I2C   FRAM;
    
    // Creating object for RTC
    RTCZero           rtc;
    
    // Require by bsec
    String output;                                
    
    // functions forward declarations
    void doSleep(uint32_t sTime);
    bool CheckSensor(void);
    void getState(void);
    void saveState(void);
    
    
    // Global variables....
    const char CompileDate[32]    = __DATE__ ", " __TIME__;
    uint64_t   nextRunTime        = 0;
    
    // Projects defines
    #define BME680_ADDRESS       (0x77)           // I2C device address of the BME680 sensor
    #define BSEC_ADDR             0               // base location in FRAM of bsec-blob... blob size is 139 bytes
    #define TX_Interval           1               // in minutes
    
    #ifndef ADAFRUIT_FEATHER_M0 
    #error Requires a Feather M0 varient.h file
    #endif
    
    
    /* ************************************************************** */
    /* ************************************************************** */
    void setup(void)
    {  
        Serial.begin (115200);              // Initialize USB/serial connection ( will disconnect when we sleep...)
        Serial1.begin(115200);              // debug port
        delay(2000); 
    
    #ifdef MyDelay    
        Serial1.printf("\n\nStarted with delay: %s\n%s\n%s\n", SKETCHNAME, SKETCHVERSION, CompileDate);
    #else
        Serial1.printf("\n\nStarted with sleep: %s\n%s\n%s\n", SKETCHNAME, SKETCHVERSION, CompileDate);
    #endif
    
        Wire.begin();
        FRAM.begin();
        rtc.begin(true);                 // initialize the realtime clock (RTC), reset time...
        
        Serial1.printf("**curTime: %lu sec\n", rtc.getEpoch() );
        
    // Start BME680
        iaqSensor.begin(BME680_ADDRESS, Wire);
        if (!CheckSensor()) { Serial1.printf("Failed to init BME680, check wiring!\n"); }
        
        Serial1.printf("\nBSEC library version %d.%d.%d.%d\n",
                               iaqSensor.version.major,
                               iaqSensor.version.minor,
                               iaqSensor.version.major_bugfix,
                               iaqSensor.version.minor_bugfix
                               );
    
        iaqSensor.setConfig(bsec_config_iaq);         // set operation mode
        if (!CheckSensor()) { Serial1.printf("Failed to set BME680 config!\n"); }
        
    //  loadCalibrationData();                        // load pass calabration data if available
        getState();                                   // laod pass operational state from FRAM if available
        if (!CheckSensor()) { Serial1.printf("Failed to set BME680 state!\n"); }
        
        bsec_virtual_sensor_t sensorList[10] = {
          BSEC_OUTPUT_RAW_TEMPERATURE,
          BSEC_OUTPUT_RAW_PRESSURE,
          BSEC_OUTPUT_RAW_HUMIDITY,
          BSEC_OUTPUT_RAW_GAS,
          BSEC_OUTPUT_IAQ,
          BSEC_OUTPUT_STATIC_IAQ,
          BSEC_OUTPUT_CO2_EQUIVALENT,
          BSEC_OUTPUT_BREATH_VOC_EQUIVALENT,
          BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
          BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
        };
    
      iaqSensor.updateSubscription(sensorList, sizeof(sensorList) / sizeof(sensorList[0]), BSEC_SAMPLE_RATE_LP);    // BSEC_SAMPLE_RATE_ULP
      if (!CheckSensor()) { Serial1.printf("Failed to update iaq subscription!\n"); }
    }
    
    
    /* ************************************************************** */
    /* ************************************************************** */
    void loop(void)
    { 
    
      nextRunTime = ( (10) + rtc.getEpoch() );    // 10 sec...
      
      //nextRunTime = ( (TX_Interval * 60) + rtc.getEpoch() );       // get current time, add delay = next run time in sec
      Serial1.printf("**CurentTime:  %lu\n", rtc.getEpoch());
      Serial1.printf("**nextRunTime: %lu\n", nextRunTime);
    
      getState();                                                  // reload beq data to device as we have just woken up......  
      if (!CheckSensor()) { Serial1.printf("Failed to set BME680 state!\n"); }
      
      if (iaqSensor.run(rtc.getEpoch() * 1000 ))                   // start the sensor with current time from RTC in ms, wait for data
      {                                                            // If new data is available  
         
        Serial1.printf("**nextRunTime: %lu\n", nextRunTime );
        Serial1.printf("**nextCall:    %lu\n", iaqSensor.nextCall );
        
        if (!CheckSensor()) { Serial1.printf("*Data not valid!\n"); }
    
        output = String("Sensor");
        output += ": RT: "  + String(iaqSensor.rawTemperature);
        output += ", P: "   + String(iaqSensor.pressure/100);
        output += ", RH: "  + String(iaqSensor.rawHumidity);
        output += ", Gas: " + String(iaqSensor.gasResistance/1000);
        output += ", IAQ: " + String(iaqSensor.iaq);
        output += ", Q: "   + String(iaqSensor.iaqAccuracy);
        output += ", T: "   + String(iaqSensor.temperature);
        output += ", H: "   + String(iaqSensor.humidity);
        Serial1.println(output);
    
        saveState();                                                // save beq data here prior to sleep
        Serial1.printf("***Going to sleep until: %lu\n", nextRunTime); 
              
          doSleep(nextRunTime);                                     // deep sleep for x seconds
    
        Serial1.printf("***Wakeing up at:        %lu\n", (uint64_t) rtc.getEpoch());
      }
    }
    
    
    /* ************************************************************** */
    void doSleep(uint32_t sTime) 
    {
    #ifdef MyDelay
        while ( rtc.getEpoch() <= sTime ) { delay(1); }     // this will fake sleeping for testing...
    #else
        rtc.setAlarmEpoch(sTime);               // set new alarm time in seconds    
        rtc.enableAlarm(rtc.MATCH_HHMMSS);      // currently only checking for HMS, not days or years
        rtc.standbyMode();                      // bring CPU into deep sleep mode (until woken up by the RTC alarm)
    #endif
    }
    
    
    /* ************************************************************** */
    bool CheckSensor() 
    {
      if (iaqSensor.status < BSEC_OK) 
      {
        Serial1.printf("BSEC error, status %d!", iaqSensor.status);
        return false;
        
      } else
      if (iaqSensor.status > BSEC_OK) 
      {
        Serial1.printf("BSEC warning, status %d!", iaqSensor.status);
      }
    
      if (iaqSensor.bme680Status < BME680_OK) 
      {
        Serial1.printf("Sensor error, bme680_status %d!", iaqSensor.bme680Status);
        return false;
        
      } else if (iaqSensor.bme680Status > BME680_OK) 
      {
        Serial1.printf("Sensor warning, status %d!", iaqSensor.bme680Status);
      }
      return true;
    }
    
    
    /* ************************************************************** */
    void getState(void)
    {
      uint8_t Blob_Size;                              // its less that 256 bytes in size
      FRAM.readByte(BSEC_ADDR, &Blob_Size);
      if (Blob_Size == BSEC_MAX_STATE_BLOB_SIZE)      // for now, see if we have blob size in FRAM... (should be CRC16 in future...) 
      {
        // we have an Existing state in FRAM
        Serial1.printf("*Reading state from FRAM\n");
    
        for (uint32_t i = 0; i < BSEC_MAX_STATE_BLOB_SIZE; i++) 
        {
          uint8_t rdata;
          FRAM.readByte(i + 1, &rdata);
          bsecState[i] = rdata;
    #ifdef DumpBLOB      
          Serial1.printf("%02x ", rdata);
          if (i % 16 == 15) { Serial1.print("\n"); }
          if ( i == (BSEC_MAX_STATE_BLOB_SIZE -1 )) { Serial1.print("\n"); }
    #endif 
        }
        
        iaqSensor.setState(bsecState);
        CheckSensor();
      } else
       
      {
        // Erase the FRAM with zeroes
        Serial1.printf("*Erasing FRAM\n");
    
        for (uint32_t i = BSEC_ADDR; i < BSEC_MAX_STATE_BLOB_SIZE + 1; i++)
          FRAM.writeByte(i, 0);
      }
    }
    
    
    /* ************************************************************** */
    void saveState(void)
    {
        iaqSensor.getState(bsecState);
        CheckSensor();  
        Serial1.printf("*Writing state to FRAM\n");
        for (uint32_t i = BSEC_ADDR; i < BSEC_MAX_STATE_BLOB_SIZE ; i++) 
        {
          FRAM.writeByte(i + 1, bsecState[i]);
    #ifdef DumpBLOB      
          Serial1.printf("%02x ", bsecState[i]);
          if (i % 16 == 15) { Serial1.print("\n"); }
          if ( i == (BSEC_MAX_STATE_BLOB_SIZE -1 )) { Serial1.print("\n"); }
    #endif  
        }   
    
        FRAM.writeByte(BSEC_ADDR, BSEC_MAX_STATE_BLOB_SIZE);        // save blob size as flag... (should be CRC16 in future...) 
    }
    
    /* ********************* The End ******************************** */
    /* ************************************************************** */

     

     

     

     

    ~~~

    handytech
    Community Moderator
    Community Moderator

    @lafleur wrote:

    In the library, you have a delay_ms that uses delay() function from Arduino… how is this used? Do I need to be concern about this when the MCU sleeps? if so, it would be nice if you would make this function __weak__ so that it can be overwritten in the main program.

    If not specified, the BSEC Software Library uses the default delay() function from Arduino. Alternatively, the last argument of the begin() functions can already be used to overwrite the default delay behavior with your own custom function. Delays are typically used within the BME680 sensor API (drivers) as well as during the measurement period of the sensor.


    @lafleur wrote:

    What is the relationship of sensor.nextCall to MCU sleep timing?


    BSEC expects timestamps to be continuous in time and sensor.nextCall represents the expected timestamp (in ms) at which bsec_sensor_control() - thus sensor.run() - should be called next. Therefore this value could be used to calculate how long you would put your MCU to sleep before the next measurement is needed.


    @lafleur wrote:

    Should BEC  state ONLY be saved if IAQ>3?


    It depends on your integration. If running continuously (e.g. without deep sleep), you could decide to save the state file only when the accuracy reaches 3. If you are running in deep sleep mode between measurements and the RAM content of your MCU (thus of BSEC internal states too) are wiped, it becomes mandatory to store/reload the state file between every single sample to retain the minimum mandatory information for BSEC to run.


    @lafleur wrote:

    I have been unable to get my test code to acquire an IAQ of anything other than zero when I attempted to sleep or delay for a fixed time… I based the code on the ESP32 example, but have been unable to make it work properly.

    I’m sure it’s something I’m missing or do not understand about using the BEQ library. Any ideas??


    If the IAQ accuracy remains at zero, it typically indicates some timing issues. BSEC requires accurate timings as determined by the selected operating mode, which is a sampling period of 3s in LP mode (or 300s in ULP mode). From your log and code, it looks like your are currently sampling at ~11s intervals (~10s sleep) time, which is most likely causing some internal warnings and preventing the accuracy from increasing.

    Thank you for the information...

     

    basically, I'm trying to use the sensor in an asynchronous process cycle where I want to trigger a request when I wake up...

    Is it possible with this device? what is the limitation of doing this? do I need to stay in the 3 or 300 seconds cycle time of the device??

    Is there an example on how to do this??

     

     

    handytech
    Community Moderator
    Community Moderator

    Timings are important for the performance of the sensor, therefore you must indeed follow the 3s or 300s sampling period requirement, and wake-up your system in time for the next measurement if needed.

    The esp32DeepSleep example could be used as reference for other platforms.

    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