Introduction

Smablo Air Quality Shield is based on the BME680 sensor which can measure gas, humidity, pressure and temperature.

Applications

Air quality module allows you to monitor indoor air quality and present it in form of Air-quality EPA Index. In simple words, it shows if air quality conditions are good, unhealthy or hazardous:

  • Indoor air quality
  • Home automaticion and control
  • Internet of things
  • Wearables
  • Accessories devices
  • Weather forcast
  • Indoor navigation(chanfge of floor detection, elevator detection)
  • Outdoor navigation, leisure and sports applications
  • Vertical velocity indication (rise/sink speed)
  • Etc.

Getting started

To get started with Smablo Air Quality Shield you will need:

TFrom Smablo Development Kit take Smablo CPU Shield and place it on Smablo Development board and do the same with Smablo Air Quality Shield just as you can see on the pictures and video below: {.force-inline} {.force-inline} {.force-inline} {.force-inline}

plugin:youtube

When you’ve done connecting Shields you can connect Smablo Development board to your computer with USB cable.

Example programs

To show you how to interact with Smablo Air Quality Shield open Visual Studio Code and from your Smablo SDK example directory and open bme680_bsec like it was shown at the video below:

bme680_bsec

If you will scroll down to the bottom of the bsec_manager_main_demo.c file you will see main configuration function called bsec_manager_demo_main. To compile and run the example press F5 button and then press run button on the top screen menu. The example will measure IAQ, humidity, pressure and temperature and print it on screen with use of RTT Viewer.

Minimal code

Minimal example code will show you how to program with Smablo Shields an app_bsec_manager.h driver.

//1
#include <stdio.h>
#include "app_bsec_manager.h"
#include "sm_timestamp.h"
#include "nrf_log.h"
#include "app_error.h"

//4
static void bsec_data_handler(const app_bsec_data_t* const p_bsec_data)
{
    char buff[100];

    snprintf(buff, sizeof(buff), "%llu:\t\tstatus: %d", p_bsec_data->timestamp/1000000000, p_bsec_data->bsec_status);
    NRF_LOG_RAW_DEBUG("%s\r\n", nrf_log_push(buff));

    if(p_bsec_data->temp_present) 
    {
        snprintf(buff, sizeof(buff), "\tTemp:\t\t%.2f oC", p_bsec_data->temp);
        NRF_LOG_RAW_DEBUG("%s\r\n", nrf_log_push(buff));
    }

    if(p_bsec_data->hum_present) 
    {
        snprintf(buff, sizeof(buff), "\tHum:\t\t%.2f %%Rh", p_bsec_data->hum);
        NRF_LOG_RAW_DEBUG("%s\r\n", nrf_log_push(buff));
    }

    if(p_bsec_data->press_present) 
    {
        snprintf(buff, sizeof(buff), "\tPress:\t%.0f Pa", p_bsec_data->press);
        NRF_LOG_RAW_DEBUG("%s\r\n", nrf_log_push(buff));
    }

    if(p_bsec_data->iaq_present) 
    {
        snprintf(buff, sizeof(buff), "\tIAQ:\t\t%.3f\tacc:%u", p_bsec_data->iaq, p_bsec_data->iaq_accuracy);
        NRF_LOG_RAW_DEBUG("%s\r\n", nrf_log_push(buff));
    }

    if(p_bsec_data->iaq_runin_present)
    {
        snprintf(buff, sizeof(buff), "\tIAQ runin:\t%.0f", p_bsec_data->iaq_runin);
        NRF_LOG_RAW_DEBUG("%s\r\n", nrf_log_push(buff));
    }
}

void bsec_manager_demo_main(void)
{
//2
    //initialize app_bsec
    bsec_library_return_t ret=app_bsec_init(APP_BSEC_SAMPLE_RATE_LP, bsec_data_handler, NULL);
//3 if(ret!=BSEC_OK)
    {
        NRF_LOG_ERROR("app_bsec_manager failed to initialize\r\n");
        APP_ERROR_CHECK(NRF_ERROR_INTERNAL);
    }
}

Minimal code example show how to use Air Quality Shield. Example is measuring temperature, humidity, pressure and IAQ (indoor air quality) and print them on screen.

In point 1 we need to include libraries and driver we will use in project.

#include "app_bsec_manager.h"
#include "sm_timestamp.h"
#include "nrf_log.h"
#include "app_error.h"
  • app_bsec_manager.h is a driver that we wil use to interact with Air Quality Shield
  • sm_timestamp.h is a library that will let us to measure timestamps
  • nrf_log.h is library that we will use to print log on screen log marcos
  • app_error.h is libary that will help us to check for errors

In point 2 we are initializing the Smablo Air Quality Shield with app_bsec_init function. Function is type bsec_library_return_t


/*!
 * @brief Enumeration for function return codes 
 */
typedef enum
{
    BSEC_OK = 0,                                    /*!< Function execution successful */
    BSEC_E_DOSTEPS_INVALIDINPUT = -1,               /*!< Input (physical) sensor id passed to bsec_do_steps() is not in the valid range or not valid for requested virtual sensor */
    BSEC_E_DOSTEPS_VALUELIMITS = -2,                /*!< Value of input (physical) sensor signal passed to bsec_do_steps() is not in the valid range */
    BSEC_E_DOSTEPS_DUPLICATEINPUT = -6,             /*!< Duplicate input (physical) sensor ids passed as input to bsec_do_steps() */
    BSEC_I_DOSTEPS_NOOUTPUTSRETURNABLE = 2,         /*!< No memory allocated to hold return values from bsec_do_steps(), i.e., n_outputs == 0 */
    BSEC_W_DOSTEPS_EXCESSOUTPUTS = 3,               /*!< Not enough memory allocated to hold return values from bsec_do_steps(), i.e., n_outputs < maximum number of requested output (virtual) sensors */
    BSEC_W_DOSTEPS_TSINTRADIFFOUTOFRANGE = 4,       /*!< Duplicate timestamps passed to bsec_do_steps() */
    BSEC_E_SU_WRONGDATARATE = -10,                  /*!< The sample_rate of the requested output (virtual) sensor passed to bsec_update_subscription() is zero */
    BSEC_E_SU_SAMPLERATELIMITS = -12,               /*!< The sample_rate of the requested output (virtual) sensor passed to bsec_update_subscription() does not match with the sampling rate allowed for that sensor */
    BSEC_E_SU_DUPLICATEGATE = -13,                  /*!< Duplicate output (virtual) sensor ids requested through bsec_update_subscription() */
    BSEC_E_SU_INVALIDSAMPLERATE = -14,              /*!< The sample_rate of the requested output (virtual) sensor passed to bsec_update_subscription() does not fall within the global minimum and maximum sampling rates  */
    BSEC_E_SU_GATECOUNTEXCEEDSARRAY = -15,          /*!< Not enough memory allocated to hold returned input (physical) sensor data from bsec_update_subscription(), i.e., n_required_sensor_settings < #BSEC_MAX_PHYSICAL_SENSOR */
    BSEC_E_SU_SAMPLINTVLINTEGERMULT = -16,          /*!< The sample_rate of the requested output (virtual) sensor passed to bsec_update_subscription() is not correct */
    BSEC_E_SU_MULTGASSAMPLINTVL = -17,              /*!< The sample_rate of the requested output (virtual), which requires the gas sensor, is not equal to the sample_rate that the gas sensor is being operated */
    BSEC_E_SU_HIGHHEATERONDURATION = -18,           /*!< The duration of one measurement is longer than the requested sampling interval */
    BSEC_W_SU_UNKNOWNOUTPUTGATE = 10,               /*!< Output (virtual) sensor id passed to bsec_update_subscription() is not in the valid range; e.g., n_requested_virtual_sensors > actual number of output (virtual) sensors requested */
    BSEC_I_SU_SUBSCRIBEDOUTPUTGATES = 12,           /*!< No output (virtual) sensor data were requested via bsec_update_subscription() */
    BSEC_E_PARSE_SECTIONEXCEEDSWORKBUFFER = -32,    /*!< n_work_buffer_size passed to bsec_set_[configuration/state]() not sufficient */
    BSEC_E_CONFIG_FAIL = -33,                       /*!< Configuration failed */
    BSEC_E_CONFIG_VERSIONMISMATCH = -34,            /*!< Version encoded in serialized_[settings/state] passed to bsec_set_[configuration/state]() does not match with current version */
    BSEC_E_CONFIG_FEATUREMISMATCH = -35,            /*!< Enabled features encoded in serialized_[settings/state] passed to bsec_set_[configuration/state]() does not match with current library implementation */
    BSEC_E_CONFIG_CRCMISMATCH = -36,                /*!< serialized_[settings/state] passed to bsec_set_[configuration/state]() is corrupted */
    BSEC_E_CONFIG_EMPTY = -37,                      /*!< n_serialized_[settings/state] passed to bsec_set_[configuration/state]() is to short to be valid */
    BSEC_E_CONFIG_INSUFFICIENTWORKBUFFER = -38,     /*!< Provided work_buffer is not large enough to hold the desired string */
    BSEC_E_CONFIG_INVALIDSTRINGSIZE = -40,          /*!< String size encoded in configuration/state strings passed to bsec_set_[configuration/state]() does not match with the actual string size n_serialized_[settings/state] passed to these functions */
    BSEC_E_CONFIG_INSUFFICIENTBUFFER = -41,         /*!< String buffer nsufficient to hold serialized data from BSEC library */
    BSEC_E_SET_INVALIDCHANNELIDENTIFIER = -100,     /*!< Internal error code */
    BSEC_E_SET_INVALIDLENGTH = -104,                /*!< Internal error code */
    BSEC_W_SC_CALL_TIMING_VIOLATION = 100,          /*!< Difference between actual and defined sampling intervals of bsec_sensor_control() greater than allowed */
} bsec_library_return_t;

Which holds possible states of the shield. app_bsec_init function takes 3 parameters.

  • sample_rate type app_bsec_sample_rate_t

    ///Sample rate setting enum
    typedef enum
    {
        APP_BSEC_SAMPLE_RATE_LP=0,  ///< 'Low power mode' - 1 sample every 3 seconds, high current usage, recommended only for development
        APP_BSEC_SAMPLE_RATE_ULP    ///< 'Ultra low power mode' - 1 sample every 300 seconds, low current usage, recommended mode
    
    } app_bsec_sample_rate_t;

    parameter which determnes the sample rate of measurements. W can choose between APP_BSEC_SAMPLE_RATE_LP which will return measurements every 3 second and is desined for development debug and testing and APP_BSEC_SAMPLE_RATE_ULP which is ultra low power mode designed for end usage, this mode will sample measurment every 300 seconds.

  • drdy_handler type app_bsec_drdy_handler_t which is pointer to user defined handler which will execute with rate confugured in sample_rate parameter. The hanler will also give you access to app_bsec_data_t structure which will hold the most recent measurements. The app_bsec_data_t holds following components :

    ///Data container returned by BSEC to data ready handler
    typedef struct
    {
        int64_t timestamp;                      ///< Measurement timestamp in nanoseconds
        bsec_library_return_t bsec_status;      ///< BSEC status, non zero indicates error
    
        float iaq;                              ///< Indoor Air Quality index value
        uint8_t iaq_accuracy;                   ///< iaq measurement accuracy:
                                                ///< 0 - The sensor is not yet stablized or in a run-in status
                                                ///< 1 - Calibration required but not enough data to perform it at this time
                                                ///< 2 - Calibration on-going
                                                ///< 3 - Calibration is done, now IAQ estimate achieves best perfomance
        bool iaq_present;                       ///< if true iaq measurement is present in this structure
    
        float iaq_runin;                        ///< iaq sensor run-in status 1= run in complete
        bool iaq_runin_present;                 ///< if true run in signal is present
    
        float temp;                             ///< temperature in Centigrade
        bool temp_present;                      ///< if true temperature signal is present
    
        float hum;                              ///< relative humidity in % Rh
        bool hum_present;                       ///< if true humidity signal is present
    
        float press;                            ///< pressure in Pa
        bool press_present;                     ///< if true pressure signal is present
    } app_bsec_data_t;
    
    • timestamp type int64_t is a measurement timestamp of the measurement
    • bsec_status type bsec_library_return_t
    /*!
    * @brief Enumeration for function return codes 
    */
    typedef enum
    {
        BSEC_OK = 0,                                    /*!< Function execution successful */
        BSEC_E_DOSTEPS_INVALIDINPUT = -1,               /*!< Input (physical) sensor id passed to bsec_do_steps() is not in the valid range or not valid for requested virtual sensor */
        BSEC_E_DOSTEPS_VALUELIMITS = -2,                /*!< Value of input (physical) sensor signal passed to bsec_do_steps() is not in the valid range */
        BSEC_E_DOSTEPS_DUPLICATEINPUT = -6,             /*!< Duplicate input (physical) sensor ids passed as input to bsec_do_steps() */
        BSEC_I_DOSTEPS_NOOUTPUTSRETURNABLE = 2,         /*!< No memory allocated to hold return values from bsec_do_steps(), i.e., n_outputs == 0 */
        BSEC_W_DOSTEPS_EXCESSOUTPUTS = 3,               /*!< Not enough memory allocated to hold return values from bsec_do_steps(), i.e., n_outputs < maximum number of requested output (virtual) sensors */
        BSEC_W_DOSTEPS_TSINTRADIFFOUTOFRANGE = 4,       /*!< Duplicate timestamps passed to bsec_do_steps() */
        BSEC_E_SU_WRONGDATARATE = -10,                  /*!< The sample_rate of the requested output (virtual) sensor passed to bsec_update_subscription() is zero */
        BSEC_E_SU_SAMPLERATELIMITS = -12,               /*!< The sample_rate of the requested output (virtual) sensor passed to bsec_update_subscription() does not match with the sampling rate allowed for that sensor */
        BSEC_E_SU_DUPLICATEGATE = -13,                  /*!< Duplicate output (virtual) sensor ids requested through bsec_update_subscription() */
        BSEC_E_SU_INVALIDSAMPLERATE = -14,              /*!< The sample_rate of the requested output (virtual) sensor passed to bsec_update_subscription() does not fall within the global minimum and maximum sampling rates  */
        BSEC_E_SU_GATECOUNTEXCEEDSARRAY = -15,          /*!< Not enough memory allocated to hold returned input (physical) sensor data from bsec_update_subscription(), i.e., n_required_sensor_settings < #BSEC_MAX_PHYSICAL_SENSOR */
        BSEC_E_SU_SAMPLINTVLINTEGERMULT = -16,          /*!< The sample_rate of the requested output (virtual) sensor passed to bsec_update_subscription() is not correct */
        BSEC_E_SU_MULTGASSAMPLINTVL = -17,              /*!< The sample_rate of the requested output (virtual), which requires the gas sensor, is not equal to the sample_rate that the gas sensor is being operated */
        BSEC_E_SU_HIGHHEATERONDURATION = -18,           /*!< The duration of one measurement is longer than the requested sampling interval */
        BSEC_W_SU_UNKNOWNOUTPUTGATE = 10,               /*!< Output (virtual) sensor id passed to bsec_update_subscription() is not in the valid range; e.g., n_requested_virtual_sensors > actual number of output (virtual) sensors requested */
        BSEC_I_SU_SUBSCRIBEDOUTPUTGATES = 12,           /*!< No output (virtual) sensor data were requested via bsec_update_subscription() */
        BSEC_E_PARSE_SECTIONEXCEEDSWORKBUFFER = -32,    /*!< n_work_buffer_size passed to bsec_set_[configuration/state]() not sufficient */
        BSEC_E_CONFIG_FAIL = -33,                       /*!< Configuration failed */
        BSEC_E_CONFIG_VERSIONMISMATCH = -34,            /*!< Version encoded in serialized_[settings/state] passed to bsec_set_[configuration/state]() does not match with current version */
        BSEC_E_CONFIG_FEATUREMISMATCH = -35,            /*!< Enabled features encoded in serialized_[settings/state] passed to bsec_set_[configuration/state]() does not match with current library implementation */
        BSEC_E_CONFIG_CRCMISMATCH = -36,                /*!< serialized_[settings/state] passed to bsec_set_[configuration/state]() is corrupted */
        BSEC_E_CONFIG_EMPTY = -37,                      /*!< n_serialized_[settings/state] passed to bsec_set_[configuration/state]() is to short to be valid */
        BSEC_E_CONFIG_INSUFFICIENTWORKBUFFER = -38,     /*!< Provided work_buffer is not large enough to hold the desired string */
        BSEC_E_CONFIG_INVALIDSTRINGSIZE = -40,          /*!< String size encoded in configuration/state strings passed to bsec_set_[configuration/state]() does not match with the actual string size n_serialized_[settings/state] passed to these functions */
        BSEC_E_CONFIG_INSUFFICIENTBUFFER = -41,         /*!< String buffer nsufficient to hold serialized data from BSEC library */
        BSEC_E_SET_INVALIDCHANNELIDENTIFIER = -100,     /*!< Internal error code */
        BSEC_E_SET_INVALIDLENGTH = -104,                /*!< Internal error code */
        BSEC_W_SC_CALL_TIMING_VIOLATION = 100,          /*!< Difference between actual and defined sampling intervals of bsec_sensor_control() greater than allowed */
    } bsec_library_return_t;
    

    Which are are function error codes that descibe the state of the shield.

    • iaq type float which is Indoor Air Quality index value. This index can have values from 0 to 500 with resolution of 1 to indicate or quantify the quality of the surrinding air.
    • iaq_accuracy type uint8_t is an IAQ measurement accuracy:
      • 0 - The sensor is not yet stablized or in a run-in status
      • 1 - Calibration required but not enough data to perform it at this time
      • 2 - Calibration on-going
      • 3 - Calibration is done, now IAQ estimate achieves best perfomance
    • iaq_present type bool when value of parameter is True IAQ new measurement is present in this structure
    • iaq_runin type float iaq sensor run-in status 1 = run in complete. Indicates when sensor oos ready after switch-on
    • iaq_runin_present type bool if true run in signal is present
    • temp type float temperature value in Centigrade ( -40…85°C) with ±1.0°C accuracy
    • temp_present type bool when value of parameter is True new temperature measurement is present in this structure
    • hum type float relative humidity in % Rh (0…100%) with ±3% accuracy
    • hum_present type bool when value of parameter is True new humidity measurement is present in this structure
    • press type float pressure in Pa (300...1100 hPa) with ±1 hPa absolute accuracy
    • press_present type bool when value of parameter is True new pressure measurement is present in this structure
  • error_handler type app_bsec_error_handler_t which is pointer to user defined error handler function that will execute when error occurs

In point 3 we check if initialization went ok if not the error code is printed on screen.

In point 4 bsec_data_handler handler taht will be called every 3 seconds in this example will print all measurement on screen with use of log marcos.

app_bsec_manager library reference

app_bsec_init

Prototype:

bsec_library_return_t app_bsec_init(app_bsec_sample_rate_t sample_rate, app_bsec_drdy_handler_t drdy_handler, app_bsec_error_handler_t error_handler);

Function is used to initialize the Air Quality Shield configure sampling data rate configure user defined handler and user defined error handler. This is the only function in app_bsec_manager driver and its usage was described in Minimal code chapter