initial
This commit is contained in:
parent
7f066f338f
commit
5009ec0563
@ -3,30 +3,52 @@
|
|||||||
|
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include <Wire.h>
|
#include <Wire.h>
|
||||||
#include "bsec_integration.h"
|
|
||||||
#include "irqhandler.h"
|
#include "irqhandler.h"
|
||||||
|
#include "bsec.h"
|
||||||
extern const uint8_t bsec_config_iaq[454];
|
|
||||||
|
|
||||||
extern bmeStatus_t
|
extern bmeStatus_t
|
||||||
bme_status; // Make struct for storing gps data globally available
|
bme_status; // Make struct for storing gps data globally available
|
||||||
extern TaskHandle_t BmeTask;
|
extern TaskHandle_t BmeTask;
|
||||||
|
|
||||||
|
// --- Bosch BSEC library configuration ---
|
||||||
|
// 3,3V supply voltage; 3s max time between sensor_control calls; 4 days
|
||||||
|
// calibration. Change this const if not applicable for your application (see
|
||||||
|
// BME680 datasheet)
|
||||||
|
const uint8_t bsec_config_iaq[454] = {
|
||||||
|
1, 7, 4, 1, 61, 0, 0, 0, 0, 0, 0, 0, 174, 1, 0,
|
||||||
|
0, 48, 0, 1, 0, 137, 65, 0, 63, 205, 204, 204, 62, 0, 0,
|
||||||
|
64, 63, 205, 204, 204, 62, 0, 0, 225, 68, 0, 192, 168, 71, 64,
|
||||||
|
49, 119, 76, 0, 0, 0, 0, 0, 80, 5, 95, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 28, 0, 2, 0, 0, 244, 1, 225, 0, 25, 0,
|
||||||
|
0, 128, 64, 0, 0, 32, 65, 144, 1, 0, 0, 112, 65, 0, 0,
|
||||||
|
0, 63, 16, 0, 3, 0, 10, 215, 163, 60, 10, 215, 35, 59, 10,
|
||||||
|
215, 35, 59, 9, 0, 5, 0, 0, 0, 0, 0, 1, 88, 0, 9,
|
||||||
|
0, 229, 208, 34, 62, 0, 0, 0, 0, 0, 0, 0, 0, 218, 27,
|
||||||
|
156, 62, 225, 11, 67, 64, 0, 0, 160, 64, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 94, 75, 72, 189, 93, 254, 159, 64, 66, 62, 160, 191,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 33, 31, 180, 190, 138, 176, 97,
|
||||||
|
64, 65, 241, 99, 190, 0, 0, 0, 0, 0, 0, 0, 0, 167, 121,
|
||||||
|
71, 61, 165, 189, 41, 192, 184, 30, 189, 64, 12, 0, 10, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 229, 0, 254, 0, 2, 1, 5, 48,
|
||||||
|
117, 100, 0, 44, 1, 112, 23, 151, 7, 132, 3, 197, 0, 92, 4,
|
||||||
|
144, 1, 64, 1, 64, 1, 144, 1, 48, 117, 48, 117, 48, 117, 48,
|
||||||
|
117, 100, 0, 100, 0, 100, 0, 48, 117, 48, 117, 48, 117, 100, 0,
|
||||||
|
100, 0, 48, 117, 48, 117, 100, 0, 100, 0, 100, 0, 100, 0, 48,
|
||||||
|
117, 48, 117, 48, 117, 100, 0, 100, 0, 100, 0, 48, 117, 48, 117,
|
||||||
|
100, 0, 100, 0, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44,
|
||||||
|
1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1,
|
||||||
|
44, 1, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8,
|
||||||
|
7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7,
|
||||||
|
112, 23, 112, 23, 112, 23, 112, 23, 112, 23, 112, 23, 112, 23, 112,
|
||||||
|
23, 112, 23, 112, 23, 112, 23, 112, 23, 112, 23, 112, 23, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 220, 5, 220, 5, 220, 5, 255, 255, 255,
|
||||||
|
255, 255, 255, 220, 5, 220, 5, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 44, 1, 0, 0, 0, 0,
|
||||||
|
239, 79, 0, 0};
|
||||||
|
|
||||||
int bme_init();
|
int bme_init();
|
||||||
void bme_loop(void *pvParameters);
|
void bme_loop(void *pvParameters);
|
||||||
int8_t i2c_read(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data,
|
int checkIaqSensorStatus(void);
|
||||||
uint16_t len);
|
|
||||||
int8_t i2c_write(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data,
|
|
||||||
uint16_t len);
|
|
||||||
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,
|
|
||||||
float co2_equivalent, float breath_voc_equivalent);
|
|
||||||
uint32_t state_load(uint8_t *state_buffer, uint32_t n_buffer);
|
|
||||||
void state_save(const uint8_t *state_buffer, uint32_t length);
|
|
||||||
uint32_t config_load(uint8_t *config_buffer, uint32_t n_buffer);
|
|
||||||
void user_delay_ms(uint32_t period);
|
|
||||||
int64_t get_timestamp_us();
|
|
||||||
|
|
||||||
#endif
|
#endif
|
493
lib/Bosch-BSEC/bsec.cpp
Normal file
493
lib/Bosch-BSEC/bsec.cpp
Normal file
@ -0,0 +1,493 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (C) 2017 - 2018 Bosch Sensortec GmbH
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names of the
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
|
||||||
|
* OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||||
|
* OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
|
||||||
|
*
|
||||||
|
* The information provided is believed to be accurate and reliable.
|
||||||
|
* The copyright holder assumes no responsibility
|
||||||
|
* for the consequences of use
|
||||||
|
* of such information nor for any infringement of patents or
|
||||||
|
* other rights of third parties which may result from its use.
|
||||||
|
* No license is granted by implication or otherwise under any patent or
|
||||||
|
* patent rights of the copyright holder.
|
||||||
|
*
|
||||||
|
* @file bsec.cpp
|
||||||
|
* @date 31 Jan 2018
|
||||||
|
* @version 1.0
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "bsec.h"
|
||||||
|
|
||||||
|
TwoWire* Bsec::wireObj = NULL;
|
||||||
|
SPIClass* Bsec::spiObj = NULL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructor
|
||||||
|
*/
|
||||||
|
Bsec::Bsec()
|
||||||
|
{
|
||||||
|
nextCall = 0;
|
||||||
|
version.major = 0;
|
||||||
|
version.minor = 0;
|
||||||
|
version.major_bugfix = 0;
|
||||||
|
version.minor_bugfix = 0;
|
||||||
|
millisOverflowCounter = 0;
|
||||||
|
lastTime = 0;
|
||||||
|
bme680Status = BME680_OK;
|
||||||
|
outputTimestamp = 0;
|
||||||
|
_tempOffset = 0.0f;
|
||||||
|
status = BSEC_OK;
|
||||||
|
zeroOutputs();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function to initialize the BSEC library and the BME680 sensor
|
||||||
|
*/
|
||||||
|
void Bsec::begin(uint8_t devId, enum bme680_intf intf, bme680_com_fptr_t read, bme680_com_fptr_t write, bme680_delay_fptr_t idleTask)
|
||||||
|
{
|
||||||
|
_bme680.dev_id = devId;
|
||||||
|
_bme680.intf = intf;
|
||||||
|
_bme680.read = read;
|
||||||
|
_bme680.write = write;
|
||||||
|
_bme680.delay_ms = idleTask;
|
||||||
|
_bme680.amb_temp = 25;
|
||||||
|
_bme680.power_mode = BME680_FORCED_MODE;
|
||||||
|
|
||||||
|
beginCommon();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function to initialize the BSEC library and the BME680 sensor
|
||||||
|
*/
|
||||||
|
void Bsec::begin(uint8_t i2cAddr, TwoWire &i2c)
|
||||||
|
{
|
||||||
|
_bme680.dev_id = i2cAddr;
|
||||||
|
_bme680.intf = BME680_I2C_INTF;
|
||||||
|
_bme680.read = Bsec::i2cRead;
|
||||||
|
_bme680.write = Bsec::i2cWrite;
|
||||||
|
_bme680.delay_ms = Bsec::delay_ms;
|
||||||
|
_bme680.amb_temp = 25;
|
||||||
|
_bme680.power_mode = BME680_FORCED_MODE;
|
||||||
|
|
||||||
|
Bsec::wireObj = &i2c;
|
||||||
|
Bsec::wireObj->begin();
|
||||||
|
|
||||||
|
beginCommon();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function to initialize the BSEC library and the BME680 sensor
|
||||||
|
*/
|
||||||
|
void Bsec::begin(uint8_t chipSelect, SPIClass &spi)
|
||||||
|
{
|
||||||
|
_bme680.dev_id = chipSelect;
|
||||||
|
_bme680.intf = BME680_SPI_INTF;
|
||||||
|
_bme680.read = Bsec::spiTransfer;
|
||||||
|
_bme680.write = Bsec::spiTransfer;
|
||||||
|
_bme680.delay_ms = Bsec::delay_ms;
|
||||||
|
_bme680.amb_temp = 25;
|
||||||
|
_bme680.power_mode = BME680_FORCED_MODE;
|
||||||
|
|
||||||
|
pinMode(chipSelect, OUTPUT);
|
||||||
|
digitalWrite(chipSelect, HIGH);
|
||||||
|
Bsec::spiObj = &spi;
|
||||||
|
Bsec::spiObj->begin();
|
||||||
|
|
||||||
|
beginCommon();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Common code for the begin function
|
||||||
|
*/
|
||||||
|
void Bsec::beginCommon(void)
|
||||||
|
{
|
||||||
|
status = bsec_init();
|
||||||
|
|
||||||
|
getVersion();
|
||||||
|
|
||||||
|
bme680Status = bme680_init(&_bme680);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function that sets the desired sensors and the sample rates
|
||||||
|
*/
|
||||||
|
void Bsec::updateSubscription(bsec_virtual_sensor_t sensorList[], uint8_t nSensors, float sampleRate)
|
||||||
|
{
|
||||||
|
bsec_sensor_configuration_t virtualSensors[BSEC_NUMBER_OUTPUTS],
|
||||||
|
sensorSettings[BSEC_MAX_PHYSICAL_SENSOR];
|
||||||
|
uint8_t nVirtualSensors = 0, nSensorSettings = BSEC_MAX_PHYSICAL_SENSOR;
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < nSensors; i++) {
|
||||||
|
virtualSensors[nVirtualSensors].sensor_id = sensorList[i];
|
||||||
|
virtualSensors[nVirtualSensors].sample_rate = sampleRate;
|
||||||
|
nVirtualSensors++;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = bsec_update_subscription(virtualSensors, nVirtualSensors, sensorSettings, &nSensorSettings);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback from the user to trigger reading of data from the BME680, process and store outputs
|
||||||
|
*/
|
||||||
|
bool Bsec::run(void)
|
||||||
|
{
|
||||||
|
bool newData = false;
|
||||||
|
/* Check if the time has arrived to call do_steps() */
|
||||||
|
int64_t callTimeMs = getTimeMs();
|
||||||
|
|
||||||
|
if (callTimeMs >= nextCall) {
|
||||||
|
|
||||||
|
bsec_bme_settings_t bme680Settings;
|
||||||
|
|
||||||
|
int64_t callTimeNs = callTimeMs * INT64_C(1000000);
|
||||||
|
|
||||||
|
status = bsec_sensor_control(callTimeNs, &bme680Settings);
|
||||||
|
if (status < BSEC_OK)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
nextCall = bme680Settings.next_call / INT64_C(1000000); // Convert from ns to ms
|
||||||
|
|
||||||
|
bme680Status = setBme680Config(bme680Settings);
|
||||||
|
if (bme680Status != BME680_OK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bme680Status = bme680_set_sensor_mode(&_bme680);
|
||||||
|
if (bme680Status != BME680_OK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait for measurement to complete */
|
||||||
|
uint16_t meas_dur = 0;
|
||||||
|
|
||||||
|
bme680_get_profile_dur(&meas_dur, &_bme680);
|
||||||
|
delay_ms(meas_dur);
|
||||||
|
|
||||||
|
newData = readProcessData(callTimeNs, bme680Settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function to get the state of the algorithm to save to non-volatile memory
|
||||||
|
*/
|
||||||
|
void Bsec::getState(uint8_t *state)
|
||||||
|
{
|
||||||
|
uint8_t workBuffer[BSEC_MAX_STATE_BLOB_SIZE];
|
||||||
|
uint32_t n_serialized_state = BSEC_MAX_STATE_BLOB_SIZE;
|
||||||
|
status = bsec_get_state(0, state, BSEC_MAX_STATE_BLOB_SIZE, workBuffer, BSEC_MAX_STATE_BLOB_SIZE, &n_serialized_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function to set the state of the algorithm from non-volatile memory
|
||||||
|
*/
|
||||||
|
void Bsec::setState(uint8_t *state)
|
||||||
|
{
|
||||||
|
uint8_t workBuffer[BSEC_MAX_STATE_BLOB_SIZE];
|
||||||
|
|
||||||
|
status = bsec_set_state(state, BSEC_MAX_STATE_BLOB_SIZE, workBuffer, BSEC_MAX_STATE_BLOB_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function to set the configuration of the algorithm from memory
|
||||||
|
*/
|
||||||
|
void Bsec::setConfig(const uint8_t *state)
|
||||||
|
{
|
||||||
|
uint8_t workBuffer[BSEC_MAX_PROPERTY_BLOB_SIZE];
|
||||||
|
|
||||||
|
status = bsec_set_configuration(state, BSEC_MAX_PROPERTY_BLOB_SIZE, workBuffer, sizeof(workBuffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Private functions */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the version of the BSEC library
|
||||||
|
*/
|
||||||
|
void Bsec::getVersion(void)
|
||||||
|
{
|
||||||
|
bsec_get_version(&version);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read data from the BME680 and process it
|
||||||
|
*/
|
||||||
|
bool Bsec::readProcessData(int64_t currTimeNs, bsec_bme_settings_t bme680Settings)
|
||||||
|
{
|
||||||
|
bme680Status = bme680_get_sensor_data(&_data, &_bme680);
|
||||||
|
if (bme680Status != BME680_OK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bsec_input_t inputs[BSEC_MAX_PHYSICAL_SENSOR]; // Temp, Pres, Hum & Gas
|
||||||
|
uint8_t nInputs = 0, nOutputs = 0;
|
||||||
|
|
||||||
|
if (_data.status & BME680_NEW_DATA_MSK) {
|
||||||
|
if (bme680Settings.process_data & BSEC_PROCESS_TEMPERATURE) {
|
||||||
|
inputs[nInputs].sensor_id = BSEC_INPUT_TEMPERATURE;
|
||||||
|
inputs[nInputs].signal = _data.temperature;
|
||||||
|
inputs[nInputs].time_stamp = currTimeNs;
|
||||||
|
nInputs++;
|
||||||
|
/* Temperature offset from the real temperature due to external heat sources */
|
||||||
|
inputs[nInputs].sensor_id = BSEC_INPUT_HEATSOURCE;
|
||||||
|
inputs[nInputs].signal = _tempOffset;
|
||||||
|
inputs[nInputs].time_stamp = currTimeNs;
|
||||||
|
nInputs++;
|
||||||
|
}
|
||||||
|
if (bme680Settings.process_data & BSEC_PROCESS_HUMIDITY) {
|
||||||
|
inputs[nInputs].sensor_id = BSEC_INPUT_HUMIDITY;
|
||||||
|
inputs[nInputs].signal = _data.humidity;
|
||||||
|
inputs[nInputs].time_stamp = currTimeNs;
|
||||||
|
nInputs++;
|
||||||
|
}
|
||||||
|
if (bme680Settings.process_data & BSEC_PROCESS_PRESSURE) {
|
||||||
|
inputs[nInputs].sensor_id = BSEC_INPUT_PRESSURE;
|
||||||
|
inputs[nInputs].signal = _data.pressure;
|
||||||
|
inputs[nInputs].time_stamp = currTimeNs;
|
||||||
|
nInputs++;
|
||||||
|
}
|
||||||
|
if (bme680Settings.process_data & BSEC_PROCESS_GAS) {
|
||||||
|
inputs[nInputs].sensor_id = BSEC_INPUT_GASRESISTOR;
|
||||||
|
inputs[nInputs].signal = _data.gas_resistance;
|
||||||
|
inputs[nInputs].time_stamp = currTimeNs;
|
||||||
|
nInputs++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nInputs > 0) {
|
||||||
|
nOutputs = BSEC_NUMBER_OUTPUTS;
|
||||||
|
bsec_output_t _outputs[BSEC_NUMBER_OUTPUTS];
|
||||||
|
|
||||||
|
status = bsec_do_steps(inputs, nInputs, _outputs, &nOutputs);
|
||||||
|
if (status != BSEC_OK)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
zeroOutputs();
|
||||||
|
|
||||||
|
if (nOutputs > 0) {
|
||||||
|
outputTimestamp = _outputs[0].time_stamp / 1000000; // Convert from ns to ms
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < nOutputs; i++) {
|
||||||
|
switch (_outputs[i].sensor_id) {
|
||||||
|
case BSEC_OUTPUT_IAQ:
|
||||||
|
iaqEstimate = _outputs[i].signal;
|
||||||
|
iaqAccuracy = _outputs[i].accuracy;
|
||||||
|
break;
|
||||||
|
case BSEC_OUTPUT_STATIC_IAQ:
|
||||||
|
staticIaq = _outputs[i].signal;
|
||||||
|
staticIaqAccuracy = _outputs[i].accuracy;
|
||||||
|
break;
|
||||||
|
case BSEC_OUTPUT_CO2_EQUIVALENT:
|
||||||
|
co2Equivalent = _outputs[i].signal;
|
||||||
|
co2Accuracy = _outputs[i].accuracy;
|
||||||
|
break;
|
||||||
|
case BSEC_OUTPUT_BREATH_VOC_EQUIVALENT:
|
||||||
|
breathVocEquivalent = _outputs[i].signal;
|
||||||
|
breathVocAccuracy = _outputs[i].accuracy;
|
||||||
|
break;
|
||||||
|
case BSEC_OUTPUT_RAW_TEMPERATURE:
|
||||||
|
rawTemperature = _outputs[i].signal;
|
||||||
|
break;
|
||||||
|
case BSEC_OUTPUT_RAW_PRESSURE:
|
||||||
|
pressure = _outputs[i].signal;
|
||||||
|
break;
|
||||||
|
case BSEC_OUTPUT_RAW_HUMIDITY:
|
||||||
|
rawHumidity = _outputs[i].signal;
|
||||||
|
break;
|
||||||
|
case BSEC_OUTPUT_RAW_GAS:
|
||||||
|
gasResistance = _outputs[i].signal;
|
||||||
|
break;
|
||||||
|
case BSEC_OUTPUT_STABILIZATION_STATUS:
|
||||||
|
stabStatus = _outputs[i].signal;
|
||||||
|
break;
|
||||||
|
case BSEC_OUTPUT_RUN_IN_STATUS:
|
||||||
|
runInStatus = _outputs[i].signal;
|
||||||
|
break;
|
||||||
|
case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE:
|
||||||
|
temperature = _outputs[i].signal;
|
||||||
|
break;
|
||||||
|
case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY:
|
||||||
|
humidity = _outputs[i].signal;
|
||||||
|
break;
|
||||||
|
case BSEC_OUTPUT_COMPENSATED_GAS:
|
||||||
|
compGasValue = _outputs[i].signal;
|
||||||
|
compGasAccuracy = _outputs[i].accuracy;
|
||||||
|
break;
|
||||||
|
case BSEC_OUTPUT_GAS_PERCENTAGE:
|
||||||
|
gasPercentage = _outputs[i].signal;
|
||||||
|
gasPercentageAcccuracy = _outputs[i].accuracy;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the BME680 sensor's configuration
|
||||||
|
*/
|
||||||
|
int8_t Bsec::setBme680Config(bsec_bme_settings_t bme680Settings)
|
||||||
|
{
|
||||||
|
_bme680.gas_sett.run_gas = bme680Settings.run_gas;
|
||||||
|
_bme680.tph_sett.os_hum = bme680Settings.humidity_oversampling;
|
||||||
|
_bme680.tph_sett.os_temp = bme680Settings.temperature_oversampling;
|
||||||
|
_bme680.tph_sett.os_pres = bme680Settings.pressure_oversampling;
|
||||||
|
_bme680.gas_sett.heatr_temp = bme680Settings.heater_temperature;
|
||||||
|
_bme680.gas_sett.heatr_dur = bme680Settings.heating_duration;
|
||||||
|
uint16_t desired_settings = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_FILTER_SEL
|
||||||
|
| BME680_GAS_SENSOR_SEL;
|
||||||
|
return bme680_set_sensor_settings(desired_settings, &_bme680);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function to zero the outputs
|
||||||
|
*/
|
||||||
|
void Bsec::zeroOutputs(void)
|
||||||
|
{
|
||||||
|
temperature = 0.0f;
|
||||||
|
pressure = 0.0f;
|
||||||
|
humidity = 0.0f;
|
||||||
|
gasResistance = 0.0f;
|
||||||
|
rawTemperature = 0.0f;
|
||||||
|
rawHumidity = 0.0f;
|
||||||
|
stabStatus = 0.0f;
|
||||||
|
runInStatus = 0.0f;
|
||||||
|
iaqEstimate = 0.0f;
|
||||||
|
iaqAccuracy = 0;
|
||||||
|
staticIaq = 0.0f;
|
||||||
|
staticIaqAccuracy = 0;
|
||||||
|
co2Equivalent = 0.0f;
|
||||||
|
co2Accuracy = 0;
|
||||||
|
breathVocEquivalent = 0.0f;
|
||||||
|
breathVocAccuracy = 0;
|
||||||
|
compGasValue = 0.0f;
|
||||||
|
compGasAccuracy = 0;
|
||||||
|
gasPercentage = 0.0f;
|
||||||
|
gasPercentageAcccuracy = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function to calculate an int64_t timestamp in milliseconds
|
||||||
|
*/
|
||||||
|
int64_t Bsec::getTimeMs(void)
|
||||||
|
{
|
||||||
|
int64_t timeMs = millis();
|
||||||
|
|
||||||
|
if (lastTime > timeMs) { // An overflow occured
|
||||||
|
lastTime = timeMs;
|
||||||
|
millisOverflowCounter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return timeMs + (millisOverflowCounter * 0xFFFFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Task that delays for a ms period of time
|
||||||
|
*/
|
||||||
|
void Bsec::delay_ms(uint32_t period)
|
||||||
|
{
|
||||||
|
// Wait for a period amount of ms
|
||||||
|
// The system may simply idle, sleep or even perform background tasks
|
||||||
|
delay(period);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Callback function for reading registers over I2C
|
||||||
|
*/
|
||||||
|
int8_t Bsec::i2cRead(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t length)
|
||||||
|
{
|
||||||
|
uint16_t i;
|
||||||
|
int8_t rslt = 0;
|
||||||
|
if(Bsec::wireObj) {
|
||||||
|
Bsec::wireObj->beginTransmission(devId);
|
||||||
|
Bsec::wireObj->write(regAddr);
|
||||||
|
rslt = Bsec::wireObj->endTransmission();
|
||||||
|
Bsec::wireObj->requestFrom((int) devId, (int) length);
|
||||||
|
for (i = 0; (i < length) && Bsec::wireObj->available(); i++) {
|
||||||
|
regData[i] = Bsec::wireObj->read();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rslt = -1;
|
||||||
|
}
|
||||||
|
return rslt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback function for writing registers over I2C
|
||||||
|
*/
|
||||||
|
int8_t Bsec::i2cWrite(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t length)
|
||||||
|
{
|
||||||
|
uint16_t i;
|
||||||
|
int8_t rslt = 0;
|
||||||
|
if(Bsec::wireObj) {
|
||||||
|
Bsec::wireObj->beginTransmission(devId);
|
||||||
|
Bsec::wireObj->write(regAddr);
|
||||||
|
for (i = 0; i < length; i++) {
|
||||||
|
Bsec::wireObj->write(regData[i]);
|
||||||
|
}
|
||||||
|
rslt = Bsec::wireObj->endTransmission();
|
||||||
|
} else {
|
||||||
|
rslt = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rslt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback function for reading and writing registers over SPI
|
||||||
|
*/
|
||||||
|
int8_t Bsec::spiTransfer(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t length)
|
||||||
|
{
|
||||||
|
int8_t rslt = 0;
|
||||||
|
if(Bsec::spiObj) {
|
||||||
|
Bsec::spiObj->beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0)); // Can be upto 10MHz
|
||||||
|
|
||||||
|
digitalWrite(devId, LOW);
|
||||||
|
|
||||||
|
Bsec::spiObj->transfer(regAddr); // Write the register address, ignore the return
|
||||||
|
for (uint16_t i = 0; i < length; i++)
|
||||||
|
regData[i] = Bsec::spiObj->transfer(regData[i]);
|
||||||
|
|
||||||
|
digitalWrite(devId, HIGH);
|
||||||
|
Bsec::spiObj->endTransaction();
|
||||||
|
} else {
|
||||||
|
rslt = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rslt;;
|
||||||
|
}
|
230
lib/Bosch-BSEC/bsec.h
Normal file
230
lib/Bosch-BSEC/bsec.h
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (C) 2017 - 2018 Bosch Sensortec GmbH
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names of the
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
|
||||||
|
* OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||||
|
* OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
|
||||||
|
*
|
||||||
|
* The information provided is believed to be accurate and reliable.
|
||||||
|
* The copyright holder assumes no responsibility
|
||||||
|
* for the consequences of use
|
||||||
|
* of such information nor for any infringement of patents or
|
||||||
|
* other rights of third parties which may result from its use.
|
||||||
|
* No license is granted by implication or otherwise under any patent or
|
||||||
|
* patent rights of the copyright holder.
|
||||||
|
*
|
||||||
|
* @file bsec.h
|
||||||
|
* @date 31 Jan 2018
|
||||||
|
* @version 1.0
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BSEC_CLASS_H
|
||||||
|
#define BSEC_CLASS_H
|
||||||
|
|
||||||
|
/* Includes */
|
||||||
|
#include "Arduino.h"
|
||||||
|
#include "Wire.h"
|
||||||
|
#include "SPI.h"
|
||||||
|
#include "bsec_datatypes.h"
|
||||||
|
#include "bsec_interface.h"
|
||||||
|
#include "bme680.h"
|
||||||
|
|
||||||
|
/* BSEC class definition */
|
||||||
|
class Bsec
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/* Public variables */
|
||||||
|
bsec_version_t version; // Stores the version of the BSEC algorithm
|
||||||
|
int64_t nextCall; // Stores the time when the algorithm has to be called next in ms
|
||||||
|
int8_t bme680Status; // Placeholder for the BME680 driver's error codes
|
||||||
|
bsec_library_return_t status;
|
||||||
|
float iaqEstimate, rawTemperature, pressure, rawHumidity, gasResistance, stabStatus, runInStatus, temperature, humidity,
|
||||||
|
staticIaq, co2Equivalent, breathVocEquivalent, compGasValue, gasPercentage;
|
||||||
|
uint8_t iaqAccuracy, staticIaqAccuracy, co2Accuracy, breathVocAccuracy, compGasAccuracy, gasPercentageAcccuracy;
|
||||||
|
int64_t outputTimestamp; // Timestamp in ms of the output
|
||||||
|
static TwoWire *wireObj;
|
||||||
|
static SPIClass *spiObj;
|
||||||
|
|
||||||
|
/* Public APIs */
|
||||||
|
/**
|
||||||
|
* @brief Constructor
|
||||||
|
*/
|
||||||
|
Bsec();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function to initialize the BSEC library and the BME680 sensor
|
||||||
|
* @param devId : Device identifier parameter for the read/write interface functions
|
||||||
|
* @param intf : Physical communication interface
|
||||||
|
* @param read : Pointer to the read function
|
||||||
|
* @param write : Pointer to the write function
|
||||||
|
* @param idleTask : Pointer to the idling task
|
||||||
|
*/
|
||||||
|
void begin(uint8_t devId, enum bme680_intf intf, bme680_com_fptr_t read, bme680_com_fptr_t write, bme680_delay_fptr_t idleTask);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function to initialize the BSEC library and the BME680 sensor
|
||||||
|
* @param i2cAddr : I2C address
|
||||||
|
* @param i2c : Pointer to the TwoWire object
|
||||||
|
*/
|
||||||
|
void begin(uint8_t i2cAddr, TwoWire &i2c);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function to initialize the BSEC library and the BME680 sensor
|
||||||
|
* @param chipSelect : SPI chip select
|
||||||
|
* @param spi : Pointer to the SPIClass object
|
||||||
|
*/
|
||||||
|
void begin(uint8_t chipSelect, SPIClass &spi);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function that sets the desired sensors and the sample rates
|
||||||
|
* @param sensorList : The list of output sensors
|
||||||
|
* @param nSensors : Number of outputs requested
|
||||||
|
* @param sampleRate : The sample rate of requested sensors
|
||||||
|
*/
|
||||||
|
void updateSubscription(bsec_virtual_sensor_t sensorList[], uint8_t nSensors, float sampleRate = BSEC_SAMPLE_RATE_ULP);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback from the user to trigger reading of data from the BME680, process and store outputs
|
||||||
|
* @return true if there are new outputs. false otherwise
|
||||||
|
*/
|
||||||
|
bool run(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function to get the state of the algorithm to save to non-volatile memory
|
||||||
|
* @param state : Pointer to a memory location that contains the state
|
||||||
|
*/
|
||||||
|
void getState(uint8_t *state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function to set the state of the algorithm from non-volatile memory
|
||||||
|
* @param state : Pointer to a memory location that contains the state
|
||||||
|
*/
|
||||||
|
void setState(uint8_t *state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function to set the configuration of the algorithm from memory
|
||||||
|
* @param state : Pointer to a memory location that contains the configuration
|
||||||
|
*/
|
||||||
|
void setConfig(const uint8_t *config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function to set the temperature offset
|
||||||
|
* @param tempOffset : Temperature offset in degree Celsius
|
||||||
|
*/
|
||||||
|
void setTemperatureOffset(float tempOffset)
|
||||||
|
{
|
||||||
|
_tempOffset = tempOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function to calculate an int64_t timestamp in milliseconds
|
||||||
|
*/
|
||||||
|
int64_t getTimeMs(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Task that delays for a ms period of time
|
||||||
|
* @param period : Period of time in ms
|
||||||
|
*/
|
||||||
|
static void delay_ms(uint32_t period);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback function for reading registers over I2C
|
||||||
|
* @param devId : Library agnostic parameter to identify the device to communicate with
|
||||||
|
* @param regAddr : Register address
|
||||||
|
* @param regData : Pointer to the array containing the data to be read
|
||||||
|
* @param length : Length of the array of data
|
||||||
|
* @return Zero for success, non-zero otherwise
|
||||||
|
*/
|
||||||
|
static int8_t i2cRead(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback function for writing registers over I2C
|
||||||
|
* @param devId : Library agnostic parameter to identify the device to communicate with
|
||||||
|
* @param regAddr : Register address
|
||||||
|
* @param regData : Pointer to the array containing the data to be written
|
||||||
|
* @param length : Length of the array of data
|
||||||
|
* @return Zero for success, non-zero otherwise
|
||||||
|
*/
|
||||||
|
static int8_t i2cWrite(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback function for reading and writing registers over SPI
|
||||||
|
* @param devId : Library agnostic parameter to identify the device to communicate with
|
||||||
|
* @param regAddr : Register address
|
||||||
|
* @param regData : Pointer to the array containing the data to be read or written
|
||||||
|
* @param length : Length of the array of data
|
||||||
|
* @return Zero for success, non-zero otherwise
|
||||||
|
*/
|
||||||
|
static int8_t spiTransfer(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t length);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/* Private variables */
|
||||||
|
struct bme680_dev _bme680;
|
||||||
|
struct bme680_field_data _data;
|
||||||
|
float _tempOffset;
|
||||||
|
// Global variables to help create a millisecond timestamp that doesn't overflow every 51 days.
|
||||||
|
// If it overflows, it will have a negative value. Something that should never happen.
|
||||||
|
uint32_t millisOverflowCounter;
|
||||||
|
uint32_t lastTime;
|
||||||
|
|
||||||
|
/* Private APIs */
|
||||||
|
/**
|
||||||
|
* @brief Get the version of the BSEC library
|
||||||
|
*/
|
||||||
|
void getVersion(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read data from the BME680 and process it
|
||||||
|
* @param currTimeNs: Current time in ns
|
||||||
|
* @param bme680Settings: BME680 sensor's settings
|
||||||
|
* @return true if there are new outputs. false otherwise
|
||||||
|
*/
|
||||||
|
bool readProcessData(int64_t currTimeNs, bsec_bme_settings_t bme680Settings);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the BME680 sensor's configuration
|
||||||
|
* @param bme680Settings: Settings to configure the BME680
|
||||||
|
* @return BME680 return code. BME680_OK for success, failure otherwise
|
||||||
|
*/
|
||||||
|
int8_t setBme680Config(bsec_bme_settings_t bme680Settings);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Common code for the begin function
|
||||||
|
*/
|
||||||
|
void beginCommon(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function to zero the outputs
|
||||||
|
*/
|
||||||
|
void zeroOutputs(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
; ---> SELECT TARGET PLATFORM HERE! <---
|
; ---> SELECT TARGET PLATFORM HERE! <---
|
||||||
[platformio]
|
[platformio]
|
||||||
env_default = generic
|
;env_default = generic
|
||||||
;env_default = ebox
|
;env_default = ebox
|
||||||
;env_default = eboxtube
|
;env_default = eboxtube
|
||||||
;env_default = heltec
|
;env_default = heltec
|
||||||
@ -16,7 +16,7 @@ env_default = generic
|
|||||||
;env_default = ttgov21old
|
;env_default = ttgov21old
|
||||||
;env_default = ttgov21new
|
;env_default = ttgov21new
|
||||||
;env_default = ttgobeam_old
|
;env_default = ttgobeam_old
|
||||||
;env_default = ttgobeam_new
|
env_default = ttgobeam_new
|
||||||
;env_default = lopy
|
;env_default = lopy
|
||||||
;env_default = lopy4
|
;env_default = lopy4
|
||||||
;env_default = fipy
|
;env_default = fipy
|
||||||
@ -30,10 +30,10 @@ description = Paxcounter is a proof-of-concept ESP32 device for metering passeng
|
|||||||
|
|
||||||
[common]
|
[common]
|
||||||
; for release_version use max. 10 chars total, use any decimal format like "a.b.c"
|
; for release_version use max. 10 chars total, use any decimal format like "a.b.c"
|
||||||
release_version = 1.7.01
|
release_version = 1.7.03
|
||||||
; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running!
|
; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running!
|
||||||
; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose
|
; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose
|
||||||
debug_level = 0
|
debug_level = 4
|
||||||
; UPLOAD MODE: select esptool to flash via USB/UART, select custom to upload to cloud for OTA
|
; UPLOAD MODE: select esptool to flash via USB/UART, select custom to upload to cloud for OTA
|
||||||
upload_protocol = esptool
|
upload_protocol = esptool
|
||||||
;upload_protocol = custom
|
;upload_protocol = custom
|
||||||
|
@ -1,88 +1,89 @@
|
|||||||
#ifdef HAS_BME
|
#ifdef HAS_BME
|
||||||
|
|
||||||
#include "bme680mems.h"
|
#include "bme680mems.h"
|
||||||
|
#include "bsec.h"
|
||||||
|
|
||||||
// Local logging tag
|
// Local logging tag
|
||||||
static const char TAG[] = "main";
|
static const char TAG[] = "main";
|
||||||
|
|
||||||
bmeStatus_t bme_status;
|
bmeStatus_t bme_status;
|
||||||
TaskHandle_t BmeTask;
|
TaskHandle_t BmeTask;
|
||||||
|
|
||||||
float bme_offset = (float)BME_TEMP_OFFSET;
|
float bme_offset = (float)BME_TEMP_OFFSET;
|
||||||
|
|
||||||
// --- Bosch BSEC library configuration ---
|
Bsec iaqSensor;
|
||||||
// 3,3V supply voltage; 3s max time between sensor_control calls; 4 days
|
|
||||||
// calibration. Change this const if not applicable for your application (see
|
|
||||||
// BME680 datasheet)
|
|
||||||
const uint8_t bsec_config_iaq[454] = {
|
|
||||||
1, 7, 4, 1, 61, 0, 0, 0, 0, 0, 0, 0, 174, 1, 0,
|
|
||||||
0, 48, 0, 1, 0, 137, 65, 0, 63, 205, 204, 204, 62, 0, 0,
|
|
||||||
64, 63, 205, 204, 204, 62, 0, 0, 225, 68, 0, 192, 168, 71, 64,
|
|
||||||
49, 119, 76, 0, 0, 0, 0, 0, 80, 5, 95, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 28, 0, 2, 0, 0, 244, 1, 225, 0, 25, 0,
|
|
||||||
0, 128, 64, 0, 0, 32, 65, 144, 1, 0, 0, 112, 65, 0, 0,
|
|
||||||
0, 63, 16, 0, 3, 0, 10, 215, 163, 60, 10, 215, 35, 59, 10,
|
|
||||||
215, 35, 59, 9, 0, 5, 0, 0, 0, 0, 0, 1, 88, 0, 9,
|
|
||||||
0, 229, 208, 34, 62, 0, 0, 0, 0, 0, 0, 0, 0, 218, 27,
|
|
||||||
156, 62, 225, 11, 67, 64, 0, 0, 160, 64, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 94, 75, 72, 189, 93, 254, 159, 64, 66, 62, 160, 191,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 33, 31, 180, 190, 138, 176, 97,
|
|
||||||
64, 65, 241, 99, 190, 0, 0, 0, 0, 0, 0, 0, 0, 167, 121,
|
|
||||||
71, 61, 165, 189, 41, 192, 184, 30, 189, 64, 12, 0, 10, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 229, 0, 254, 0, 2, 1, 5, 48,
|
|
||||||
117, 100, 0, 44, 1, 112, 23, 151, 7, 132, 3, 197, 0, 92, 4,
|
|
||||||
144, 1, 64, 1, 64, 1, 144, 1, 48, 117, 48, 117, 48, 117, 48,
|
|
||||||
117, 100, 0, 100, 0, 100, 0, 48, 117, 48, 117, 48, 117, 100, 0,
|
|
||||||
100, 0, 48, 117, 48, 117, 100, 0, 100, 0, 100, 0, 100, 0, 48,
|
|
||||||
117, 48, 117, 48, 117, 100, 0, 100, 0, 100, 0, 48, 117, 48, 117,
|
|
||||||
100, 0, 100, 0, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44,
|
|
||||||
1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1,
|
|
||||||
44, 1, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8,
|
|
||||||
7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7,
|
|
||||||
112, 23, 112, 23, 112, 23, 112, 23, 112, 23, 112, 23, 112, 23, 112,
|
|
||||||
23, 112, 23, 112, 23, 112, 23, 112, 23, 112, 23, 112, 23, 255, 255,
|
|
||||||
255, 255, 255, 255, 255, 255, 220, 5, 220, 5, 220, 5, 255, 255, 255,
|
|
||||||
255, 255, 255, 220, 5, 220, 5, 255, 255, 255, 255, 255, 255, 255, 255,
|
|
||||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
|
||||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 44, 1, 0, 0, 0, 0,
|
|
||||||
239, 79, 0, 0};
|
|
||||||
|
|
||||||
// initialize BME680 sensor
|
// initialize BME680 sensor
|
||||||
int bme_init(void) {
|
int bme_init(void) {
|
||||||
|
|
||||||
// struct bme680_dev gas_sensor;
|
Wire.begin(HAS_BME);
|
||||||
Wire.begin(HAS_BME, 400000); // I2C connect to BME680 sensor with 400 KHz
|
iaqSensor.begin(BME_ADDR, Wire);
|
||||||
|
|
||||||
// Call to the function which initializes the BSEC library
|
ESP_LOGI(TAG, "BSEC v%d.%d.%d.%d", iaqSensor.version.major,
|
||||||
// Switch on low-power mode and provide no temperature offset
|
iaqSensor.version.minor, iaqSensor.version.major_bugfix,
|
||||||
|
iaqSensor.version.minor_bugfix);
|
||||||
|
|
||||||
return_values_init ret =
|
iaqSensor.setConfig(bsec_config_iaq);
|
||||||
bsec_iot_init(BSEC_SAMPLE_RATE_LP, bme_offset, i2c_write, i2c_read,
|
|
||||||
user_delay_ms, state_load, config_load);
|
|
||||||
|
|
||||||
if ((int)ret.bme680_status) {
|
if (checkIaqSensorStatus())
|
||||||
ESP_LOGE(TAG, "Could not initialize BME680, error %d",
|
|
||||||
(int)ret.bme680_status);
|
|
||||||
} else if ((int)ret.bsec_status) {
|
|
||||||
ESP_LOGE(TAG, "Could not initialize BSEC library, error %d",
|
|
||||||
(int)ret.bsec_status);
|
|
||||||
} else {
|
|
||||||
ESP_LOGI(TAG, "BME680 sensor found and initialized");
|
ESP_LOGI(TAG, "BME680 sensor found and initialized");
|
||||||
|
else {
|
||||||
|
ESP_LOGE(TAG, "BME680 sensor not found");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
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, 10, BSEC_SAMPLE_RATE_LP);
|
||||||
|
|
||||||
|
if (checkIaqSensorStatus())
|
||||||
|
ESP_LOGI(TAG, "BSEC subscription succesful");
|
||||||
|
else {
|
||||||
|
ESP_LOGE(TAG, "BSEC subscription error");
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void output_ready(int64_t timestamp, float iaq, uint8_t iaq_accuracy,
|
iaqSensor.setTemperatureOffset(bme_offset);
|
||||||
float temperature, float humidity, float pressure,
|
|
||||||
float raw_temperature, float raw_humidity, float gas,
|
|
||||||
bsec_library_return_t bsec_status, float static_iaq,
|
|
||||||
float co2_equivalent, float breath_voc_equivalent) {
|
|
||||||
|
|
||||||
bme_status.temperature = temperature;
|
if (checkIaqSensorStatus())
|
||||||
bme_status.humidity = humidity;
|
ESP_LOGI(TAG, "Ttemperature offset initialized succesful");
|
||||||
bme_status.pressure = (pressure / 100.0); // conversion Pa -> hPa
|
else {
|
||||||
bme_status.iaq = iaq;
|
ESP_LOGE(TAG, "Temperature offset initialization error");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function definitions
|
||||||
|
int checkIaqSensorStatus(void) {
|
||||||
|
int rslt = 1; // true = 1 = no error, false = 0 = error
|
||||||
|
|
||||||
|
if (iaqSensor.status != BSEC_OK) {
|
||||||
|
rslt = 0;
|
||||||
|
if (iaqSensor.status < BSEC_OK)
|
||||||
|
ESP_LOGE(TAG, "BSEC error %d", iaqSensor.status);
|
||||||
|
else
|
||||||
|
ESP_LOGW(TAG, "BSEC warning %d", iaqSensor.status);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iaqSensor.bme680Status != BME680_OK) {
|
||||||
|
rslt = 0;
|
||||||
|
if (iaqSensor.bme680Status < BME680_OK)
|
||||||
|
ESP_LOGE(TAG, "BME680 error %d", iaqSensor.bme680Status);
|
||||||
|
else
|
||||||
|
ESP_LOGW(TAG, "BME680 warning %d", iaqSensor.bme680Status);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rslt;
|
||||||
}
|
}
|
||||||
|
|
||||||
// loop function which reads and processes data based on sensor settings
|
// loop function which reads and processes data based on sensor settings
|
||||||
@ -91,84 +92,23 @@ void bme_loop(void *pvParameters) {
|
|||||||
configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check
|
configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check
|
||||||
|
|
||||||
#ifdef HAS_BME
|
#ifdef HAS_BME
|
||||||
// State is saved every 10.000 samples, which means every 10.000 * 3 secs =
|
while (checkIaqSensorStatus()) {
|
||||||
// 500 minutes
|
if (iaqSensor.run()) { // If new data is available
|
||||||
bsec_iot_loop(user_delay_ms, get_timestamp_us, output_ready, state_save,
|
bme_status.raw_temperature = iaqSensor.rawTemperature;
|
||||||
10000);
|
bme_status.raw_humidity = iaqSensor.rawHumidity;
|
||||||
|
bme_status.temperature = iaqSensor.temperature;
|
||||||
|
bme_status.humidity = iaqSensor.humidity;
|
||||||
|
bme_status.pressure =
|
||||||
|
(iaqSensor.pressure / 100.0); // conversion Pa -> hPa
|
||||||
|
bme_status.iaq = iaqSensor.iaqEstimate;
|
||||||
|
bme_status.iaq_accuracy = iaqSensor.iaqAccuracy;
|
||||||
|
bme_status.gas = iaqSensor.gasResistance;
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
ESP_LOGE(TAG, "BME task ended");
|
||||||
vTaskDelete(BmeTask); // should never be reached
|
vTaskDelete(BmeTask); // should never be reached
|
||||||
|
|
||||||
} // bme_loop()
|
} // bme_loop()
|
||||||
|
|
||||||
int8_t i2c_read(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data,
|
|
||||||
uint16_t len) {
|
|
||||||
int8_t rslt = 0;
|
|
||||||
Wire.beginTransmission(dev_id);
|
|
||||||
Wire.write(reg_addr);
|
|
||||||
rslt = Wire.endTransmission(false);
|
|
||||||
|
|
||||||
Wire.requestFrom((int)dev_id, (int)len);
|
|
||||||
for (uint16_t i = 0; (i < len) && Wire.available(); i++) {
|
|
||||||
reg_data[i] = Wire.read();
|
|
||||||
}
|
|
||||||
// return 0 for success, non-zero for failure
|
|
||||||
return rslt;
|
|
||||||
}
|
|
||||||
|
|
||||||
int8_t i2c_write(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data,
|
|
||||||
uint16_t len) {
|
|
||||||
Wire.beginTransmission(dev_id);
|
|
||||||
Wire.write(reg_addr);
|
|
||||||
for (uint16_t i = 0; i < len; i++) {
|
|
||||||
Wire.write(reg_data[i]);
|
|
||||||
}
|
|
||||||
// return 0 for success, non-zero for failure
|
|
||||||
return Wire.endTransmission(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Load previous library state from non-volatile memory
|
|
||||||
*
|
|
||||||
* @param[in,out] state_buffer buffer to hold the loaded state string
|
|
||||||
* @param[in] n_buffer size of the allocated state buffer
|
|
||||||
*
|
|
||||||
* @return number of bytes copied to state_buffer
|
|
||||||
*/
|
|
||||||
uint32_t state_load(uint8_t *state_buffer, uint32_t n_buffer) {
|
|
||||||
// ...
|
|
||||||
// Load a previous library state from non-volatile memory, if available.
|
|
||||||
//
|
|
||||||
// Return zero if loading was unsuccessful or no state was available,
|
|
||||||
// otherwise return length of loaded state string.
|
|
||||||
// ...
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Save library state to non-volatile memory
|
|
||||||
*
|
|
||||||
* @param[in] state_buffer buffer holding the state to be stored
|
|
||||||
* @param[in] length length of the state string to be stored
|
|
||||||
*
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
void state_save(const uint8_t *state_buffer, uint32_t length) {
|
|
||||||
// ...
|
|
||||||
// Save the string some form of non-volatile memory, if possible.
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t config_load(uint8_t *config_buffer, uint32_t n_buffer) {
|
|
||||||
|
|
||||||
// Load a library config from non-volatile memory, if available.
|
|
||||||
// Return zero if loading was unsuccessful or no config was available,
|
|
||||||
// otherwise return length of loaded config string.
|
|
||||||
|
|
||||||
memcpy(config_buffer, bsec_config_iaq, sizeof(bsec_config_iaq));
|
|
||||||
return sizeof(bsec_config_iaq);
|
|
||||||
}
|
|
||||||
|
|
||||||
void user_delay_ms(uint32_t period) { delay(period); }
|
|
||||||
|
|
||||||
int64_t get_timestamp_us() { return (int64_t)millis() * 1000; }
|
|
||||||
|
|
||||||
#endif // HAS_BME
|
#endif // HAS_BME
|
@ -17,8 +17,8 @@
|
|||||||
|
|
||||||
// enable only if device has these sensors, otherwise comment these lines
|
// enable only if device has these sensors, otherwise comment these lines
|
||||||
// BME680 sensor on I2C bus
|
// BME680 sensor on I2C bus
|
||||||
// don't forget to connect SDIO of BME680 to GND for selecting i2c addr 0x76
|
|
||||||
#define HAS_BME GPIO_NUM_21, GPIO_NUM_22 // SDA, SCL
|
#define HAS_BME GPIO_NUM_21, GPIO_NUM_22 // SDA, SCL
|
||||||
|
#define BME_ADDR BME680_I2C_ADDR_PRIMARY // connect SDIO of BME680 to GND
|
||||||
|
|
||||||
// user defined sensors
|
// user defined sensors
|
||||||
//#define HAS_SENSORS 1 // comment out if device has user defined sensors
|
//#define HAS_SENSORS 1 // comment out if device has user defined sensors
|
||||||
|
@ -11,11 +11,9 @@
|
|||||||
// disable brownout detection (avoid unexpected reset on some boards)
|
// disable brownout detection (avoid unexpected reset on some boards)
|
||||||
#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature
|
#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature
|
||||||
|
|
||||||
// enable only if device has these sensors, otherwise comment these lines
|
|
||||||
// BME680 sensor on I2C bus
|
|
||||||
// Octopus32 has a pre-populated BME680 on i2c addr 0x76
|
// Octopus32 has a pre-populated BME680 on i2c addr 0x76
|
||||||
#define HAS_BME GPIO_NUM_23, GPIO_NUM_22 // SDA, SCL
|
#define HAS_BME GPIO_NUM_23, GPIO_NUM_22 // SDA, SCL
|
||||||
//#define HAS_BME 0x76
|
#define BME_ADDR BME680_I2C_ADDR_PRIMARY // connect SDIO of BME680 to GND
|
||||||
|
|
||||||
// user defined sensors
|
// user defined sensors
|
||||||
//#define HAS_SENSORS 1 // comment out if device has user defined sensors
|
//#define HAS_SENSORS 1 // comment out if device has user defined sensors
|
||||||
|
@ -8,12 +8,11 @@
|
|||||||
// Hardware related definitions for TTGO T-Beam board
|
// Hardware related definitions for TTGO T-Beam board
|
||||||
//
|
//
|
||||||
// pinouts taken from http://tinymicros.com/wiki/TTGO_T-Beam
|
// pinouts taken from http://tinymicros.com/wiki/TTGO_T-Beam
|
||||||
//
|
|
||||||
// enable only if device has these sensors, otherwise comment these lines
|
// enable only if device has these sensors, otherwise comment these lines
|
||||||
// BME680 sensor on I2C bus
|
// BME680 sensor on I2C bus
|
||||||
// don't forget to connect SDIO of BME680 to GND for selecting i2c addr 0x76
|
#define HAS_BME GPIO_NUM_21, GPIO_NUM_22 // SDA, SCL
|
||||||
//
|
#define BME_ADDR BME680_I2C_ADDR_PRIMARY // connect SDIO of BME680 to GND
|
||||||
//#define HAS_BME GPIO_NUM_21, GPIO_NUM_22 // SDA, SCL
|
|
||||||
|
|
||||||
#define HAS_LED GPIO_NUM_14 // on board green LED
|
#define HAS_LED GPIO_NUM_14 // on board green LED
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user