Add bme680 bsec

This commit is contained in:
Mathieu Maret 2020-07-28 19:37:19 +02:00
parent fc6020e703
commit 976a9a8053
10 changed files with 266 additions and 13 deletions

View File

@ -21,7 +21,7 @@ int BME680GetMeasure(float &t, float &p, float &h, float &g, float &a);
int BME680Setup();
bool BME680IsConnected();
#else //CONFIG_ENABLE_BMP80
#else //CONFIG_ENABLE_BME680
int BME680GetMeasure(float &, float &, float&, float &, float &){return -1;};
int BME680Setup(){SKETCH_DEBUG_PRINTLN("BME680 is disabled at build time"); return -1;};
bool BME680IsConnected(){return false;};

View File

@ -0,0 +1,15 @@
#pragma once
#ifdef CONFIG_BME680_BSEC_ENABLE
int BME680BSECGetMeasure(float &t, float &p, float &h, float &iaq, float &iaqAcc);
int BME680BSECSetup();
bool BME680BSECIsConnected();
#else // CONFIG_ENABLE_BME680_BSEC
int BME680BSECGetMeasure(float &, float &, float &, float &, float &) {
return -1;
};
int BME680BSECSetup() {
SKETCH_DEBUG_PRINTLN("BME680 BSEC is disabled at build time");
return -1;
};
bool BME680BSECIsConnected() { return false; };
#endif

View File

@ -0,0 +1,153 @@
#ifdef CONFIG_BME680_BSEC_ENABLE
#include "BME680_BSEC.h"
#include "bsec.h"
/* Configure the BSEC library with information about the sensor
18v/33v = Voltage at Vdd. 1.8V or 3.3V
3s/300s = BSEC operating mode, BSEC_SAMPLE_RATE_LP or BSEC_SAMPLE_RATE_ULP
4d/28d = Operating age of the sensor in days
generic_18v_3s_4d
generic_18v_3s_28d
generic_18v_300s_4d
generic_18v_300s_28d
generic_33v_3s_4d
generic_33v_3s_28d
generic_33v_300s_4d
generic_33v_300s_28d
*/
const uint8_t bsec_config_iaq[] = {
#if CONFIG_SAMPLING_PERIODE_MS == 3000
#include "config/generic_33v_3s_4d/bsec_iaq.txt"
#elif CONFIG_SAMPLING_PERIODE_MS == 300000
#include "config/generic_33v_300s_4d/bsec_iaq.txt"
#else
#error "Unsupport CONFIG_SAMPLING_PERIODE_MS (3000 and 300000 are supported)"
#endif
};
#define STATE_SAVE_PERIOD \
UINT32_C(360 * 60 * 1000) // 360 minutes - 4 times a day
uint16_t stateUpdateCounter = 0;
Bsec iaqSensor;
uint8_t bsecState[BSEC_MAX_STATE_BLOB_SIZE] = {0};
// Helper function definitions
int checkIaqSensorStatus(void) {
if (iaqSensor.status != BSEC_OK) {
if (iaqSensor.status < BSEC_OK) {
SKETCH_DEBUG_PRINTLN("BSEC error code : " + String(iaqSensor.status));
return -2;
} else {
SKETCH_DEBUG_PRINTLN("BSEC warning code : " + String(iaqSensor.status));
return -1;
}
}
if (iaqSensor.bme680Status != BME680_OK) {
if (iaqSensor.bme680Status < BME680_OK) {
SKETCH_DEBUG_PRINTLN("BME680 error code : " + String(iaqSensor.bme680Status));
return -2;
} else {
SKETCH_DEBUG_PRINTLN("BME680 warning code : " + String(iaqSensor.bme680Status));
return -1;
}
}
iaqSensor.status = BSEC_OK;
return 0;
}
void updateState(void)
{
bool update = false;
/* Set a trigger to save the state. Here, the state is saved every STATE_SAVE_PERIOD with the
* first state being saved once the algorithm achieves full calibration, i.e. iaqAccuracy = 3
*/
if (stateUpdateCounter == 0) {
if (iaqSensor.iaqAccuracy >= 3) {
update = true;
stateUpdateCounter++;
}
} else {
/* Update every STATE_SAVE_PERIOD milliseconds */
if ((stateUpdateCounter * STATE_SAVE_PERIOD) < millis()) {
update = true;
stateUpdateCounter++;
}
}
if (update) {
iaqSensor.getState(bsecState);
checkIaqSensorStatus();
SKETCH_DEBUG_PRINTLN("Writing state to EEPROM");
EepromSaveBME680State(bsecState);
}
}
int BME680BSECGetMeasure(float &t, float &p, float &h, float &iaq, float &iaqAcc)
{
if (iaqSensor.run()) { // If new data is available
t = iaqSensor.temperature;
p = iaqSensor.pressure;
h = iaqSensor.humidity;
iaq = iaqSensor.iaq;
iaqAcc = iaqSensor.iaqAccuracy;
updateState();
} else {
return -1;
}
return 0;
}
int BME680BSECSetup()
{
Wire.begin();
iaqSensor.begin(CONFIG_BME680_BSEC_I2C_ADDR, Wire);
SKETCH_DEBUG_PRINTLN("\nBSEC library version " + String(iaqSensor.version.major) + "." +
String(iaqSensor.version.minor) + "." + String(iaqSensor.version.major_bugfix) +
"." + String(iaqSensor.version.minor_bugfix));
if (checkIaqSensorStatus())
return -1;
iaqSensor.setConfig(bsec_config_iaq);
if (checkIaqSensorStatus())
return -1;
if (!EepromLoadBME680State(bsecState))
iaqSensor.setState(bsecState);
if (checkIaqSensorStatus())
return -1;
bsec_virtual_sensor_t sensorList[7] = {
BSEC_OUTPUT_RAW_TEMPERATURE,
BSEC_OUTPUT_RAW_PRESSURE,
BSEC_OUTPUT_RAW_HUMIDITY,
BSEC_OUTPUT_RAW_GAS,
BSEC_OUTPUT_IAQ,
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
};
iaqSensor.updateSubscription(sensorList, 7, BSEC_SAMPLE_RATE_LP);
if (checkIaqSensorStatus())
return -1;
return 0;
}
bool BME680BSECIsConnected()
{
if (checkIaqSensorStatus())
return false;
return true;
}
#endif

View File

@ -23,3 +23,5 @@ typedef struct productConfig_t {
int EepromSaveConfig(productConfig &config);
int EepromSaveBootMode(uint8_t bootMode);
void EepromReadConfig(productConfig &config);
int EepromSaveBME680State(uint8_t *bsecState);
int EepromLoadBME680State(uint8_t *bsecState);

View File

@ -6,6 +6,8 @@
*/
#include "EEPROM.h"
#define BME680_BSEC_EEPROM_ORIG (CONFIG_EEPROM_SIZE)
char eeprom[CONFIG_EEPROM_SIZE];
int EepromSaveConfig(productConfig &config) {
@ -54,7 +56,6 @@ void readConfElement(char** element, int &i) {
SKETCH_DEBUG_PRINTLN("Looks like there is a configuration issue (too long)");
**element = '\0';
}
}
void EepromReadConfig(productConfig &config) {
@ -101,3 +102,42 @@ void EepromReadConfig(productConfig &config) {
readConfElement(&config.bssid, i);
}
int EepromSaveBME680State(uint8_t *bsecState)
{
for (uint16_t i = BME680_BSEC_EEPROM_ORIG;
i < BME680_BSEC_EEPROM_ORIG + BSEC_MAX_STATE_BLOB_SIZE; i++) {
EEPROM.write(i + 1, bsecState[i]);
}
EEPROM.write(BME680_BSEC_EEPROM_ORIG, BSEC_MAX_STATE_BLOB_SIZE);
EEPROM.commit();
return 0;
}
int EepromLoadBME680State(uint8_t *bsecState)
{
if (EEPROM.read(BME680_BSEC_EEPROM_ORIG) == BSEC_MAX_STATE_BLOB_SIZE) {
// Existing state in EEPROM
SKETCH_DEBUG_PRINTLN("Reading BME680 state from EEPROM");
for (uint16_t i = BME680_BSEC_EEPROM_ORIG;
i < BME680_BSEC_EEPROM_ORIG + BSEC_MAX_STATE_BLOB_SIZE; i++) {
bsecState[i] = EEPROM.read(i + 1);
}
return 0;
} else {
// Erase the EEPROM with zeroes
SKETCH_DEBUG_PRINTLN("Erasing EEPROM for BME680 state");
for (uint16_t i = BME680_BSEC_EEPROM_ORIG;
i < BME680_BSEC_EEPROM_ORIG + BSEC_MAX_STATE_BLOB_SIZE + 1; i++)
EEPROM.write(i, 0);
EEPROM.commit();
return -1;
}
}

View File

@ -16,6 +16,8 @@
#define BME680_HUMIDITY_FEED_FORMAT "/feeds/%s/%s/bme680/humidity"
#define BME680_GAZ_FEED_FORMAT "/feeds/%s/%s/bme680/gaz"
#define BME680_ALT_FEED_FORMAT "/feeds/%s/%s/bme680/alt"
#define BME680_IAQ_FEED_FORMAT "/feeds/%s/%s/bme680/iaq"
#define BME680_IAQ_ACC_FEED_FORMAT "/feeds/%s/%s/bme680/iaqAcc"
#ifndef CONFIG_DISABLE_MQTT
#include "Adafruit_MQTT.h"

View File

@ -40,6 +40,9 @@ void WebHandleRoot() {
#ifdef CONFIG_ENABLE_BME680
"" + (BME680IsConnected() ? "<h6>BME680</h6>Temperature " + String(bme680T, 2) + "C<br/> Pressure " + String(bme680P, 2) + "hPa<br/> Humidity " + String(bme680H, 2) + "%<br/> Gaz " + String(bme680G, 2) + "kOhm<br/>" : "BME680 Disconnected" ) + ""
#endif
#ifdef CONFIG_BME680_BSEC_ENABLE
"" + (BME680BSECIsConnected() ? "<h6>BME680 BSEC</h6>Temperature " + String(bme680BSECT, 2) + "C<br/> Pressure " + String(bme680BSECP, 2) + "hPa<br/> Humidity " + String(bme680BSECH, 2) + "%<br/> Indoor Air Quality " + String(bme680BSECIaq, 2) + "/500<br/> IAQ Accuraccy" + String(bme680BSECIaqAcc) + "/3<br/>": "BME680 Disconnected" ) + ""
#endif
#ifdef CONFIG_ENABLE_DRY_SENSOR
"Dryness " + String((dryness * 100) / 1024) + "%<br/>"
#endif

View File

@ -44,6 +44,7 @@
#include "debug_sketch.h"
#include "BMP180.h"
#include "BME680.h"
#include "BME680_BSEC.h"
#include "sensor_DHT.h"
#include "dry_sensor.h"
#include "MQTT.h"
@ -63,6 +64,7 @@ extern "C" {
double temp, pressure;
float dhtTemp, dhtHumidity;
float bme680T, bme680P, bme680H, bme680G, bme680A;
float bme680BSECT, bme680BSECP, bme680BSECH, bme680BSECIaq, bme680BSECIaqAcc;
int dryness;
uint8_t mode;
int reconfig = 0;
@ -142,7 +144,7 @@ void WifiSetup(productConfig conf) {
reconfig = 0;
return;
}
if (connectionTry == 20) {
if (connectionTry == 60) {
SKETCH_DEBUG_PRINTLN("Cannot connect to wifi. Try without BSSID and channel");
WiFi.begin(conf.ssid, conf.password);
}
@ -278,6 +280,9 @@ void setup() {
if(!BME680Setup()){
SKETCH_DEBUG_PRINTLN("BME680 init success");
}
if(!BME680BSECSetup()){
SKETCH_DEBUG_PRINTLN("BME680 with BSEC init success");
}
WebSetupServer(mode);
}
#ifdef CONFIG_ENABLE_POWER_SAVE
@ -312,7 +317,7 @@ void loop() {
}
if (!DryGetMeasure(dryness)) {
SKETCH_DEBUG_PRINTF("Current dryness %d %%\n", (dryness * 100) / 1024);
batchInfo.push_back({dryness, DRY_FEED_FORMAT, 0, 0});
batchInfo.push_back({(float)dryness, DRY_FEED_FORMAT, 0, 0});
}
if (!BME680GetMeasure(bme680T, bme680P, bme680H, bme680G, bme680A)) {
SKETCH_DEBUG_PRINT("Current T°C: ");
@ -332,6 +337,25 @@ void loop() {
batchInfo.push_back({bme680A, BME680_ALT_FEED_FORMAT, 0, 0});
}
if (!BME680BSECGetMeasure(bme680BSECT, bme680BSECP, bme680BSECH, bme680BSECIaq,
bme680BSECIaqAcc)) {
SKETCH_DEBUG_PRINT("Current T°C: ");
SKETCH_DEBUG_PRINT(bme680BSECT);
SKETCH_DEBUG_PRINT(" Pressure hPa: ");
SKETCH_DEBUG_PRINT(bme680BSECP);
SKETCH_DEBUG_PRINT(" Humidity %: ");
SKETCH_DEBUG_PRINT(bme680BSECH);
SKETCH_DEBUG_PRINT(" Indoor Air Quality: ");
SKETCH_DEBUG_PRINT(bme680BSECIaq);
SKETCH_DEBUG_PRINT(" IAQ Accuracy: ");
SKETCH_DEBUG_PRINTLN(bme680BSECIaqAcc);
batchInfo.push_back({bme680BSECT, BME680_TEMPERATURE_FEED_FORMAT, 0, 0});
batchInfo.push_back({bme680BSECP, BME680_PRESSURE_FEED_FORMAT, 0, 0});
batchInfo.push_back({bme680BSECH, BME680_HUMIDITY_FEED_FORMAT, 0, 0});
batchInfo.push_back({bme680BSECIaq, BME680_IAQ_FEED_FORMAT, 0, 0});
batchInfo.push_back({bme680BSECIaqAcc, BME680_IAQ_ACC_FEED_FORMAT, 0, 0});
}
if (mode == BOOTMODE_NORMAL)
MqttBatchPublish(batchInfo, conf.mqttUser, conf.host);
nbCycle = 0;

View File

@ -13,6 +13,14 @@
#define CONFIG_SAMPLING_PERIODE_MS 60000
#endif
#if defined(CONFIG_ENABLE_BME680) && defined(CONFIG_BME680_BSEC_ENABLE)
#error "BME680 and BME680 BSEC cannot be enabled together"
#endif
#ifndef CONFIG_BME680_BSEC_I2C_ADDR
#define CONFIG_BME680_BSEC_I2C_ADDR 0x76
#endif
#if defined(CONFIG_ENABLE_BMP180) && !defined(CONFIG_BMP180_SDA)
#error "When enabling BMP180, you should configure SDA pin"
#elif !defined(CONFIG_ENABLE_BMP180)

View File

@ -14,16 +14,22 @@
// Enable the temperature, pressure, humidity and gaz Sensor BME680 on standard i2c esp8266 pins
// It use default i2c pin GPIO4(D2): SDA, GPIO5(D1):SCL
#define CONFIG_ENABLE_BME680
// Should be powered by 3.3v and sampled every 3sec or 300s (Or you should adapt bsec_config_iaq in BME680_BSEC.ino )
#define CONFIG_BME680_BSEC_ENABLE
#define CONFIG_BME680_BSEC_I2C_ADDR 0x77
// Enable the temperature, pressure, humidity and gaz Sensor BME680 on standard i2c esp8266 pins
// It use default i2c pin GPIO4(D2): SDA, GPIO5(D1):SCL
//#define CONFIG_ENABLE_BME680
// Enable the temperatue and pressure Sensor BMP180
// (CONFIG_BMP180_SDA and CONFIG_BMP180_SDA should be defined as well)
#define CONFIG_ENABLE_BMP180
#define CONFIG_BMP180_SDA SDA //D2
#define CONFIG_BMP180_SCL SCL //D1
#define CONFIG_ENABLE_DHT
#define CONFIG_DHT_PIN 2
#define CONFIG_DHT_TYPE DHT22
//#define CONFIG_ENABLE_BMP180
//#define CONFIG_BMP180_SDA SDA //D2
//#define CONFIG_BMP180_SCL SCL //D1
//
//#define CONFIG_ENABLE_DHT
//#define CONFIG_DHT_PIN 2
//#define CONFIG_DHT_TYPE DHT22
//#define CONFIG_ENABLE_DRY_SENSOR
//If the dry sensor is powered by a GPIO, this GPIO could be defined here
@ -47,7 +53,7 @@
//#define CONFIG_WEB_DELAY_MS 100
// Get sensors value every X ms
#define CONFIG_SAMPLING_PERIODE_MS 300000
#define CONFIG_SAMPLING_PERIODE_MS 3000
// Name of the SSID when in AP mode for configuration
#define CONFIG_SSID_NAME "ESPConfiguratorBureau"