Bosch Sensortec Community

    Showing results for 
    Search instead for 
    Did you mean: 

    BSEC BME680 no IAQ output

    BSEC BME680 no IAQ output


    I have an issue with bsec light version Everything seems to work, however I receive only 5 outputs and no IAQ output, even though I requested it. I base strongly on example from BSEC_1.4.8.0_Generic_Release_updated_v3
    I use BME680 sensor, which is configured in low power mode.

    I update structure and init sensor:






        gas_sensor.dev_id = BME680_I2C_ADDR_SECONDARY;
        gas_sensor.intf = BME680_I2C_INTF; = user_i2c_read;
        gas_sensor.write = user_i2c_write;
        gas_sensor.delay_ms = delay;
        /* amb_temp can be set to 25 prior to configuring the gas sensor
         * or by performing a few temperature readings without operating the gas sensor.
        gas_sensor.amb_temp = 25;
       bsec_library_return_t status = BSEC_OK;
        auto result = bme680_init(&gas_sensor);
        KD_ERROR_IF(result != 0, KD_BME680_BSEC, "Error initializing: %d", result);
        status = bsec_init();
        KD_ERROR_IF(status != BSEC_OK, KD_BME680_BSEC, "Error initializing bsec: %d", status);
        bsec_version_t bsec_ver;
        status = bsec_get_version(&bsec_ver);
        KD_INFO(KD_BME680_BSEC, "BSEC bsec_get_version res: %d", (int)status);
        KD_INFO(KD_BME680_BSEC, "BSEC version %d.%d.%d.%d", bsec_ver.major, bsec_ver.minor, bsec_ver.major_bugfix,
        status = bme680_bsec_update_subscription(BSEC_SAMPLE_RATE_LP);
        KD_ERROR_IF(status != BSEC_OK, KD_BME680_BSEC, "Error initializing bsec sensors init: %d", status);






    Then I call every specified time definded by next_call ( mostly 2920 ms) function:






       KD_DEBUG(KD_BME680_BSEC, "fetchData");
        bsec_library_return_t status = BSEC_OK;
        int8_t result = BME680_OK;
        /* time stamp */
        int64_t time_stamp = (int64_t)(m_clock->getMillisecondsSinceBoot()) * INT64_C(1000) * INT64_C(1000);  // nanoseconds;
        int64_t time_stamp_interval_ms = 0;
        /* BSEC sensor settings struct */
        bsec_bme_settings_t sensor_settings;
        /* Allocate enough memory for up to BSEC_MAX_PHYSICAL_SENSOR physical inputs*/
        bsec_input_t bsec_inputs[BSEC_MAX_PHYSICAL_SENSOR];
        /* Number of inputs to BSEC */
        uint8_t num_bsec_inputs = 0;
        // tmp
        KD_DEBUG_DUMP_MEMORY(KD_BME680_BSEC, "Timestamp nano       ", tmp, sizeof(tmp));
        // tmp
        /* Retrieve sensor settings to be used in this time instant by calling bsec_sensor_control */
        status = bsec_sensor_control(time_stamp, &sensor_settings);
        KD_ERROR_IF(status != BSEC_OK, KD_BME680_BSEC, "Error initializing bsec_sensor_control: %d", status);
        /* Trigger a measurement if necessary */
        result = bme680_bsec_trigger_measurement(&sensor_settings, delay);
        KD_ERROR_IF(result != BME680_OK, KD_BME680_BSEC, "Error initializing bme680_bsec_trigger_measurement: %d", result);
        /* Read data from last measurement */
        result = bme680_bsec_read_data(time_stamp, bsec_inputs, &num_bsec_inputs, sensor_settings.process_data);
        KD_ERROR_IF(result != BME680_OK, KD_BME680_BSEC, "Error initializing bme680_bsec_read_data: %d", result);
        KD_DEBUG(KD_BME680_BSEC, "num_bsec_inputs %d", num_bsec_inputs);
        /* Time to invoke BSEC to perform the actual processing */
        status = bme680_bsec_process_data(bsec_inputs, num_bsec_inputs, output_ready);
        KD_ERROR_IF(status != BSEC_OK, KD_BME680_BSEC, "Error initializing bme680_bsec_process_data: %d", status);
        time_stamp_interval_ms =
            (sensor_settings.next_call - (m_clock->getMillisecondsSinceBoot() * (int64_t)1000 * (int64_t)1000)) /
        KD_DEBUG(KD_BME680_BSEC, "Wakeup in %u ms", (uint32_t)time_stamp_interval_ms);






    following support functioins are used:






    static void output_ready(int64_t timestamp, float iaq, uint8_t iaq_accuracy, float temperature, float humidity,
                             float pressure, float raw_temperature, float raw_humidity, float gas,
                             bsec_library_return_t bsec_status, float static_iaq, uint8_t static_iaq_accuracy,
                             float co2_equivalent, uint8_t co2_accuracy, float breath_voc_equivalent,
                             uint8_t breath_voc_accuracy, float gas_percentage, uint8_t gas_percentage_acccuracy,
                             float comp_gas, uint8_t comp_gas_accuracy) {
        KD_DEBUG(KD_BME680_BSEC, "Bsec status: %d", bsec_status);
        KD_DEBUG(KD_BME680_BSEC, "Timestamp: %ld", timestamp / 1e6);
        KD_DEBUG(KD_BME680_BSEC, "Temperature: %d", (int)temperature);
        KD_DEBUG(KD_BME680_BSEC, "Temperature raw: %d", (int)raw_temperature);
        KD_DEBUG(KD_BME680_BSEC, "Pressure: %d", (int)pressure);
        KD_DEBUG(KD_BME680_BSEC, "Humidity: %d", (int)humidity);
        KD_DEBUG(KD_BME680_BSEC, "Humidity raw: %d", (int)raw_humidity);
        KD_DEBUG(KD_BME680_BSEC, "IAQ: %d", (int)iaq);
        KD_DEBUG(KD_BME680_BSEC, "IAQ accurway: %d", iaq_accuracy);
        KD_DEBUG(KD_BME680_BSEC, "IAQ static: %d", (int)static_iaq);
        KD_DEBUG(KD_BME680_BSEC, "IAQ static accurtacy: %d", static_iaq_accuracy);
        KD_DEBUG(KD_BME680_BSEC, "CO2 equivalent: %d", (int)co2_equivalent);
        KD_DEBUG(KD_BME680_BSEC, "CO2 equivalent accuracy: %d", co2_accuracy);
        KD_DEBUG(KD_BME680_BSEC, "VOC: %d", (int)breath_voc_equivalent);
        KD_DEBUG(KD_BME680_BSEC, "VOC accuracy: %d", breath_voc_accuracy);
        KD_DEBUG(KD_BME680_BSEC, "gas: %d", (int)gas);
        KD_DEBUG(KD_BME680_BSEC, "gas_percentage: %d", (int)gas_percentage);
        KD_DEBUG(KD_BME680_BSEC, "gas_percentage_acccuracy: %d", gas_percentage_acccuracy);
        KD_DEBUG(KD_BME680_BSEC, "comp_gas: %d", (int)comp_gas);
        KD_DEBUG(KD_BME680_BSEC, "comp_gas_accuracy: %d", comp_gas_accuracy);
    bsec_library_return_t Bme680bsec::bme680_bsec_update_subscription(float sample_rate) {
        bsec_sensor_configuration_t requested_virtual_sensors[NUM_USED_OUTPUTS];
        uint8_t n_requested_virtual_sensors = NUM_USED_OUTPUTS;
        bsec_sensor_configuration_t required_sensor_settings[BSEC_MAX_PHYSICAL_SENSOR];
        uint8_t n_required_sensor_settings = BSEC_MAX_PHYSICAL_SENSOR;
        bsec_library_return_t status = BSEC_OK;
        /* note: Virtual sensors as desired to be added here */
        requested_virtual_sensors[0].sensor_id = BSEC_OUTPUT_IAQ;
        requested_virtual_sensors[0].sample_rate = sample_rate;
        requested_virtual_sensors[1].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE;
        requested_virtual_sensors[1].sample_rate = sample_rate;
        requested_virtual_sensors[2].sensor_id = BSEC_OUTPUT_RAW_PRESSURE;
        requested_virtual_sensors[2].sample_rate = sample_rate;
        requested_virtual_sensors[3].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY;
        requested_virtual_sensors[3].sample_rate = sample_rate;
        requested_virtual_sensors[4].sensor_id = BSEC_OUTPUT_RAW_GAS;
        requested_virtual_sensors[4].sample_rate = sample_rate;
        requested_virtual_sensors[5].sensor_id = BSEC_OUTPUT_RAW_TEMPERATURE;
        requested_virtual_sensors[5].sample_rate = sample_rate;
        requested_virtual_sensors[6].sensor_id = BSEC_OUTPUT_RAW_HUMIDITY;
        requested_virtual_sensors[6].sample_rate = sample_rate;
        requested_virtual_sensors[7].sensor_id = BSEC_OUTPUT_STATIC_IAQ;
        requested_virtual_sensors[7].sample_rate = sample_rate;
        /* Call bsec_update_subscription() to enable/disable the requested virtual sensors */
        status = bsec_update_subscription(requested_virtual_sensors, n_requested_virtual_sensors, required_sensor_settings,
        return status;
    int8_t Bme680bsec::bme680_bsec_trigger_measurement(bsec_bme_settings_t* sensor_settings, sleep_fct sleep) {
        uint16_t meas_period;
        uint8_t set_required_settings;
        int8_t bme680_status = BME680_OK;
        /* Check if a forced-mode measurement should be triggered now */
        if (sensor_settings->trigger_measurement) {
            /* Set sensor configuration */
            gas_sensor.tph_sett.os_hum = sensor_settings->humidity_oversampling;
            gas_sensor.tph_sett.os_pres = sensor_settings->pressure_oversampling;
            gas_sensor.tph_sett.os_temp = sensor_settings->temperature_oversampling;
            gas_sensor.gas_sett.run_gas = sensor_settings->run_gas;
            gas_sensor.gas_sett.heatr_temp = sensor_settings->heater_temperature; /* degree Celsius */
            /* Select the power mode */
            /* Must be set before writing the sensor configuration */
            gas_sensor.power_mode = BME680_FORCED_MODE;
            /* Set the required sensor settings needed */
            set_required_settings = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_GAS_MEAS_SEL;
            /* Set the desired sensor configuration */
            bme680_status = bme680_set_sensor_settings(set_required_settings, &gas_sensor);
            if (bme680_status != BME680_OK) return bme680_status;
            /* Set power mode as forced mode and trigger forced mode measurement */
            bme680_status = bme680_set_sensor_mode(&gas_sensor);
            if (bme680_status != BME680_OK) return bme680_status;
            /* Get the total measurement duration so as to sleep or wait till the measurement is complete */
            bme680_get_profile_dur(&meas_period, &gas_sensor);
            /* Delay till the measurement is ready. Timestamp resolution in ms */
            return bme680_status;
        /* Call the API to get current operation mode of the sensor */
        bme680_status = bme680_get_sensor_mode(&gas_sensor);
        /* When the measurement is completed and data is ready for reading, the sensor must be in BME680_SLEEP_MODE.
         * Read operation mode to check whether measurement is completely done and wait until the sensor is no more
         * in BME680_FORCED_MODE. */
        while (gas_sensor.power_mode == BME680_FORCED_MODE) {
            /* sleep for 5 ms */
            bme680_status = bme680_get_sensor_mode(&gas_sensor);
            if (bme680_status != BME680_OK) return bme680_status;
        return bme680_status;
    int8_t Bme680bsec::bme680_bsec_read_data(int64_t time_stamp_trigger, bsec_input_t* inputs, uint8_t* num_bsec_inputs,
                                             int32_t bsec_process_data) {
        static struct bme680_field_data data;
        int8_t bme680_status = BME680_OK;
        /* We only have to read data if the previous call the bsec_sensor_control() actually asked for it */
        if (bsec_process_data) {
            bme680_status = bme680_get_sensor_data(&data, &gas_sensor);
            if (bme680_status != BME680_OK) return bme680_status;
            KD_DEBUG(KD_BME680_BSEC, "BSEC data staus %d bsec_process_data %d", data.status, bsec_process_data);
            if (data.status & BME680_NEW_DATA_MSK) {
                /* Pressure to be processed by BSEC */
                if (bsec_process_data & BSEC_PROCESS_PRESSURE) {
                    /* Place presssure sample into input struct */
                    inputs[*num_bsec_inputs].sensor_id = BSEC_INPUT_PRESSURE;
                    inputs[*num_bsec_inputs].signal = data.pressure;
                    inputs[*num_bsec_inputs].time_stamp = time_stamp_trigger;
                    KD_DEBUG(KD_BME680_BSEC, "BSEC data pressure %d", (int)data.pressure);
                /* Temperature to be processed by BSEC */
                if (bsec_process_data & BSEC_PROCESS_TEMPERATURE) {
                    /* Place temperature sample into input struct */
                    inputs[*num_bsec_inputs].sensor_id = BSEC_INPUT_TEMPERATURE;
                    inputs[*num_bsec_inputs].signal = data.temperature;
                    inputs[*num_bsec_inputs].signal = data.temperature / 100.0f;
                    inputs[*num_bsec_inputs].time_stamp = time_stamp_trigger;
                    KD_DEBUG(KD_BME680_BSEC, "BSEC data temperature %d", (int)data.temperature);
                    /* Also add optional heatsource input which will be subtracted from the temperature reading to
                     * compensate for device-specific self-heating (supported in BSEC IAQ solution)*/
                    inputs[*num_bsec_inputs].sensor_id = BSEC_INPUT_HEATSOURCE;
                    inputs[*num_bsec_inputs].signal = bme680_temperature_offset_g;
                    inputs[*num_bsec_inputs].time_stamp = time_stamp_trigger;
                /* Humidity to be processed by BSEC */
                if (bsec_process_data & BSEC_PROCESS_HUMIDITY) {
                    /* Place humidity sample into input struct */
                    inputs[*num_bsec_inputs].sensor_id = BSEC_INPUT_HUMIDITY;
                    inputs[*num_bsec_inputs].signal = data.humidity;
                    inputs[*num_bsec_inputs].signal = data.humidity / 1000.0f;
                    inputs[*num_bsec_inputs].time_stamp = time_stamp_trigger;
                    KD_DEBUG(KD_BME680_BSEC, "BSEC data humidity %d", (int)data.humidity);
                /* Gas to be processed by BSEC */
                if (bsec_process_data & BSEC_PROCESS_GAS) {
                    /* Check whether gas_valid flag is set */
                    if (data.status & BME680_GASM_VALID_MSK) {
                        /* Place sample into input struct */
                        inputs[*num_bsec_inputs].sensor_id = BSEC_INPUT_GASRESISTOR;
                        inputs[*num_bsec_inputs].signal = data.gas_resistance;
                        inputs[*num_bsec_inputs].time_stamp = time_stamp_trigger;
                        KD_DEBUG(KD_BME680_BSEC, "BSEC data gas_resistance %d", (int)data.gas_resistance);
                    KD_DEBUG(KD_BME680_BSEC, "BSEC data gas_resistance %d", (int)data.gas_resistance);
        return bme680_status;
    bsec_library_return_t Bme680bsec::bme680_bsec_process_data(bsec_input_t* bsec_inputs, uint8_t num_bsec_inputs,
                                                               output_ready_fct output_ready) {
        /* Output buffer set to the maximum virtual sensor outputs supported */
        bsec_output_t bsec_outputs[BSEC_NUMBER_OUTPUTS];
        uint8_t num_bsec_outputs = 0;
        uint8_t index = 0;
        bsec_library_return_t bsec_status = BSEC_OK;
        int64_t timestamp = 0;
        float iaq = 0.0f;
        uint8_t iaq_accuracy = 0;
        float temp = 0.0f;
        float raw_temp = 0.0f;
        float raw_pressure = 0.0f;
        float humidity = 0.0f;
        float raw_humidity = 0.0f;
        float raw_gas = 0.0f;
        float static_iaq = 0.0f;
        uint8_t static_iaq_accuracy = 0;
        float co2_equivalent = 0.0f;
        uint8_t co2_accuracy = 0;
        float breath_voc_equivalent = 0.0f;
        uint8_t breath_voc_accuracy = 0;
        float comp_gas_value = 0.0f;
        uint8_t comp_gas_accuracy = 0;
        float gas_percentage = 0.0f;
        uint8_t gas_percentage_acccuracy = 0;
        /* Check if something should be processed by BSEC */
        if (num_bsec_inputs > 0) {
            /* Set number of outputs to the size of the allocated buffer */
            /* BSEC_NUMBER_OUTPUTS to be defined */
            num_bsec_outputs = BSEC_NUMBER_OUTPUTS;
            /* Perform processing of the data by BSEC
               * The number of outputs you get depends on what you asked for during bsec_update_subscription(). This is
                 handled under bme680_bsec_update_subscription() function in this example file.
               * The number of actual outputs that are returned is written to num_bsec_outputs. */
            bsec_status = bsec_do_steps(bsec_inputs, num_bsec_inputs, bsec_outputs, &num_bsec_outputs);
            if (bsec_status != BME680_OK) return bsec_status;
            KD_DEBUG(KD_BME680_BSEC, "num_bsec_outputs %d", num_bsec_outputs);
            /* Iterate through the outputs and extract the relevant ones. */
            for (index = 0; index < num_bsec_outputs; index++) {
                switch (bsec_outputs[index].sensor_id) {
                    case BSEC_OUTPUT_IAQ:
                        KD_DEBUG(KD_BME680_BSEC, "BSEC_OUTPUT_IAQ");
                        iaq = bsec_outputs[index].signal;
                        iaq_accuracy = bsec_outputs[index].accuracy;
                    case BSEC_OUTPUT_STATIC_IAQ:
                        KD_DEBUG(KD_BME680_BSEC, "BSEC_OUTPUT_STATIC_IAQ");
                        static_iaq = bsec_outputs[index].signal;
                        static_iaq_accuracy = bsec_outputs[index].accuracy;
                    case BSEC_OUTPUT_CO2_EQUIVALENT:
                        KD_DEBUG(KD_BME680_BSEC, "BSEC_OUTPUT_CO2_EQUIVALENT");
                        co2_equivalent = bsec_outputs[index].signal;
                        co2_accuracy = bsec_outputs[index].accuracy;
                    case BSEC_OUTPUT_BREATH_VOC_EQUIVALENT:
                        breath_voc_equivalent = bsec_outputs[index].signal;
                        breath_voc_accuracy = bsec_outputs[index].accuracy;
                        temp = bsec_outputs[index].signal;
                    case BSEC_OUTPUT_RAW_PRESSURE:
                        KD_DEBUG(KD_BME680_BSEC, "BSEC_OUTPUT_RAW_PRESSURE");
                        raw_pressure = bsec_outputs[index].signal;
                        humidity = bsec_outputs[index].signal;
                    case BSEC_OUTPUT_RAW_GAS:
                        KD_DEBUG(KD_BME680_BSEC, "BSEC_OUTPUT_RAW_GAS");
                        raw_gas = bsec_outputs[index].signal;
                    case BSEC_OUTPUT_RAW_TEMPERATURE:
                        KD_DEBUG(KD_BME680_BSEC, "BSEC_OUTPUT_RAW_TEMPERATURE");
                        raw_temp = bsec_outputs[index].signal;
                    case BSEC_OUTPUT_RAW_HUMIDITY:
                        KD_DEBUG(KD_BME680_BSEC, "BSEC_OUTPUT_RAW_HUMIDITY");
                        raw_humidity = bsec_outputs[index].signal;
                    case BSEC_OUTPUT_COMPENSATED_GAS:
                        KD_DEBUG(KD_BME680_BSEC, "BSEC_OUTPUT_COMPENSATED_GAS");
                        comp_gas_value = bsec_outputs[index].signal;
                        comp_gas_accuracy = bsec_outputs[index].accuracy;
                    case BSEC_OUTPUT_GAS_PERCENTAGE:
                        KD_DEBUG(KD_BME680_BSEC, "BSEC_OUTPUT_GAS_PERCENTAGE");
                        gas_percentage = bsec_outputs[index].signal;
                        gas_percentage_acccuracy = bsec_outputs[index].accuracy;
                /* Assume that all the returned timestamps are the same */
                timestamp = bsec_outputs[index].time_stamp;
            /* Pass the extracted outputs to the user provided output_ready() function. */
            output_ready(timestamp, iaq, iaq_accuracy, temp, humidity, raw_pressure, raw_temp, raw_humidity, raw_gas,
                         bsec_status, static_iaq, static_iaq_accuracy, co2_equivalent, co2_accuracy, breath_voc_equivalent,
                         breath_voc_accuracy, gas_percentage, gas_percentage_acccuracy, comp_gas_value, comp_gas_accuracy);
        return bsec_status;





    I noticed that timestamp in output function is always the same, is it correct bsec framework behaviour?

    I have checked normal version without config and with bsec_config_iaq, unfortunately results are exactly the same.


    What is the potenial reason, that I provide neccesary inputs, timestamps, I receive no error and in the outputs there is no IAQ value in every case?


    I studied all provided documents and I cannot find bug in my code. I attached also log file from device.
    Could you help me solve that mistert?
    Thank you in advance,


    15 REPLIES 15

    Community Moderator
    Community Moderator

    Hi MJ_kio,

    You only need to modify the interface related to your hardware platform, such as bus_write(), bus_read(), sleep(), get_timestamp_us(). Do not modify other parts of the reference code and then run bsec_iot_example.ino. And see the run test.

    Hi BSTRobin,

    I have done it basically, I am not working in Ardiuno enviormnent, our platform is based on nrf52. I cannot use directly init and loop functions, I use unchanged functions from mentioned functions bodies.

    I tested provided example on ESP8266 and the accuracy was all the time 1 - could you advice how to improve it?

    I noticed the only difference between Arduino example project and project based on nrf52 - timestamp from bsec do_step function. In Arduino input timestamp and output timestamp are the same. In nrf project I provide correct timestamp as input, however output timestamp is constant and not changing. Do you have an idea why?

    Thank you for your support,

    @BSTRobinany thoughts?

    Community Moderator
    Community Moderator

    Hi MJ_kio,

    Before run bsec_do_steps() function, are your input data and units correct?