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
|
- Silicon unique ID
|
||||||
- Battery voltage monitoring
|
- Battery voltage monitoring
|
||||||
- GPS (Generic serial NMEA, or Quectel L76 I2C)
|
- 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>
|
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>
|
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 1: Beacon RSSI reception level
|
||||||
byte 2: Beacon identifier (0..255)
|
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
|
# Remote control
|
||||||
|
|
||||||
The device listenes for remote control commands on LoRaWAN Port 2. Multiple commands per downlink are possible by concatenating them.
|
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.
|
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
|
# License
|
||||||
|
|
||||||
|
@ -2,17 +2,15 @@
|
|||||||
#define _HAS_BME
|
#define _HAS_BME
|
||||||
|
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
|
|
||||||
#include <Wire.h>
|
#include <Wire.h>
|
||||||
#include <SPI.h>
|
|
||||||
#include <Adafruit_Sensor.h>
|
#include <Adafruit_Sensor.h>
|
||||||
#include "Adafruit_BME680.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
|
extern bmeStatus_t
|
||||||
bme_status; // Make struct for storing gps data globally available
|
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
|
#endif
|
@ -47,11 +47,11 @@ typedef struct {
|
|||||||
} gpsStatus_t;
|
} gpsStatus_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
float_t temperature;
|
uint16_t temperature; // Temperature * 100 in degrees Centigrade
|
||||||
float_t pressure;
|
uint16_t pressure; // Barometic pressure in hecto pascals
|
||||||
float_t humidity;
|
uint8_t humidity; // Relative humidity in percent
|
||||||
float_t gas_resistance;
|
uint32_t gas_resistance; // Resistance in Ohms
|
||||||
float_t altitude;
|
uint16_t altitude; // Altitude in meters
|
||||||
} bmeStatus_t;
|
} bmeStatus_t;
|
||||||
|
|
||||||
// global variables
|
// global variables
|
||||||
|
@ -1,64 +1,46 @@
|
|||||||
#ifdef HAS_BME
|
#ifdef HAS_BME
|
||||||
|
|
||||||
#include "globals.h"
|
#include "bme680read.h"
|
||||||
|
|
||||||
// Local logging tag
|
// Local logging tag
|
||||||
static const char TAG[] = "main";
|
static const char TAG[] = "main";
|
||||||
|
|
||||||
#include <Wire.h>
|
|
||||||
#include <SPI.h>
|
|
||||||
#include <Adafruit_Sensor.h>
|
|
||||||
#include "Adafruit_BME680.h"
|
|
||||||
|
|
||||||
#define SEALEVELPRESSURE_HPA (1013.25)
|
#define SEALEVELPRESSURE_HPA (1013.25)
|
||||||
|
|
||||||
// I2C Bus interface
|
// I2C Bus interface
|
||||||
Adafruit_BME680 bme;
|
Adafruit_BME680 bme;
|
||||||
|
|
||||||
bmeStatus_t bme_status;
|
bmeStatus_t bme_status;
|
||||||
TaskHandle_t BmeTask;
|
|
||||||
|
|
||||||
// BME680 read loop Task
|
void bme_init(void) {
|
||||||
void bme_loop(void *pvParameters) {
|
// 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
|
bool bme_read(void) {
|
||||||
|
bool ret = bme.performReading();
|
||||||
// initialize BME680 sensor
|
if (ret) {
|
||||||
if (!bme.begin()) {
|
// read current BME data and buffer in global struct
|
||||||
ESP_LOGE(TAG, "BME680 chip not found on i2c bus, bus error %d. "
|
bme_status.temperature = (uint16_t)(bme.temperature * 100.0);
|
||||||
"Stopping BME task.");
|
bme_status.pressure = (uint16_t)(bme.pressure / 100.0);
|
||||||
vTaskDelete(BmeTask);
|
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 {
|
} else {
|
||||||
ESP_LOGI(TAG, "BME680 chip found.");
|
ESP_LOGI(TAG, "BME680 sensor read error");
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
// 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()
|
|
||||||
|
|
||||||
#endif // HAS_BME
|
#endif // HAS_BME
|
@ -32,6 +32,11 @@ void doHousekeeping() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAS_BME
|
||||||
|
// read BME280 sensor if present
|
||||||
|
bme_read();
|
||||||
|
#endif
|
||||||
|
|
||||||
// task storage debugging //
|
// task storage debugging //
|
||||||
ESP_LOGD(TAG, "Wifiloop %d bytes left",
|
ESP_LOGD(TAG, "Wifiloop %d bytes left",
|
||||||
uxTaskGetStackHighWaterMark(wifiSwitchTask));
|
uxTaskGetStackHighWaterMark(wifiSwitchTask));
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#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
|
// Hardware related definitions for Heltec LoRa-32 Board
|
||||||
#define HAS_LORA 1 // comment out if device shall not send data via LoRa
|
#define HAS_LORA 1 // comment out if device shall not send data via LoRa
|
||||||
#define CFG_sx1276_radio 1
|
#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
|
// 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 HAS_LORA 1 // comment out if device shall not send data via LoRa
|
||||||
#define CFG_sx1276_radio 1 // HPD13A LoRa SoC
|
#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;
|
lmic_time_reference_t lmicTimeReference;
|
||||||
|
|
||||||
if (flagSuccess != 1) {
|
if (flagSuccess != 1) {
|
||||||
ESP_LOGW(TAG, "Network time request callback error");
|
ESP_LOGW(TAG, "LoRaWAN network did not answer time request");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Populate lmic_time_reference
|
// Populate lmic_time_reference
|
||||||
flagSuccess = LMIC_getNetworkTimeReference(&lmicTimeReference);
|
flagSuccess = LMIC_getNetworkTimeReference(&lmicTimeReference);
|
||||||
if (flagSuccess != 1) {
|
if (flagSuccess != 1) {
|
||||||
ESP_LOGW(TAG, "Network time request failed");
|
ESP_LOGW(TAG, "LoRaWAN time request failed");
|
||||||
return;
|
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
|
looptask 1 1 arduino core -> runs the LMIC LoRa stack
|
||||||
irqhandler 1 1 executes tasks triggered by irq
|
irqhandler 1 1 executes tasks triggered by irq
|
||||||
gpsloop 1 2 reads data from GPS over serial or i2c
|
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
|
IDLE 1 0 ESP32 arduino scheduler
|
||||||
|
|
||||||
ESP32 hardware timers
|
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,
|
uint16_t volatile macs_total = 0, macs_wifi = 0, macs_ble = 0,
|
||||||
batt_voltage = 0; // globals for display
|
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;
|
TaskHandle_t irqHandlerTask, wifiSwitchTask;
|
||||||
|
|
||||||
std::set<uint16_t> macs; // container holding unique MAC adress hashes
|
std::set<uint16_t> macs; // container holding unique MAC adress hashes
|
||||||
@ -161,6 +161,7 @@ void setup() {
|
|||||||
// initialize gps
|
// initialize gps
|
||||||
#ifdef HAS_BME
|
#ifdef HAS_BME
|
||||||
strcat_P(features, " BME");
|
strcat_P(features, " BME");
|
||||||
|
bme_init();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// initialize LoRa
|
// initialize LoRa
|
||||||
@ -281,17 +282,6 @@ void setup() {
|
|||||||
1); // CPU core
|
1); // CPU core
|
||||||
#endif
|
#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
|
// start state machine
|
||||||
ESP_LOGI(TAG, "Starting IRQ Handler...");
|
ESP_LOGI(TAG, "Starting IRQ Handler...");
|
||||||
xTaskCreatePinnedToCore(irqHandler, // task function
|
xTaskCreatePinnedToCore(irqHandler, // task function
|
||||||
|
@ -59,6 +59,7 @@
|
|||||||
#define LPP1PORT 1 // Port for Cayenne LPP 1.0 dynamic sensor encoding
|
#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 LPP2PORT 2 // Port for Cayenne LPP 2.0 packed sensor encoding
|
||||||
#define BEACONPORT 6 // Port on which device sends beacon alarms
|
#define BEACONPORT 6 // Port on which device sends beacon alarms
|
||||||
|
#define BMEPORT 7 // Port on which device sends BME680 sensor data
|
||||||
|
|
||||||
// Some hardware settings
|
// Some hardware settings
|
||||||
#define RGBLUMINOSITY 30 // RGB LED luminosity [default = 30%]
|
#define RGBLUMINOSITY 30 // RGB LED luminosity [default = 30%]
|
||||||
|
@ -95,11 +95,15 @@ void PayloadConvert::addGPS(gpsStatus_t value) {
|
|||||||
|
|
||||||
void PayloadConvert::addBME(bmeStatus_t value) {
|
void PayloadConvert::addBME(bmeStatus_t value) {
|
||||||
#ifdef HAS_BME
|
#ifdef HAS_BME
|
||||||
buffer[cursor++] = (byte)(value.temperature);
|
buffer[cursor++] = highByte(value.temperature);
|
||||||
buffer[cursor++] = (byte)(value.pressure);
|
buffer[cursor++] = lowByte(value.temperature);
|
||||||
|
buffer[cursor++] = highByte(value.pressure);
|
||||||
|
buffer[cursor++] = lowByte(value.pressure);
|
||||||
buffer[cursor++] = (byte)(value.humidity);
|
buffer[cursor++] = (byte)(value.humidity);
|
||||||
buffer[cursor++] = (byte)(value.gas_resistance);
|
buffer[cursor++] = highByte(value.gas_resistance);
|
||||||
buffer[cursor++] = (byte)(value.altitude);
|
buffer[cursor++] = lowByte(value.gas_resistance);
|
||||||
|
buffer[cursor++] = highByte(value.altitude);
|
||||||
|
buffer[cursor++] = lowByte(value.altitude);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,11 +166,11 @@ void PayloadConvert::addGPS(gpsStatus_t value) {
|
|||||||
|
|
||||||
void PayloadConvert::addBME(bmeStatus_t value) {
|
void PayloadConvert::addBME(bmeStatus_t value) {
|
||||||
#ifdef HAS_BME
|
#ifdef HAS_BME
|
||||||
writeUint8((byte)value.temperature);
|
writeUint16(value.temperature);
|
||||||
writeUint8((byte)value.pressure);
|
writeUint16(value.pressure);
|
||||||
writeUint8((byte)value.humidity);
|
writeUint8(value.humidity);
|
||||||
writeUint8((byte)value.gas_resistance);
|
writeUint16(value.gas_resistance);
|
||||||
writeUint8((byte)value.altitude);
|
writeUint16(value.altitude);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,6 +240,17 @@ void get_gps(uint8_t val[]) {
|
|||||||
#endif
|
#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
|
// assign previously defined functions to set of numeric remote commands
|
||||||
// format: opcode, function, #bytes params,
|
// format: opcode, function, #bytes params,
|
||||||
// flag (true = do make settings persistent / false = don't)
|
// 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},
|
{0x0f, set_wifiant, 1, true}, {0x10, set_rgblum, 1, true},
|
||||||
{0x11, set_monitor, 1, true}, {0x12, set_beacon, 7, false},
|
{0x11, set_monitor, 1, true}, {0x12, set_beacon, 7, false},
|
||||||
{0x80, get_config, 0, false}, {0x81, get_status, 0, 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 =
|
const uint8_t cmdtablesize =
|
||||||
sizeof(table) / sizeof(table[0]); // number of commands in command table
|
sizeof(table) / sizeof(table[0]); // number of commands in command table
|
||||||
|
Loading…
Reference in New Issue
Block a user