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