BME680 support (experimental)

This commit is contained in:
Klaus K Wilting 2018-11-17 18:30:19 +01:00
parent 889ffe3a51
commit 2b96f6e0bf
12 changed files with 90 additions and 81 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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) {
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);
} else {
ESP_LOGI(TAG, "BME680 chip found.");
}
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
// 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);
ESP_LOGI(TAG, "BME680 chip found and initialized");
} else
ESP_LOGE(TAG, "BME680 chip not found on i2c bus");
}
} // end of infinite loop
vTaskDelete(NULL); // shoud never be reached
} // bme_loop()
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 sensor read error");
}
return ret;
}
#endif // HAS_BME

View File

@ -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));

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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%]

View File

@ -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
}

View File

@ -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