diff --git a/include/bme680mems.h b/include/bme680mems.h index 5532f0cc..00742ff9 100644 --- a/include/bme680mems.h +++ b/include/bme680mems.h @@ -47,8 +47,11 @@ const uint8_t bsec_config_iaq[454] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 44, 1, 0, 0, 0, 0, 239, 79, 0, 0}; +// Helper functions declarations int bme_init(); void bme_loop(void *pvParameters); int checkIaqSensorStatus(void); +void loadState(void); +void updateState(void); #endif \ No newline at end of file diff --git a/include/cyclic.h b/include/cyclic.h index 1c4da4dd..6e5df0cd 100644 --- a/include/cyclic.h +++ b/include/cyclic.h @@ -7,6 +7,10 @@ #include "spislave.h" #include +#ifdef HAS_BME +#include "bme680mems.h" +#endif + void doHousekeeping(void); void do_timesync(void); uint64_t uptime(void); diff --git a/include/globals.h b/include/globals.h index 7fda0d29..261c1fb8 100644 --- a/include/globals.h +++ b/include/globals.h @@ -54,6 +54,7 @@ typedef struct { uint8_t runmode; // 0=normal, 1=update uint8_t payloadmask; // bitswitches for payload data char version[10]; // Firmware version + char bsecstate[BSEC_MAX_STATE_BLOB_SIZE+1]; // init BSEC state for BME680 sensor } configData_t; // Struct holding payload for data send queue @@ -87,7 +88,7 @@ extern configData_t cfg; // current device configuration extern char display_line6[], display_line7[]; // screen buffers extern uint8_t volatile channel; // wifi channel rotation counter extern uint16_t volatile macs_total, macs_wifi, macs_ble, - batt_voltage; // display values + batt_voltage; // display values extern hw_timer_t *channelSwitch, *sendCycle, *displaytimer; extern SemaphoreHandle_t I2Caccess; diff --git a/platformio.ini b/platformio.ini index ecbbf0de..59e70845 100644 --- a/platformio.ini +++ b/platformio.ini @@ -6,7 +6,7 @@ ; ---> SELECT TARGET PLATFORM HERE! <--- [platformio] -;env_default = generic +env_default = generic ;env_default = ebox ;env_default = eboxtube ;env_default = heltec @@ -16,7 +16,7 @@ ;env_default = ttgov21old ;env_default = ttgov21new ;env_default = ttgobeam_old -env_default = ttgobeam_new +;env_default = ttgobeam_new ;env_default = lopy ;env_default = lopy4 ;env_default = fipy @@ -30,10 +30,10 @@ description = Paxcounter is a proof-of-concept ESP32 device for metering passeng [common] ; for release_version use max. 10 chars total, use any decimal format like "a.b.c" -release_version = 1.7.03 +release_version = 1.7.06 ; 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 -debug_level = 3 +debug_level = 0 ; UPLOAD MODE: select esptool to flash via USB/UART, select custom to upload to cloud for OTA upload_protocol = esptool ;upload_protocol = custom diff --git a/src/TTN/packed_decoder.js b/src/TTN/packed_decoder.js index c8f319a2..a99f44c6 100644 --- a/src/TTN/packed_decoder.js +++ b/src/TTN/packed_decoder.js @@ -18,7 +18,11 @@ function Decoder(bytes, port) { if (bytes.length === 4) { return decode(bytes, [uint16, uint16], ['wifi', 'ble']); } - // combined counter and gps data + // combined wifi counter and gps data + if (bytes.length === 15) { + return decode(bytes, [uint16, latLng, latLng, uint8, hdop, uint16], ['wifi', 'latitude', 'longitude', 'sats', 'hdop', 'altitude']); + } + // combined wifi + ble counter and gps data if (bytes.length === 17) { return decode(bytes, [uint16, uint16, latLng, latLng, uint8, hdop, uint16], ['wifi', 'ble', 'latitude', 'longitude', 'sats', 'hdop', 'altitude']); } diff --git a/src/bme680mems.cpp b/src/bme680mems.cpp index 58570dda..19111ba3 100644 --- a/src/bme680mems.cpp +++ b/src/bme680mems.cpp @@ -23,9 +23,12 @@ bsec_virtual_sensor_t sensorList[10] = { BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY, }; +uint8_t bsecState[BSEC_MAX_STATE_BLOB_SIZE] = {0}; +uint16_t stateUpdateCounter = 0; + // initialize BME680 sensor int bme_init(void) { - + // block i2c bus access if (xSemaphoreTake(I2Caccess, (DISPLAYREFRESH_MS / portTICK_PERIOD_MS)) == pdTRUE) { @@ -46,6 +49,8 @@ int bme_init(void) { return 1; } + loadState(); + iaqSensor.setTemperatureOffset((float)BME_TEMP_OFFSET); iaqSensor.updateSubscription(sensorList, 10, BSEC_SAMPLE_RATE_LP); @@ -99,7 +104,6 @@ void bme_loop(void *pvParameters) { // block i2c bus access if (xSemaphoreTake(I2Caccess, (DISPLAYREFRESH_MS / portTICK_PERIOD_MS)) == pdTRUE) { - if (iaqSensor.run()) { // If new data is available bme_status.raw_temperature = iaqSensor.rawTemperature; bme_status.raw_humidity = iaqSensor.rawHumidity; @@ -111,7 +115,6 @@ void bme_loop(void *pvParameters) { bme_status.iaq_accuracy = iaqSensor.iaqAccuracy; bme_status.gas = iaqSensor.gasResistance; } - xSemaphoreGive(I2Caccess); // release i2c bus access } } @@ -121,4 +124,43 @@ void bme_loop(void *pvParameters) { } // bme_loop() +void loadState(void) { + if (cfg.bsecstate[BSEC_MAX_STATE_BLOB_SIZE + 1] == BSEC_MAX_STATE_BLOB_SIZE) { + // Existing state in NVS stored + ESP_LOGI(TAG, "restoring BSEC state from NVRAM"); + memcpy(bsecState, cfg.bsecstate, BSEC_MAX_STATE_BLOB_SIZE); + iaqSensor.setState(bsecState); + checkIaqSensorStatus(); + } else // no state stored + ESP_LOGI(TAG, + "no BSEC state stored in NVRAM, starting sensor with defaults"); +} + +void updateState(void) { + bool update = false; + + if (stateUpdateCounter == 0) { + /* First state update when IAQ accuracy is >= 1 */ + if (iaqSensor.iaqAccuracy >= 3) { + update = true; + stateUpdateCounter++; + } + } else { + /* Update every STATE_SAVE_PERIOD minutes */ + if ((stateUpdateCounter * STATE_SAVE_PERIOD) < millis()) { + update = true; + stateUpdateCounter++; + } + } + + if (update) { + memcpy(bsecState, cfg.bsecstate, BSEC_MAX_STATE_BLOB_SIZE); + cfg.bsecstate[BSEC_MAX_STATE_BLOB_SIZE + 1] = BSEC_MAX_STATE_BLOB_SIZE; + iaqSensor.getState(bsecState); + checkIaqSensorStatus(); + ESP_LOGI(TAG, "saving BSEC state to NVRAM"); + saveConfig(); + } +} + #endif // HAS_BME \ No newline at end of file diff --git a/src/configmanager.cpp b/src/configmanager.cpp index 5c6ebf98..ba5ed25e 100644 --- a/src/configmanager.cpp +++ b/src/configmanager.cpp @@ -32,6 +32,8 @@ void defaultConfig() { cfg.monitormode = 0; // 0=disabled, 1=enabled cfg.runmode = 0; // 0=normal, 1=update cfg.payloadmask = 0xFF; // all payload switched on + cfg.bsecstate[BSEC_MAX_STATE_BLOB_SIZE + 1] = { + 0}; // init BSEC state for BME680 sensor strncpy(cfg.version, PROGVERSION, sizeof(cfg.version) - 1); } @@ -78,6 +80,12 @@ void saveConfig() { int16_t flash16 = 0; size_t required_size; char storedversion[10]; + char bsecstate[BSEC_MAX_STATE_BLOB_SIZE + 1]; + + if (nvs_get_str(my_handle, "bsecstate", bsecstate, &required_size) != + ESP_OK || + strcmp(bsecstate, cfg.bsecstate) != 0) + nvs_set_str(my_handle, "bsecstate", cfg.bsecstate); if (nvs_get_str(my_handle, "version", storedversion, &required_size) != ESP_OK || @@ -202,7 +210,16 @@ void loadConfig() { migrateVersion(); } - // overwrite defaults with valid values from NVRAM + // populate pre set defaults with current values from NVRAM + + char bsecstate[BSEC_MAX_STATE_BLOB_SIZE + 1]; + + if (nvs_get_str(my_handle, "bsecstate", NULL, &required_size) == ESP_OK) { + nvs_get_str(my_handle, "bsecstate", cfg.bsecstate, &required_size); + ESP_LOGI(TAG, "bsecstate = %d", + cfg.bsecstate[BSEC_MAX_STATE_BLOB_SIZE + 1]); + } + if (nvs_get_i8(my_handle, "lorasf", &flash8) == ESP_OK) { cfg.lorasf = flash8; ESP_LOGI(TAG, "lorasf = %d", flash8); diff --git a/src/cyclic.cpp b/src/cyclic.cpp index 0ce0c657..237a86be 100644 --- a/src/cyclic.cpp +++ b/src/cyclic.cpp @@ -58,6 +58,7 @@ void doHousekeeping() { // display BME sensor data if present #ifdef HAS_BME ESP_LOGI(TAG, "BME680 Temp: %.2f°C | IAQ: %.2f", bme_status.temperature, bme_status.iaq); + updateState(); #endif // check free heap memory diff --git a/src/hal/ttgobeam_new.h b/src/hal/ttgobeam_new.h index d177e033..3751e436 100644 --- a/src/hal/ttgobeam_new.h +++ b/src/hal/ttgobeam_new.h @@ -11,18 +11,18 @@ // enable only if device has these sensors, otherwise comment these lines // BME680 sensor on I2C bus -#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 BME_ADDR BME680_I2C_ADDR_PRIMARY // connect SDIO of BME680 to GND #define HAS_LED GPIO_NUM_14 // on board green LED // user defined sensors //#define HAS_SENSORS 1 // comment out if device has user defined sensors -#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C -#define MY_OLED_SDA (21) -#define MY_OLED_SCL (22) -#define MY_OLED_RST U8X8_PIN_NONE +//#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C +//#define MY_OLED_SDA (21) +//#define MY_OLED_SCL (22) +//#define MY_OLED_RST U8X8_PIN_NONE //#define DISPLAY_FLIP 1 // use if display is rotated #define HAS_LORA 1 // comment out if device shall not send data via LoRa diff --git a/src/paxcounter.conf b/src/paxcounter.conf index 2254533a..6293b4af 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -72,6 +72,8 @@ // Settings for BME680 environmental sensor (if present) #define BME_TEMP_OFFSET 5.0f // Offset sensor on chip temp <-> ambient temp [default = 5°C] +#define BSEC_MAX_STATE_BLOB_SIZE 134 // size of Bosch BME680 state data blob +#define STATE_SAVE_PERIOD UINT32_C(360 * 60 * 1000) // update every 360 minutes = 4 times a day // OTA settings #define USE_OTA 1 // Comment out to disable OTA update