Skip to content
Snippets Groups Projects
Unverified Commit 98df85ff authored by Birte Kristina Friesel's avatar Birte Kristina Friesel
Browse files

add bme680 iaq test application

parent 7fae56dd
No related branches found
No related tags found
No related merge requests found
# Copyright 2020 Daniel Friesel
#
# SPDX-License-Identifier: CC0-1.0
prompt "BME680 BSEC logger"
depends on driver_bme680_bsec && meta_driver_uptime && loop && !wakeup
/*
* Copyright 2020 Daniel Friesel
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "arch.h"
#include "driver/gpio.h"
#include "driver/stdout.h"
#include "driver/uptime.h"
#if defined(CONFIG_meta_driver_hardware_i2c)
#include "driver/i2c.h"
#elif defined(CONFIG_driver_softi2c)
#include "driver/soft_i2c.h"
#endif
#include "driver/bme680.h"
#include "driver/bme680_util.h"
#include "driver/bme680-bsec-armv6/bsec_interface.h"
const char* accuracy[] = {"(unreliable)", "(calibration required)", "(auto-trim in progress)", ""};
void loop(void)
{
static bsec_bme_settings_t sensor_settings;
struct bme680_field_data data;
bsec_input_t bsec_inputs[BSEC_MAX_PHYSICAL_SENSOR];
bsec_output_t bsec_outputs[BSEC_NUMBER_OUTPUTS];
uint8_t num_bsec_inputs = 0;
uint8_t num_bsec_outputs = BSEC_NUMBER_OUTPUTS;
int64_t now = uptime.get_us() * 1000;
uint32_t now_s = uptime.get_s();
/*
* BSEC expects the application to observe precise timing constraints.
* After each call to bsec_sensor_control, sensor_settings.next_call is set
* to the nanosecond timestamp of the next call. Significant violations
* cause bsec_sensor_control to return a BSEC_W_SC_CALL_TIMING_VIOLATION
* warning.
*/
if (now < sensor_settings.next_call) {
if (sensor_settings.next_call - now < 1000000000) {
// less than one second -> sleep
arch.delay_us((sensor_settings.next_call - now) / 1000);
now = uptime.get_us() * 1000;
} else {
// more than one second -> next loop() call is sufficient
return;
}
}
/*
* Retrieve sensor configuration from BSEC. In our case, it's fairly simple:
* all virtual sensors are set to the same sample rate, so we expect
* physical sensor readings to be the same for each BSEC call. However,
* if we disable virtual sensors, or change their sample rate, this is
* no longer the case.
* Also, bsec_sensor_control controls sensor_settings.next_call, so we
* need to call it anyways.
*/
bsec_library_return_t status = bsec_sensor_control(now, &sensor_settings);
if (status < 0) {
kout << "bsec_sensor_control error: " << status << endl;
return;
}
if (status > 0) {
kout << "bsec_sensor_control warning: " << status << endl;
}
/*
* bsec_sensor_control tells us whether it needs new sensor data or
* not. If so: configure the sensor as indicated and perform a measurement.
*/
if (sensor_settings.trigger_measurement) {
bme680.tph_sett.os_hum = sensor_settings.humidity_oversampling;
bme680.tph_sett.os_pres = sensor_settings.pressure_oversampling;
bme680.tph_sett.os_temp = sensor_settings.temperature_oversampling;
bme680.gas_sett.run_gas = sensor_settings.run_gas;
bme680.gas_sett.heatr_temp = sensor_settings.heater_temperature;
bme680.gas_sett.heatr_dur = sensor_settings.heating_duration;
bme680.power_mode = BME680_FORCED_MODE;
bme680.setSensorSettings(BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_GAS_SENSOR_SEL);
bme680.setSensorMode();
/*
* TODO recent versions of the bme680 open-source driver are able to
* calculate the required delay.
*/
arch.delay_ms(250);
do {
arch.delay_ms(5);
bme680.getSensorMode();
} while (bme680.power_mode == BME680_FORCED_MODE);
if (sensor_settings.process_data) {
bme680.getSensorData(&data);
if (data.status & BME680_NEW_DATA_MSK) {
if (sensor_settings.process_data & BSEC_PROCESS_TEMPERATURE) {
bsec_inputs[num_bsec_inputs].sensor_id = BSEC_INPUT_TEMPERATURE;
bsec_inputs[num_bsec_inputs].signal = data.temperature / 100.0f;
bsec_inputs[num_bsec_inputs].time_stamp = now;
num_bsec_inputs++;
}
if (sensor_settings.process_data & BSEC_PROCESS_HUMIDITY) {
bsec_inputs[num_bsec_inputs].sensor_id = BSEC_INPUT_HUMIDITY;
bsec_inputs[num_bsec_inputs].signal = data.humidity / 1000.0f;
bsec_inputs[num_bsec_inputs].time_stamp = now;
num_bsec_inputs++;
}
if (sensor_settings.process_data & BSEC_PROCESS_PRESSURE) {
bsec_inputs[num_bsec_inputs].sensor_id = BSEC_INPUT_PRESSURE;
bsec_inputs[num_bsec_inputs].signal = data.pressure;
bsec_inputs[num_bsec_inputs].time_stamp = now;
num_bsec_inputs++;
}
if (sensor_settings.process_data & BSEC_PROCESS_GAS) {
bsec_inputs[num_bsec_inputs].sensor_id = BSEC_INPUT_GASRESISTOR;
bsec_inputs[num_bsec_inputs].signal = data.gas_resistance;
bsec_inputs[num_bsec_inputs].time_stamp = now;
num_bsec_inputs++;
}
}
}
if (num_bsec_inputs > 0) {
status = bsec_do_steps(bsec_inputs, num_bsec_inputs, bsec_outputs, &num_bsec_outputs);
if (status < 0) {
kout << "bsec_do_steps error: " << status << endl;
return;
}
if (status > 0) {
kout << "bsec_do_steps warning: " << status << endl;
}
for (uint8_t i = 0; i < num_bsec_outputs; i++) {
switch (bsec_outputs[i].sensor_id) {
case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE:
kout << now_s << " BME680 temperature " << bsec_outputs[i].signal << " °c" << endl;
break;
case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY:
kout << now_s << " BME680 humidity " << bsec_outputs[i].signal << " %" << endl;
break;
case BSEC_OUTPUT_RAW_PRESSURE:
kout << now_s << " BME680 pressure " << bsec_outputs[i].signal / 100 << " hPa" << endl;
break;
case BSEC_OUTPUT_RAW_GAS:
kout << now_s << " BME680 gas resistance " << bsec_outputs[i].signal << " Ω" << endl;
break;
case BSEC_OUTPUT_IAQ:
if (bsec_outputs[i].accuracy > 0) {
kout << now_s << " BME680 IAQ: " << bsec_outputs[i].signal << " " << accuracy[bsec_outputs[i].accuracy] << endl;
}
break;
case BSEC_OUTPUT_STABILIZATION_STATUS:
if (bsec_outputs[i].signal < 1) {
kout << now_s << " BME680 IAQ initial stabilization in progress" << endl;
}
break;
case BSEC_OUTPUT_RUN_IN_STATUS:
if (bsec_outputs[i].signal < 1) {
kout << now_s << " BME680 IAQ power-on stabilization in progress" << endl;
}
break;
default:
continue;
}
}
kout << endl;
}
}
}
int main(void)
{
arch.setup();
gpio.setup();
kout.setup();
#if defined(CONFIG_meta_driver_i2c)
while (i2c.setup() != 0) {
kout << "I2C setup FAILED" << endl;
arch.delay_ms(1000);
}
kout << "I2C setup OK" << endl;
#endif
// Set up (open-source) BME680 driver
bme680.intf = BME680_I2C_INTF;
bme680.read = bme680_i2c_read;
bme680.write = bme680_i2c_write;
bme680.delay_ms = bme680_delay_ms;
int8_t bme680_status = bme680.init();
while (bme680_status != 0) {
kout << "BME680 init failed: " << (uint8_t)bme680_status << endl;
arch.delay_ms(1000);
}
kout << "BME680 init OK" << endl;
// Initialize proprietary BSEC library
bsec_library_return_t bsec_status = bsec_init();
while (bsec_status != BSEC_OK) {
kout << "BSEC init failed: " << bsec_status << endl;
arch.delay_ms(1000);
}
kout << "BSEC init OK" << endl;
/*
* Output configuration. The BME680 BSEC library supports several virtual
* sensors such as raw temperature, compensated temperature, or IAQ. Each
* virtual sensor is calculated based on past observations and the
* TPH+Gas readings obtained from the BME680 sinsor.
*
* Here, we are interested in seven different types of readings.
*/
bsec_sensor_configuration_t virtual_sensors[7];
unsigned char n_virtual_sensors = 7;
/*
* bsec_update_subscription writes required sensor settings to the
* sensor_configs array. We're not interested in them at the moment.
*/
bsec_sensor_configuration_t sensor_configs[BSEC_MAX_PHYSICAL_SENSOR];
unsigned char n_sensor_settings = BSEC_MAX_PHYSICAL_SENSOR;
/*
* Low Power mode -> 1/3 Hz (i.e., one sample every three seconds).
*/
float sample_rate = BSEC_SAMPLE_RATE_LP;
/*
* We're interested in the following readings.
* See bsec_virtual_sensor_t definition in bsec_datatypes for a list of
* supported virtual sensor types ("sensor_ids").
*/
virtual_sensors[0].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE;
virtual_sensors[0].sample_rate = sample_rate;
virtual_sensors[1].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY;
virtual_sensors[1].sample_rate = sample_rate;
virtual_sensors[2].sensor_id = BSEC_OUTPUT_RAW_PRESSURE;
virtual_sensors[2].sample_rate = sample_rate;
virtual_sensors[3].sensor_id = BSEC_OUTPUT_RAW_GAS;
virtual_sensors[3].sample_rate = sample_rate;
virtual_sensors[4].sensor_id = BSEC_OUTPUT_IAQ;
virtual_sensors[4].sample_rate = sample_rate;
virtual_sensors[5].sensor_id = BSEC_OUTPUT_STABILIZATION_STATUS;
virtual_sensors[5].sample_rate = sample_rate;
virtual_sensors[6].sensor_id = BSEC_OUTPUT_RUN_IN_STATUS;
virtual_sensors[6].sample_rate = sample_rate;
bsec_status = bsec_update_subscription(virtual_sensors, n_virtual_sensors, sensor_configs, &n_sensor_settings);
while (bsec_status != BSEC_OK) {
kout << "bsec_update_subscription error: " << bsec_status << endl;
arch.delay_ms(1000);
}
kout << "bsec_update_subscription OK" << endl;
arch.idle_loop();
return 0;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment