diff --git a/multigeiger/ble.cpp b/multigeiger/ble.cpp index 4194a77..3e6e39b 100644 --- a/multigeiger/ble.cpp +++ b/multigeiger/ble.cpp @@ -22,6 +22,14 @@ static NimBLEServer *bleServer; #define BLE_CHAR_HR_MEASUREMENT BLEUUID((uint16_t)0x2A37) // 16 bit UUID of Heart Rate Measurement Characteristic #define BLE_CHAR_HR_POSITION BLEUUID((uint16_t)0x2A38) // 16 bit UUID of Heart Rate Sensor Position Characteristic #define BLE_CHAR_HR_CONTROLPOINT BLEUUID((uint16_t)0x2A39) // 16 bit UUID of Heart Rate Control Point Characteristic + +#define BLE_SERVICE_ENVIRONMENTAL BLEUUID((uint16_t)0x181A) // 16 bit UUID of EnvironmentaL Service +#define BLE_CHAR_ENV_TEMPERATURE BLEUUID((uint16_t)0x2A6E) // 16 bit UUID of EnvironmentaL Temperature Characteristic (yields 16 bit little endian, 0.01 degC) +#define BLE_CHAR_ENV_HUMIDITY BLEUUID((uint16_t)0x2A6F) // 16 bit UUID of EnvironmentaL Humidity Characteristic (yields 16 bit little endian, 0.01 %) +#define BLE_CHAR_ENV_PRESSURE BLEUUID((uint16_t)0x2A6D) // 16 bit UUID of EnvironmentaL Air Pressure Characteristic (yields 32 bit little endian, 0.1 Pa) +#define BLE_CHAR_ENV_IAQ BLEUUID(0x422302f1, 0x2342, 0x2342, 0x2342234223422342) // 128 bit UUID of Environmental Indoor Air Quality (yields 16 bit little endian IAQ) +// Characteristic for IAQ from 2019 Chaos Communication Camp card10 https://firmware.card10.badge.events.ccc.de/bluetooth/ess.html + #define BLE_DESCR_UUID BLEUUID((uint16_t)0x2901) // 16 bit UUID of BLE Descriptor static bool ble_enabled = false; @@ -57,7 +65,7 @@ class MyCharacteristicCallbacks: public NimBLECharacteristicCallbacks { } }; -void update_bledata(unsigned int cpm) { +void update_bledata(unsigned int cpm, float temperature, float humidity, float pressure, int iaq) { if (!ble_enabled) return; cpm_update_counter++; @@ -81,7 +89,34 @@ void update_bledata(unsigned int cpm) { bleChr->notify(); } } + NimBLEService *bleEnvSvc = bleServer->getServiceByUUID(BLE_SERVICE_ENVIRONMENTAL); + if (bleEnvSvc) { + uint8_t txBufferEnv[4]; + NimBLECharacteristic *bleEnvTChr = bleEnvSvc->getCharacteristic(BLE_CHAR_ENV_TEMPERATURE); + if (bleEnvTChr) { + bleEnvTChr->setValue(int(temperature * 100)); + bleEnvTChr->notify(); + } + NimBLECharacteristic *bleEnvHChr = bleEnvSvc->getCharacteristic(BLE_CHAR_ENV_HUMIDITY); + if (bleEnvHChr) { + bleEnvHChr->setValue(int(humidity * 100)); + bleEnvHChr->notify(); + } + NimBLECharacteristic *bleEnvPChr = bleEnvSvc->getCharacteristic(BLE_CHAR_ENV_PRESSURE); + if (bleEnvPChr) { + bleEnvPChr->setValue(int(pressure * 10)); + bleEnvPChr->notify(); + } + NimBLECharacteristic *bleEnvIAQChr = bleEnvSvc->getCharacteristic(BLE_CHAR_ENV_IAQ); + if (bleEnvIAQChr) { + txBufferEnv[0] = iaq & 0xFF; + txBufferEnv[1] = (iaq >> 8) & 0xFF; + bleEnvIAQChr->setValue(txBufferEnv, 2); + bleEnvIAQChr->notify(); + } + } } + } void setup_ble(char *device_name, bool ble_on) { @@ -98,29 +133,48 @@ void setup_ble(char *device_name, bool ble_on) { bleServer = NimBLEDevice::createServer(); bleServer->setCallbacks(new MyServerCallbacks()); - NimBLEService *bleService = bleServer->createService(BLE_SERVICE_HEART_RATE); + // Heart Rate Service for CPM + NimBLEService *bleHRService = bleServer->createService(BLE_SERVICE_HEART_RATE); - NimBLECharacteristic *bleCharHRM = bleService->createCharacteristic(BLE_CHAR_HR_MEASUREMENT, NIMBLE_PROPERTY::NOTIFY); + NimBLECharacteristic *bleCharHRM = bleHRService->createCharacteristic(BLE_CHAR_HR_MEASUREMENT, NIMBLE_PROPERTY::NOTIFY); NimBLEDescriptor *bleDescriptorHRM = bleCharHRM->createDescriptor(BLE_DESCR_UUID, NIMBLE_PROPERTY::READ, 20); bleDescriptorHRM->setValue("Radiation rate CPM"); -// bleCharHRM.addDescriptor(new BLE2902()); // required for notification management of the service; automatically added by NimBLE lib - NimBLECharacteristic *bleCharHRCP = bleService->createCharacteristic(BLE_CHAR_HR_CONTROLPOINT, NIMBLE_PROPERTY::WRITE); + NimBLECharacteristic *bleCharHRCP = bleHRService->createCharacteristic(BLE_CHAR_HR_CONTROLPOINT, NIMBLE_PROPERTY::WRITE); NimBLEDescriptor *bleDescriptorHRCP = bleCharHRCP->createDescriptor(BLE_DESCR_UUID, NIMBLE_PROPERTY::READ, 50); bleDescriptorHRCP->setValue("0x01 for Energy Exp. (packet counter) reset"); - NimBLECharacteristic *bleCharHRPOS = bleService->createCharacteristic(BLE_CHAR_HR_POSITION, NIMBLE_PROPERTY::READ); + NimBLECharacteristic *bleCharHRPOS = bleHRService->createCharacteristic(BLE_CHAR_HR_POSITION, NIMBLE_PROPERTY::READ); NimBLEDescriptor *bleDescriptorHRPOS = bleCharHRPOS->createDescriptor(BLE_DESCR_UUID, NIMBLE_PROPERTY::READ, 30); bleDescriptorHRPOS->setValue("Geiger Mueller Tube Type"); bleCharHRCP->setCallbacks(new MyCharacteristicCallbacks()); bleCharHRPOS->setValue(txBuffer_HRPOS, 1); + // Environmental Service for temperature, humidity, air pressure, IAQ indoor air quality + NimBLEService *bleEnvService = bleServer->createService(BLE_SERVICE_ENVIRONMENTAL); + + NimBLECharacteristic *bleCharEnvT = bleEnvService->createCharacteristic(BLE_CHAR_ENV_TEMPERATURE, NIMBLE_PROPERTY::NOTIFY); + NimBLEDescriptor *bleDescriptorEnvT = bleCharEnvT->createDescriptor(BLE_DESCR_UUID, NIMBLE_PROPERTY::READ, 30); + bleDescriptorEnvT->setValue("Temperature (.01 Celsius)"); + NimBLECharacteristic *bleCharEnvH = bleEnvService->createCharacteristic(BLE_CHAR_ENV_HUMIDITY, NIMBLE_PROPERTY::NOTIFY); + NimBLEDescriptor *bleDescriptorEnvH = bleCharEnvH->createDescriptor(BLE_DESCR_UUID, NIMBLE_PROPERTY::READ, 30); + bleDescriptorEnvH->setValue("Rel. humidity (.01 %)"); + NimBLECharacteristic *bleCharEnvP = bleEnvService->createCharacteristic(BLE_CHAR_ENV_PRESSURE, NIMBLE_PROPERTY::NOTIFY); + NimBLEDescriptor *bleDescriptorEnvP = bleCharEnvP->createDescriptor(BLE_DESCR_UUID, NIMBLE_PROPERTY::READ, 30); + bleDescriptorEnvP->setValue("Air pressure (.1 Pa)"); + NimBLECharacteristic *bleCharEnvIAQ = bleEnvService->createCharacteristic(BLE_CHAR_ENV_IAQ, NIMBLE_PROPERTY::NOTIFY); + NimBLEDescriptor *bleDescriptorEnvIAQ = bleCharEnvIAQ->createDescriptor(BLE_DESCR_UUID, NIMBLE_PROPERTY::READ, 50); + bleDescriptorEnvIAQ->setValue("Indoor air quality (25 good .. 500 bad)"); + + bleServer->getAdvertising()->addServiceUUID(BLE_SERVICE_HEART_RATE); + bleServer->getAdvertising()->addServiceUUID(BLE_SERVICE_ENVIRONMENTAL); bleServer->getAdvertising()->setScanResponse(true); bleServer->getAdvertising()->setMinPreferred(0x06); bleServer->getAdvertising()->setMinPreferred(0x12); - bleService->start(); + bleHRService->start(); + bleEnvService->start(); bleServer->getAdvertising()->start(); set_status(STATUS_BLE, ST_BLE_CONNECTABLE); diff --git a/multigeiger/ble.h b/multigeiger/ble.h index a78aa03..147b011 100644 --- a/multigeiger/ble.h +++ b/multigeiger/ble.h @@ -5,7 +5,7 @@ #define _BLE_H_ void setup_ble(char *device_name, bool ble_enabled); -void update_bledata(unsigned int cpm); +void update_bledata(unsigned int cpm, float temperature, float humidity, float pressure, int iaq); bool is_ble_connected(void); void disable_ble(void); diff --git a/multigeiger/log_data.cpp b/multigeiger/log_data.cpp index c7cb19f..de8831c 100644 --- a/multigeiger/log_data.cpp +++ b/multigeiger/log_data.cpp @@ -7,10 +7,10 @@ int Serial_Print_Mode; static const char *Serial_Logging_Name = "Simple Multi-Geiger"; -static const char *dashes = "------------------------------------------------------------------------------------------------------------------------"; +static const char *dashes = "-----------------------------------------------------------------------------------------------------------------------------"; -static const char *Serial_Logging_Header = " %10s %15s %10s %9s %9s %8s %9s %9s %9s %5s %5s %6s"; -static const char *Serial_Logging_Body = "DATA %10d %15d %10f %9f %9d %8d %9d %9f %9f %5.1f %5.1f %6.0f"; +static const char *Serial_Logging_Header = " %10s %15s %10s %9s %9s %8s %9s %9s %9s %5s %5s %6s %4s"; +static const char *Serial_Logging_Body = "DATA %10d %15d %10f %9f %9d %8d %9d %9f %9f %5.1f %5.1f %6.0f %4d"; static const char *Serial_One_Minute_Log_Header = " %4s %10s %29s"; static const char *Serial_One_Minute_Log_Body = "DATA %4d %10d %29d"; @@ -28,19 +28,19 @@ void setup_log_data(int mode) { void log_data(int GMC_counts, int time_difference, float Count_Rate, float Dose_Rate, int HV_pulse_count, int accumulated_GMC_counts, int accumulated_time, float accumulated_Count_Rate, float accumulated_Dose_Rate, - float t, float h, float p) { + float t, float h, float p, int iaq) { static int counter = 0; if (counter++ % 20 == 0) { // output the header now and then, so table is better readable log(INFO, Serial_Logging_Header, - "GMC_counts", "Time_difference", "Count_Rate", "Dose_Rate", "HV Pulses", "Accu_GMC", "Accu_Time", "Accu_Rate", "Accu_Dose", "Temp", "Humi", "Press"); + "GMC_counts", "Time_difference", "Count_Rate", "Dose_Rate", "HV Pulses", "Accu_GMC", "Accu_Time", "Accu_Rate", "Accu_Dose", "Temp", "Humi", "Press", "IAQ"); log(INFO, Serial_Logging_Header, - "[Counts]", "[ms]", "[cps]", "[uSv/h]", "[-]", "[Counts]", "[ms]", "[cps]", "[uSv/h]", "[C]", "[%]", "[hPa]"); + "[Counts]", "[ms]", "[cps]", "[uSv/h]", "[-]", "[Counts]", "[ms]", "[cps]", "[uSv/h]", "[C]", "[%]", "[hPa]", "[-]"); log(INFO, dashes); } log(INFO, Serial_Logging_Body, GMC_counts, time_difference, Count_Rate, Dose_Rate, HV_pulse_count, accumulated_GMC_counts, accumulated_time, accumulated_Count_Rate, accumulated_Dose_Rate, - t, h, p); + t, h, p, iaq); } void log_data_one_minute(int time_s, int cpm, int counts) { diff --git a/multigeiger/log_data.h b/multigeiger/log_data.h index 46ad12d..1579c88 100644 --- a/multigeiger/log_data.h +++ b/multigeiger/log_data.h @@ -15,7 +15,7 @@ extern int Serial_Print_Mode; void setup_log_data(int mode); void log_data(int GMC_counts, int time_difference, float Count_Rate, float Dose_Rate, int HV_pulse_count, int accumulated_GMC_counts, int accumulated_time, float accumulated_Count_Rate, float accumulated_Dose_Rate, - float t, float h, float p); + float t, float h, float p, int iaq); void log_data_one_minute(int time_s, int cpm, int counts); void log_data_statistics(int count_time_between); diff --git a/multigeiger/multigeiger.ino b/multigeiger/multigeiger.ino index 8031f20..73a4eb6 100644 --- a/multigeiger/multigeiger.ino +++ b/multigeiger/multigeiger.ino @@ -107,7 +107,7 @@ int update_ble_status(void) { // currently no error detection } void publish(unsigned long current_ms, unsigned long current_counts, unsigned long gm_count_timestamp, unsigned long current_hv_pulses, - float temperature, float humidity, float pressure) { + float temperature, float humidity, float pressure, int iaq) { static unsigned long last_timestamp = millis(); static unsigned long last_counts = 0; static unsigned long last_hv_pulses = 0; @@ -144,7 +144,7 @@ void publish(unsigned long current_ms, unsigned long current_counts, unsigned lo accumulated_Dose_Rate = accumulated_Count_Rate * GMC_factor_uSvph; // ... and update the data on display, notify via BLE - update_bledata((unsigned int)(Count_Rate * 60)); + update_bledata((unsigned int)(Count_Rate * 60), temperature, humidity, pressure, iaq); display_GMC((unsigned int)(accumulated_time / 1000), (int)(accumulated_Dose_Rate * 1000), (int)(Count_Rate * 60), (showDisplay && switches.display_on)); @@ -162,7 +162,7 @@ void publish(unsigned long current_ms, unsigned long current_counts, unsigned lo if (Serial_Print_Mode == Serial_Logging) { log_data(counts, dt, Count_Rate, Dose_Rate, hv_pulses, accumulated_GMC_counts, accumulated_time, accumulated_Count_Rate, accumulated_Dose_Rate, - temperature, humidity, pressure); + temperature, humidity, pressure, iaq); } } else { // If there were no pulses after AFTERSTART msecs after boot, clear display anyway and show 0 counts. @@ -170,7 +170,7 @@ void publish(unsigned long current_ms, unsigned long current_counts, unsigned lo static unsigned long afterStartTime = AFTERSTART; if (afterStartTime && ((current_ms - boot_timestamp) >= afterStartTime)) { afterStartTime = 0; - update_bledata(0); + update_bledata(0, 0, 0, 0, 0); display_GMC(0, 0, 0, (showDisplay && switches.display_on)); } } @@ -200,14 +200,13 @@ void statistics_log(unsigned long current_counts, unsigned int time_between) { } } -void read_THP(unsigned long current_ms, - bool *have_thp, float *temperature, float *humidity, float *pressure) { +void read_THP(unsigned long current_ms, bool *have_thp, float *temperature, float *humidity, float *pressure, int *iaq) { static unsigned long last_timestamp = 0; // first call: immediately query thp sensor - // subsequent calls: only query every MEASUREMENT_INTERVAL - if (!last_timestamp || (current_ms - last_timestamp) >= (MEASUREMENT_INTERVAL * 1000)) { + // subsequent calls: only query every BME680_BSEC_LP_READOUT_INTERVAL + if (!last_timestamp || (current_ms - last_timestamp) >= BME680_BSEC_LP_READOUT_INTERVAL) { last_timestamp = current_ms; - *have_thp = read_thp_sensor(temperature, humidity, pressure); + *have_thp = read_thp_sensor(temperature, humidity, pressure, iaq); } } @@ -246,6 +245,7 @@ void loop() { static bool have_thp = false; static float temperature = 0.0, humidity = 0.0, pressure = 0.0; + static int iaq = 0; unsigned long current_ms = millis(); // to save multiple calls to millis() @@ -270,7 +270,7 @@ void loop() { read_GMC(&gm_counts, &gm_count_timestamp, &gm_count_time_between); - read_THP(current_ms, &have_thp, &temperature, &humidity, &pressure); + read_THP(current_ms, &have_thp, &temperature, &humidity, &pressure, &iaq); read_hv(&hv_error, &hv_pulses); set_status(STATUS_HV, hv_error ? ST_HV_ERROR : ST_HV_OK); @@ -283,7 +283,7 @@ void loop() { // do any other periodic updates for uplinks poll_transmission(); - publish(current_ms, gm_counts, gm_count_timestamp, hv_pulses, temperature, humidity, pressure); + publish(current_ms, gm_counts, gm_count_timestamp, hv_pulses, temperature, humidity, pressure, iaq); if (Serial_Print_Mode == Serial_One_Minute_Log) one_minute_log(current_ms, gm_counts); diff --git a/multigeiger/thp_sensor.cpp b/multigeiger/thp_sensor.cpp index d4f79f7..cc02acc 100644 --- a/multigeiger/thp_sensor.cpp +++ b/multigeiger/thp_sensor.cpp @@ -3,18 +3,73 @@ #include #include -#include -#include - #include "log.h" #include "thp_sensor.h" -static int type_thp = 0; +#include +/* + Bosch BSEC Lib, https://github.com/BoschSensortec/BSEC-Arduino-library + The BSEC software is only available for download or use after accepting the software license agreement. + By using this library, you have agreed to the terms of the license agreement: + https://ae-bst.resource.bosch.com/media/_tech/media/bsec/2017-07-17_ClickThrough_License_Terms_Environmentalib_SW_CLEAN.pdf */ +#include + +/* 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[] = { + // #include "config\generic_33v_3s_4d\bsec_iaq.txt" + 0, 8, 4, 1, 61, 0, 0, 0, 0, 0, 0, 0, 174, 1, 0, 0, 48, 0, 1, 0, 0, 192, 168, 71, 64, 49, 119, 76, 0, 0, 225, 68, 137, 65, 0, 191, 205, 204, 204, 190, 0, 0, 64, 191, 225, 122, 148, 190, 0, 0, 0, 0, 216, 85, 0, 100, 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, 237, 52, 0, 0 +}; Adafruit_BME280 bme280; -Adafruit_BME680 bme680; +Bsec iaqSensor; // Create an object of the class Bsec, based on BME680 +bsec_virtual_sensor_t sensorList[10] = { // Active virtual sensors for BSEC + 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, +}; + + +#define BME_TEMP_CORRECTION 1 // only 1 degree as on separate PCB + +static int type_thp = 0; + +// Helper functions declarations +bool checkIaqSensorStatus(void); + +const char *get_thp_name() { + switch (type_thp) { + case 0: + return "no THP sensor"; + case 280: + return "BME280"; + case 680: + return "BME680_BSEC"; + default: + return "no defined THP sensor"; + } +} bool setup_thp_sensor(void) { + // BME280 if (bme280.begin(BME280_ADDRESS)) type_thp = 280; @@ -23,50 +78,89 @@ bool setup_thp_sensor(void) { // BME680 if (type_thp == 0) { - if (bme680.begin(BME68X_I2C_ADDR_LOW)) - type_thp = 680; - else if (bme680.begin(BME68X_I2C_ADDR_HIGH)) + iaqSensor.begin(BME680_I2C_ADDR_PRIMARY, Wire); + if (checkIaqSensorStatus()) type_thp = 680; + else { + iaqSensor.begin(BME680_I2C_ADDR_SECONDARY, Wire); + if (checkIaqSensorStatus()) + type_thp = 680; + } } - switch (type_thp) { - case 680: - // Set up oversampling and filter initialization - bme680.setTemperatureOversampling(BME680_OS_8X); - bme680.setHumidityOversampling(BME680_OS_2X); - bme680.setPressureOversampling(BME680_OS_4X); - bme680.setIIRFilterSize(BME680_FILTER_SIZE_3); - bme680.setGasHeater(300, 150); // 300*C for 150 ms - log(INFO, "BME_Status: ok, ID: BME680"); - break; - case 280: - log(INFO, "BME_Status: ok, ID: BME280"); - break; - default: - log(INFO, "BME_Status: not found"); - break; + // BME680 initialization + if (type_thp == 680) { + iaqSensor.setConfig(bsec_config_iaq); + if (!checkIaqSensorStatus()) { + type_thp = 0; + log(INFO, "THP_Status: BME680 config error"); + } + } + if (type_thp == 680) { + iaqSensor.updateSubscription(sensorList, 10, BSEC_SAMPLE_RATE_LP); + if (!checkIaqSensorStatus()) { + type_thp = 0; + log(INFO, "THP_Status: BME680 sensor subscription error"); + } } + if (type_thp == 680) { + iaqSensor.setTemperatureOffset(BME_TEMP_CORRECTION); + if (!iaqSensor.run()) { + type_thp = 0; + log(INFO, "THP_Status: BME680 sensor readout error"); + } + } + + log(INFO, "THP_Status: %s initialized", get_thp_name()); return (type_thp > 0); } -bool read_thp_sensor(float *temperature, float *humidity, float *pressure) { +bool read_thp_sensor(float *temperature, float *humidity, float *pressure, int *iaq) { + static int bsec_failcount = 0; if (type_thp == 280) { *temperature = bme280.readTemperature(); *humidity = bme280.readHumidity(); *pressure = bme280.readPressure(); + *iaq = 0; } else if (type_thp == 680) { - if (!bme680.performReading()) { - log(INFO, "BME680: Failed to perform reading"); + if (!iaqSensor.run()) + bsec_failcount++; + else + bsec_failcount = 0; + if (bsec_failcount > 10) { + log(INFO, "THP_Status: BME680_BSEC multiple readout errors"); return false; } - *temperature = bme680.temperature; - *humidity = bme680.humidity; - *pressure = bme680.pressure; + *temperature = iaqSensor.temperature; + *humidity = iaqSensor.humidity; + *pressure = iaqSensor.pressure; + *iaq = iaqSensor.iaq; } else { *temperature = 0.0; *humidity = 0.0; *pressure = 0.0; + *iaq = 0; } return (type_thp > 0); } +bool checkIaqSensorStatus(void) { + if (iaqSensor.status != BSEC_OK) { + if (iaqSensor.status < BSEC_OK) + log(INFO, "THP_Status: BSEC error - code %d", (int)iaqSensor.status); + else + log(INFO, "THP_Status: BSEC warning - code %d", (int)iaqSensor.status); + return false; + } + + if (iaqSensor.bme680Status != BME680_OK) { + if (iaqSensor.bme680Status < BME680_OK) + log(INFO, "THP_Status: BME680 error - code %d", (int)iaqSensor.status); + else + log(INFO, "THP_Status: BME680 warning - code %d", (int)iaqSensor.status); + Serial.println(iaqSensor.status); + return false; + } + + return true; +} diff --git a/multigeiger/thp_sensor.h b/multigeiger/thp_sensor.h index f43a9ab..50a7a91 100644 --- a/multigeiger/thp_sensor.h +++ b/multigeiger/thp_sensor.h @@ -3,7 +3,10 @@ #ifndef _THP_SENSOR_H_ #define _THP_SENSOR_H_ +#define BME680_BSEC_LP_READOUT_INTERVAL 3000 // ms + bool setup_thp_sensor(void); -bool read_thp_sensor(float *temperature, float *humidity, float *pressure); +const char *get_thp_name(void); +bool read_thp_sensor(float *temperature, float *humidity, float *pressure, int *iaq); #endif // _THP_SENSOR_H_ diff --git a/platformio-example.ini b/platformio-example.ini index 765db24..608a17e 100644 --- a/platformio-example.ini +++ b/platformio-example.ini @@ -25,8 +25,8 @@ framework = arduino monitor_speed=115200 lib_deps= U8g2 - Adafruit BME680 Library@^2.0.0 Adafruit BME280 Library + boschsensortec/BSEC Software Library@^1.6.1480 Adafruit Unified Sensor IotWebConf@^3.1.0 MCCI LoRaWAN LMIC library