BME680 support (experimental)
This commit is contained in:
		
							parent
							
								
									889ffe3a51
								
							
						
					
					
						commit
						2b96f6e0bf
					
				
							
								
								
									
										13
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								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).<br> | ||||
| 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.<br> | ||||
| @ -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 | ||||
| 
 | ||||
|  | ||||
| @ -2,17 +2,15 @@ | ||||
| #define _HAS_BME | ||||
| 
 | ||||
| #include "globals.h" | ||||
| 
 | ||||
| #include <Wire.h> | ||||
| #include <SPI.h> | ||||
| #include <Adafruit_Sensor.h> | ||||
| #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 | ||||
| @ -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
 | ||||
|  | ||||
| @ -1,64 +1,46 @@ | ||||
| #ifdef HAS_BME | ||||
| 
 | ||||
| #include "globals.h" | ||||
| #include "bme680read.h" | ||||
| 
 | ||||
| // Local logging tag
 | ||||
| static const char TAG[] = "main"; | ||||
| 
 | ||||
| #include <Wire.h> | ||||
| #include <SPI.h> | ||||
| #include <Adafruit_Sensor.h> | ||||
| #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
 | ||||
| @ -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)); | ||||
|  | ||||
| @ -3,6 +3,8 @@ | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| //#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 | ||||
|  | ||||
| @ -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
 | ||||
| 
 | ||||
|  | ||||
| @ -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; | ||||
|   } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										16
									
								
								src/main.cpp
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								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<uint16_t> 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
 | ||||
|  | ||||
| @ -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%] | ||||
|  | ||||
| @ -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 | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -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
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user