diff --git a/README.md b/README.md index b4b6a61f..43afb1c1 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ Depending on board hardware following features are supported: - Silicon unique ID - Battery voltage monitoring - GPS (Generic serial NMEA, or Quectel L76 I2C) +- MEMS sensor (Bosch BME680) Target platform must be selected in [platformio.ini](https://github.com/cyberman54/ESP32-Paxcounter/blob/master/platformio.ini).
Hardware dependent settings (pinout etc.) are stored in board files in /hal directory. If you want to use a ESP32 board which is not yet supported, use hal file generic.h and tailor pin mappings to your needs. Pull requests for new boards welcome.
@@ -198,6 +199,14 @@ Hereafter described is the default *plain* format, which uses MSB bit numbering. byte 1: Beacon RSSI reception level byte 2: Beacon identifier (0..255) +**Port #7:** BME680 query result + + bytes 1-2: Temperature [°C] + bytes 3-4: Pressure [hPa] + byte 5: Humidity [%] + bytes 6-7: Gas resistance [MOhm] + bytes 8-9: Altitude [meter] + # Remote control The device listenes for remote control commands on LoRaWAN Port 2. Multiple commands per downlink are possible by concatenating them. @@ -310,6 +319,10 @@ Note: all settings are stored in NVRAM and will be reloaded when device starts. Device answers with it's current status on Port 4. +0x85 get BME680 sensor data + + Device answers with BME680 sensor data set on Port 7. + # License diff --git a/include/bme680read.h b/include/bme680read.h index 04f506fc..057cb40d 100644 --- a/include/bme680read.h +++ b/include/bme680read.h @@ -2,17 +2,15 @@ #define _HAS_BME #include "globals.h" - #include -#include #include #include "Adafruit_BME680.h" -extern Adafruit_BME680 bme; // Make TinyGPS++ instance globally availabe +extern Adafruit_BME680 bme; // Make bme instance globally availabe extern bmeStatus_t bme_status; // Make struct for storing gps data globally available -extern TaskHandle_t BmeTask; -void bme_loop(void *pvParameters); +void bme_init(); +bool bme_read(); #endif \ No newline at end of file diff --git a/include/globals.h b/include/globals.h index 0966ba95..b519bb52 100644 --- a/include/globals.h +++ b/include/globals.h @@ -47,11 +47,11 @@ typedef struct { } gpsStatus_t; typedef struct { - float_t temperature; - float_t pressure; - float_t humidity; - float_t gas_resistance; - float_t altitude; + uint16_t temperature; // Temperature * 100 in degrees Centigrade + uint16_t pressure; // Barometic pressure in hecto pascals + uint8_t humidity; // Relative humidity in percent + uint32_t gas_resistance; // Resistance in Ohms + uint16_t altitude; // Altitude in meters } bmeStatus_t; // global variables diff --git a/src/bme680read.cpp b/src/bme680read.cpp index f49c11ea..aa75c162 100644 --- a/src/bme680read.cpp +++ b/src/bme680read.cpp @@ -1,64 +1,46 @@ #ifdef HAS_BME -#include "globals.h" +#include "bme680read.h" // Local logging tag static const char TAG[] = "main"; -#include -#include -#include -#include "Adafruit_BME680.h" - #define SEALEVELPRESSURE_HPA (1013.25) // I2C Bus interface Adafruit_BME680 bme; bmeStatus_t bme_status; -TaskHandle_t BmeTask; -// BME680 read loop Task -void bme_loop(void *pvParameters) { +void bme_init(void) { + // initialize BME680 sensor using default i2c address 0x77 + if (bme.begin()) { + // Set up oversampling and filter initialization + bme.setTemperatureOversampling(BME680_OS_8X); + bme.setHumidityOversampling(BME680_OS_2X); + bme.setPressureOversampling(BME680_OS_4X); + bme.setIIRFilterSize(BME680_FILTER_SIZE_3); + bme.setGasHeater(320, 150); // 320*C for 150 ms + ESP_LOGI(TAG, "BME680 chip found and initialized"); + } else + ESP_LOGE(TAG, "BME680 chip not found on i2c bus"); +} - configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check - - // initialize BME680 sensor - if (!bme.begin()) { - ESP_LOGE(TAG, "BME680 chip not found on i2c bus, bus error %d. " - "Stopping BME task."); - vTaskDelete(BmeTask); +bool bme_read(void) { + bool ret = bme.performReading(); + if (ret) { + // read current BME data and buffer in global struct + bme_status.temperature = (uint16_t)(bme.temperature * 100.0); + bme_status.pressure = (uint16_t)(bme.pressure / 100.0); + bme_status.humidity = (uint8_t)bme.humidity; + bme_status.gas_resistance = (uint16_t)(bme.gas_resistance / 1000.0); + bme_status.altitude = + (uint16_t)(bme.readAltitude(SEALEVELPRESSURE_HPA / 1000.0)); + ESP_LOGI(TAG, "BME680 sensor data read success"); } else { - ESP_LOGI(TAG, "BME680 chip found."); + ESP_LOGI(TAG, "BME680 sensor read error"); } - - // Set up oversampling and filter initialization - bme.setTemperatureOversampling(BME680_OS_8X); - bme.setHumidityOversampling(BME680_OS_2X); - bme.setPressureOversampling(BME680_OS_4X); - bme.setIIRFilterSize(BME680_FILTER_SIZE_3); - bme.setGasHeater(320, 150); // 320*C for 150 ms - - // read loop - while (1) { - - vTaskDelay(10000 / portTICK_PERIOD_MS); - - if (!bme.performReading()) { - ESP_LOGE(TAG, "BME680 read error"); - continue; - } else { - // read current BME data and buffer in global struct - bme_status.temperature = bme.temperature; - bme_status.pressure = bme.pressure / 100.0; - bme_status.humidity = bme.humidity; - bme_status.gas_resistance = bme.gas_resistance / 1000.0; - bme_status.altitude = bme.readAltitude(SEALEVELPRESSURE_HPA); - } - } // end of infinite loop - - vTaskDelete(NULL); // shoud never be reached - -} // bme_loop() + return ret; +} #endif // HAS_BME \ No newline at end of file diff --git a/src/cyclic.cpp b/src/cyclic.cpp index b95f176d..99329040 100644 --- a/src/cyclic.cpp +++ b/src/cyclic.cpp @@ -32,6 +32,11 @@ void doHousekeeping() { } #endif +#ifdef HAS_BME + // read BME280 sensor if present + bme_read(); +#endif + // task storage debugging // ESP_LOGD(TAG, "Wifiloop %d bytes left", uxTaskGetStackHighWaterMark(wifiSwitchTask)); diff --git a/src/hal/heltec.h b/src/hal/heltec.h index d3c54ee3..492f3425 100644 --- a/src/hal/heltec.h +++ b/src/hal/heltec.h @@ -3,6 +3,8 @@ #include +//#define HAS_BME 1 // BME680 sensor on I2C bus (SDI=21/SCL=22); comment out if not present + // Hardware related definitions for Heltec LoRa-32 Board #define HAS_LORA 1 // comment out if device shall not send data via LoRa #define CFG_sx1276_radio 1 diff --git a/src/hal/ttgov21new.h b/src/hal/ttgov21new.h index 6ef93285..bc41184a 100644 --- a/src/hal/ttgov21new.h +++ b/src/hal/ttgov21new.h @@ -8,6 +8,8 @@ // This settings are for boards labeled v1.6 on pcb, NOT for v1.5 or older */ +//#define HAS_BME 1 // BME680 sensor on I2C bus (SDI=21/SCL=22); comment out if not present + #define HAS_LORA 1 // comment out if device shall not send data via LoRa #define CFG_sx1276_radio 1 // HPD13A LoRa SoC diff --git a/src/lorawan.cpp b/src/lorawan.cpp index f1787c66..5159531c 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -422,14 +422,14 @@ void user_request_network_time_callback(void *pVoidUserUTCTime, lmic_time_reference_t lmicTimeReference; if (flagSuccess != 1) { - ESP_LOGW(TAG, "Network time request callback error"); + ESP_LOGW(TAG, "LoRaWAN network did not answer time request"); return; } // Populate lmic_time_reference flagSuccess = LMIC_getNetworkTimeReference(&lmicTimeReference); if (flagSuccess != 1) { - ESP_LOGW(TAG, "Network time request failed"); + ESP_LOGW(TAG, "LoRaWAN time request failed"); return; } diff --git a/src/main.cpp b/src/main.cpp index 92abe5bc..0fed89ec 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,7 +35,6 @@ IDLE 0 0 ESP32 arduino scheduler -> runs wifi sniffer looptask 1 1 arduino core -> runs the LMIC LoRa stack irqhandler 1 1 executes tasks triggered by irq gpsloop 1 2 reads data from GPS over serial or i2c -bmeloop 1 2 reads data from BME680 over i2c IDLE 1 0 ESP32 arduino scheduler ESP32 hardware timers @@ -56,7 +55,8 @@ uint8_t volatile channel = 0; // channel rotation counter uint16_t volatile macs_total = 0, macs_wifi = 0, macs_ble = 0, batt_voltage = 0; // globals for display -hw_timer_t *channelSwitch = NULL, *sendCycle = NULL, *homeCycle = NULL, *displaytimer = NULL; // irq tasks +hw_timer_t *channelSwitch = NULL, *sendCycle = NULL, *homeCycle = NULL, + *displaytimer = NULL; // irq tasks TaskHandle_t irqHandlerTask, wifiSwitchTask; std::set macs; // container holding unique MAC adress hashes @@ -161,6 +161,7 @@ void setup() { // initialize gps #ifdef HAS_BME strcat_P(features, " BME"); + bme_init(); #endif // initialize LoRa @@ -281,17 +282,6 @@ void setup() { 1); // CPU core #endif -#ifdef HAS_BME - ESP_LOGI(TAG, "Starting BMEloop..."); - xTaskCreatePinnedToCore(bme_loop, // task function - "bmeloop", // name of task - 2048, // stack size of task - (void *)1, // parameter of the task - 2, // priority of the task - &BmeTask, // task handle - 1); // CPU core -#endif - // start state machine ESP_LOGI(TAG, "Starting IRQ Handler..."); xTaskCreatePinnedToCore(irqHandler, // task function diff --git a/src/paxcounter.conf b/src/paxcounter.conf index 2f27acaf..1135963d 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -59,6 +59,7 @@ #define LPP1PORT 1 // Port for Cayenne LPP 1.0 dynamic sensor encoding #define LPP2PORT 2 // Port for Cayenne LPP 2.0 packed sensor encoding #define BEACONPORT 6 // Port on which device sends beacon alarms +#define BMEPORT 7 // Port on which device sends BME680 sensor data // Some hardware settings #define RGBLUMINOSITY 30 // RGB LED luminosity [default = 30%] diff --git a/src/payload.cpp b/src/payload.cpp index 56c87fce..d328f975 100644 --- a/src/payload.cpp +++ b/src/payload.cpp @@ -95,11 +95,15 @@ void PayloadConvert::addGPS(gpsStatus_t value) { void PayloadConvert::addBME(bmeStatus_t value) { #ifdef HAS_BME - buffer[cursor++] = (byte)(value.temperature); - buffer[cursor++] = (byte)(value.pressure); + buffer[cursor++] = highByte(value.temperature); + buffer[cursor++] = lowByte(value.temperature); + buffer[cursor++] = highByte(value.pressure); + buffer[cursor++] = lowByte(value.pressure); buffer[cursor++] = (byte)(value.humidity); - buffer[cursor++] = (byte)(value.gas_resistance); - buffer[cursor++] = (byte)(value.altitude); + buffer[cursor++] = highByte(value.gas_resistance); + buffer[cursor++] = lowByte(value.gas_resistance); + buffer[cursor++] = highByte(value.altitude); + buffer[cursor++] = lowByte(value.altitude); #endif } @@ -162,11 +166,11 @@ void PayloadConvert::addGPS(gpsStatus_t value) { void PayloadConvert::addBME(bmeStatus_t value) { #ifdef HAS_BME - writeUint8((byte)value.temperature); - writeUint8((byte)value.pressure); - writeUint8((byte)value.humidity); - writeUint8((byte)value.gas_resistance); - writeUint8((byte)value.altitude); + writeUint16(value.temperature); + writeUint16(value.pressure); + writeUint8(value.humidity); + writeUint16(value.gas_resistance); + writeUint16(value.altitude); #endif } diff --git a/src/rcommand.cpp b/src/rcommand.cpp index ffba3ff0..dc525f44 100644 --- a/src/rcommand.cpp +++ b/src/rcommand.cpp @@ -240,6 +240,17 @@ void get_gps(uint8_t val[]) { #endif }; +void get_bme(uint8_t val[]) { + ESP_LOGI(TAG, "Remote command: get bme680 sensor data"); +#ifdef HAS_BME + payload.reset(); + payload.addBME(bme_status); + SendData(BMEPORT); +#else + ESP_LOGW(TAG, "BME680 sensor not supported"); +#endif +}; + // assign previously defined functions to set of numeric remote commands // format: opcode, function, #bytes params, // flag (true = do make settings persistent / false = don't) @@ -255,7 +266,8 @@ cmd_t table[] = { {0x0f, set_wifiant, 1, true}, {0x10, set_rgblum, 1, true}, {0x11, set_monitor, 1, true}, {0x12, set_beacon, 7, false}, {0x80, get_config, 0, false}, {0x81, get_status, 0, false}, - {0x84, get_gps, 0, false}}; + {0x84, get_gps, 0, false}, {0x85, get_bme, 0, false}, +}; const uint8_t cmdtablesize = sizeof(table) / sizeof(table[0]); // number of commands in command table