Add support for the BME680 sensor
This commit is contained in:
parent
782692eaa3
commit
f38e6fe6ae
|
@ -7,20 +7,27 @@
|
|||
<script type="text/javascript">
|
||||
function updateSensorTable(sensordata)
|
||||
{
|
||||
elements = ['temperature', 'humidity', 'co2'];
|
||||
scd30_elements = ['temperature', 'humidity', 'co2'];
|
||||
|
||||
|
||||
elements.forEach(function(item, index) {
|
||||
scd30_elements.forEach(function(item, index) {
|
||||
elem = document.getElementById('scd30_' + item);
|
||||
val = sensordata['scd30'][item];
|
||||
elem.textContent = val.toFixed(2);
|
||||
});
|
||||
|
||||
bme680_elements = ['temperature', 'humidity', 'pressure', 'gas_resistance'];
|
||||
|
||||
bme680_elements.forEach(function(item, index) {
|
||||
elem = document.getElementById('bme680_' + item);
|
||||
val = sensordata['bme680'][item];
|
||||
elem.textContent = val.toFixed(2);
|
||||
});
|
||||
}
|
||||
|
||||
function setup()
|
||||
{
|
||||
getSensorData(updateSensorTable);
|
||||
setInterval(function() { getSensorData(updateSensorTable) }, 60000);
|
||||
setInterval(function() { getSensorData(updateSensorTable) }, 30000);
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
|
@ -43,24 +50,40 @@
|
|||
<table>
|
||||
<tr>
|
||||
<th>Sensor</th>
|
||||
<th>Messwert</th>
|
||||
<th>SCD30</th>
|
||||
<th>BME680</th>
|
||||
<th>Einheit</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SCD30 CO₂</td>
|
||||
<td class="value" id="scd30_co2">----,--</td>
|
||||
<td>CO₂</td>
|
||||
<td class="value" id="scd30_co2">---,--</td>
|
||||
<td class="value" id="bme680_co2">---,--</td>
|
||||
<td>ppm</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SCD30 Temperatur</td>
|
||||
<td>Temperatur</td>
|
||||
<td class="value" id="scd30_temperature">-,--</td>
|
||||
<td class="value" id="bme680_temperature">-,--</td>
|
||||
<td>°C</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SCD30 Luftfeuchtigkeit</td>
|
||||
<td class="value" id="scd30_humidity">-,--</td>
|
||||
<td>Luftfeuchtigkeit</td>
|
||||
<td class="value" id="scd30_humidity">--,--</td>
|
||||
<td class="value" id="bme680_humidity">--,--</td>
|
||||
<td>%rH</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Luftdruck</td>
|
||||
<td class="value" id="scd30_pressure">---,--</td>
|
||||
<td class="value" id="bme680_pressure">---,--</td>
|
||||
<td>hPa</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Gaswiderstand</td>
|
||||
<td class="value" id="scd30_gas_resistance">---,--</td>
|
||||
<td class="value" id="bme680_gas_resistance">---,--</td>
|
||||
<td>kΩ</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <Adafruit_SCD30.h>
|
||||
#include <Adafruit_BME680.h>
|
||||
|
||||
#include <HTTPRequest.hpp>
|
||||
#include <HTTPResponse.hpp>
|
||||
|
@ -12,7 +13,7 @@
|
|||
class WebServer
|
||||
{
|
||||
public:
|
||||
bool start(Adafruit_SCD30 *scd30);
|
||||
bool start(Adafruit_SCD30 *scd30, Adafruit_BME680 *bme680);
|
||||
|
||||
static WebServer &instance(void)
|
||||
{
|
||||
|
@ -24,6 +25,7 @@ class WebServer
|
|||
httpsserver::HTTPServer *m_server;
|
||||
|
||||
Adafruit_SCD30 *m_scd30;
|
||||
Adafruit_BME680 *m_bme680;
|
||||
|
||||
WebServer(void);
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ monitor_speed = 115200
|
|||
lib_deps =
|
||||
zinggjm/GxEPD2@^1.5.7
|
||||
adafruit/Adafruit SCD30@^1.0.11
|
||||
adafruit/Adafruit BME680 Library@^2.0.5
|
||||
SPI
|
||||
Wire
|
||||
NTPClient
|
||||
|
|
|
@ -71,6 +71,15 @@ void WebServer::handleReadout(httpsserver::HTTPRequest *req, httpsserver::HTTPRe
|
|||
res->print(instance().m_scd30->relative_humidity);
|
||||
res->print(", \"temperature\": ");
|
||||
res->print(instance().m_scd30->temperature);
|
||||
res->print("},");
|
||||
res->print("\"bme680\": {\"pressure\": ");
|
||||
res->print(instance().m_bme680->pressure/100.0);
|
||||
res->print(", \"humidity\": ");
|
||||
res->print(instance().m_bme680->humidity);
|
||||
res->print(", \"temperature\": ");
|
||||
res->print(instance().m_bme680->temperature);
|
||||
res->print(", \"gas_resistance\": ");
|
||||
res->print(instance().m_bme680->gas_resistance / 1000.0);
|
||||
res->println("}}");
|
||||
}
|
||||
|
||||
|
@ -155,9 +164,10 @@ void WebServer::serverTask(void *arg)
|
|||
Serial.println("[server] Server died?! This should never happen.");
|
||||
}
|
||||
|
||||
bool WebServer::start(Adafruit_SCD30 *scd30)
|
||||
bool WebServer::start(Adafruit_SCD30 *scd30, Adafruit_BME680 *bme680)
|
||||
{
|
||||
m_scd30 = scd30;
|
||||
m_bme680 = bme680;
|
||||
|
||||
xTaskCreatePinnedToCore(
|
||||
WebServer::serverTask, /* Task function. */
|
||||
|
|
135
src/main.cpp
135
src/main.cpp
|
@ -1,5 +1,6 @@
|
|||
#include <Arduino.h>
|
||||
#include <Adafruit_SCD30.h>
|
||||
#include <Adafruit_BME680.h>
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <WiFiMulti.h>
|
||||
|
@ -19,8 +20,10 @@
|
|||
#include <epaper.h>
|
||||
|
||||
Adafruit_SCD30 scd30;
|
||||
Adafruit_BME680 bme680;
|
||||
|
||||
static timeseries_t ts_scd30_co2, ts_scd30_temperature, ts_scd30_humidity;
|
||||
static timeseries_t ts_bme680_temperature, ts_bme680_humidity, ts_bme680_pressure, ts_bme680_gas_resistance;
|
||||
|
||||
static WiFiMulti wiFiMulti;
|
||||
static bool wiFiConnectedToStation;
|
||||
|
@ -94,6 +97,10 @@ void initSCD30(void)
|
|||
timeseries_init(&ts_scd30_co2, timeClient.getEpochTime(), 15, "ppm", "%.1f");
|
||||
timeseries_init(&ts_scd30_temperature, timeClient.getEpochTime(), 15, "°C", "%.1f");
|
||||
timeseries_init(&ts_scd30_humidity, timeClient.getEpochTime(), 15, "%", "%.1f");
|
||||
timeseries_init(&ts_bme680_temperature, timeClient.getEpochTime(), 15, "°C", "%.1f");
|
||||
timeseries_init(&ts_bme680_humidity, timeClient.getEpochTime(), 15, "%", "%.1f");
|
||||
timeseries_init(&ts_bme680_pressure, timeClient.getEpochTime(), 15, "hPa", "%.1f");
|
||||
timeseries_init(&ts_bme680_gas_resistance, timeClient.getEpochTime(), 15, "kOhm", "%.1f");
|
||||
|
||||
// Try to initialize!
|
||||
if (!scd30.begin()) {
|
||||
|
@ -102,8 +109,7 @@ void initSCD30(void)
|
|||
}
|
||||
Serial.println("scd30: SCD30 Found!");
|
||||
|
||||
// TODO: check what this actually resets. Maybe also the calibration?
|
||||
scd30.reset();
|
||||
scd30.reset(); // note: does not reset the calibration
|
||||
|
||||
if (!scd30.setMeasurementInterval(15)){ // seconds
|
||||
Serial.println("scd30: Failed to set measurement interval");
|
||||
|
@ -145,6 +151,24 @@ void initSCD30(void)
|
|||
}
|
||||
|
||||
|
||||
static void initBME680(void)
|
||||
{
|
||||
if (!bme680.begin()) {
|
||||
Serial.println(F("Could not find a valid BME680 sensor, check wiring!"));
|
||||
while (1) {
|
||||
delay(10);
|
||||
}
|
||||
}
|
||||
|
||||
// Set up oversampling and filter initialization
|
||||
bme680.setTemperatureOversampling(BME680_OS_8X);
|
||||
bme680.setHumidityOversampling(BME680_OS_2X);
|
||||
bme680.setPressureOversampling(BME680_OS_4X);
|
||||
bme680.setIIRFilterSize(BME680_FILTER_SIZE_3);
|
||||
bme680.setGasHeater(320, 150); // 320*C for 150 ms
|
||||
}
|
||||
|
||||
|
||||
static void draw_epaper_initial_callback(GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> *display)
|
||||
{
|
||||
display->setRotation(1);
|
||||
|
@ -212,16 +236,19 @@ void setup(void)
|
|||
wifi_setup();
|
||||
|
||||
initSCD30();
|
||||
initBME680();
|
||||
epaper_init();
|
||||
|
||||
epaper_draw_and_hibernate(draw_epaper_initial_callback, false);
|
||||
|
||||
WebServer::instance().start(&scd30);
|
||||
WebServer::instance().start(&scd30, &bme680);
|
||||
}
|
||||
|
||||
|
||||
static void draw_epaper_callback(GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> *display)
|
||||
{
|
||||
const int16_t line_height = 75;
|
||||
|
||||
display->setRotation(1);
|
||||
display->setTextColor(GxEPD_BLACK);
|
||||
|
||||
|
@ -248,10 +275,10 @@ static void draw_epaper_callback(GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_H
|
|||
display->setFont(&FreeSans12pt7b);
|
||||
display->print(" ppm");
|
||||
|
||||
epaper_plot(150, 5, 150, 65, &ts_scd30_co2, 900);
|
||||
epaper_plot(150, 0*line_height + 5, 150, 65, &ts_scd30_co2, 900);
|
||||
|
||||
// second line: temperature
|
||||
y = 75 + FreeSans12pt7b.yAdvance*3/4;
|
||||
y = 1*line_height + FreeSans12pt7b.yAdvance*3/4;
|
||||
display->setCursor(0, y);
|
||||
|
||||
display->setFont(&FreeSans12pt7b);
|
||||
|
@ -261,7 +288,7 @@ static void draw_epaper_callback(GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_H
|
|||
display->setCursor(0, y);
|
||||
|
||||
display->setFont(&FreeSansBold12pt7b);
|
||||
display->print(scd30.temperature, 2);
|
||||
display->print(bme680.temperature, 2);
|
||||
|
||||
display->setFont(&FreeSans12pt7b);
|
||||
display->print(" ");
|
||||
|
@ -277,10 +304,10 @@ static void draw_epaper_callback(GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_H
|
|||
display->setCursor(cursor_x, stored_baseline_y);
|
||||
display->print("C");
|
||||
|
||||
epaper_plot(150, 80, 150, 65, &ts_scd30_temperature, 900);
|
||||
epaper_plot(150, 1*line_height + 5, 150, 65, &ts_bme680_temperature, 900);
|
||||
|
||||
// second line: Humidity
|
||||
y = 150 + FreeSans12pt7b.yAdvance*3/4;
|
||||
// third line: Humidity
|
||||
y = 2*line_height + FreeSans12pt7b.yAdvance*3/4;
|
||||
display->setCursor(0, y);
|
||||
|
||||
display->setFont(&FreeSans12pt7b);
|
||||
|
@ -290,21 +317,57 @@ static void draw_epaper_callback(GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_H
|
|||
display->setCursor(0, y);
|
||||
|
||||
display->setFont(&FreeSansBold12pt7b);
|
||||
display->print(scd30.relative_humidity, 1);
|
||||
display->print(bme680.humidity, 1);
|
||||
|
||||
display->setFont(&FreeSans12pt7b);
|
||||
display->print(" %rH");
|
||||
|
||||
epaper_plot(150, 155, 150, 65, &ts_scd30_humidity, 900);
|
||||
epaper_plot(150, 2*line_height + 5, 150, 65, &ts_bme680_humidity, 900);
|
||||
|
||||
y = 225 + FreeSans12pt7b.yAdvance*3/4;
|
||||
// fourth line: Pressure
|
||||
y = 3*line_height + FreeSans12pt7b.yAdvance*3/4;
|
||||
display->setCursor(0, y);
|
||||
|
||||
display->setFont(&FreeSans12pt7b);
|
||||
display->print("Druck: ");
|
||||
|
||||
y += FreeSans12pt7b.yAdvance;
|
||||
display->setCursor(0, y);
|
||||
|
||||
display->setFont(&FreeSansBold12pt7b);
|
||||
display->print(bme680.pressure / 100.0, 1);
|
||||
|
||||
display->setFont(&FreeSans12pt7b);
|
||||
display->print(" hPa");
|
||||
|
||||
epaper_plot(150, 3*line_height + 5, 150, 65, &ts_bme680_pressure, 900);
|
||||
|
||||
// fifth line: Gas resistance
|
||||
y = 4*line_height + FreeSans12pt7b.yAdvance*3/4;
|
||||
display->setCursor(0, y);
|
||||
|
||||
display->setFont(&FreeSans12pt7b);
|
||||
display->print("Gas: ");
|
||||
|
||||
y += FreeSans12pt7b.yAdvance;
|
||||
display->setCursor(0, y);
|
||||
|
||||
display->setFont(&FreeSansBold12pt7b);
|
||||
display->print(bme680.gas_resistance * 1e-3, 2);
|
||||
|
||||
display->setFont(&FreeSans12pt7b);
|
||||
display->print(" kOhm");
|
||||
|
||||
epaper_plot(150, 4*line_height + 5, 150, 65, &ts_bme680_gas_resistance, 900);
|
||||
|
||||
y = 5*line_height + FreeSans12pt7b.yAdvance*3/4;
|
||||
display->setCursor(0, y);
|
||||
|
||||
display->setFont(&FreeSans12pt7b);
|
||||
display->print("Aktualisiert: ");
|
||||
|
||||
y += FreeSans12pt7b.yAdvance;
|
||||
display->setCursor(0, y);
|
||||
//y += FreeSans12pt7b.yAdvance;
|
||||
//display->setCursor(0, y);
|
||||
|
||||
display->setFont(&FreeSansBold12pt7b);
|
||||
display->print(timeClient.getFormattedTime());
|
||||
|
@ -318,7 +381,12 @@ static void upload_data(void)
|
|||
String json_string = String("{"
|
||||
"\"scd30_co2\":") + scd30.CO2
|
||||
+ ", \"scd30_temperature\":" + scd30.temperature
|
||||
+ ", \"scd30_humidity\":" + scd30.relative_humidity + "}";
|
||||
+ ", \"scd30_humidity\":" + scd30.relative_humidity
|
||||
+ ", \"bme680_temperature\":" + bme680.temperature
|
||||
+ ", \"bme680_humidity\":" + bme680.humidity
|
||||
+ ", \"bme680_pressure\":" + bme680.pressure
|
||||
+ ", \"bme680_gas_resistance\":" + bme680.gas_resistance
|
||||
+ "}";
|
||||
|
||||
// send the data to graphite
|
||||
HTTPClient client;
|
||||
|
@ -364,6 +432,32 @@ void loop(void)
|
|||
first_scd30_readout = false;
|
||||
}
|
||||
|
||||
// read synchronously from the bme680. This takes some time (100s of
|
||||
// milliseconds), but the SCD30 is running autonomously, so this does not
|
||||
// disturb that measurement.
|
||||
if(bme680.performReading()) {
|
||||
timeseries_append(&ts_bme680_temperature, bme680.temperature);
|
||||
timeseries_append(&ts_bme680_humidity, bme680.humidity);
|
||||
timeseries_append(&ts_bme680_pressure, bme680.pressure / 100.0);
|
||||
timeseries_append(&ts_bme680_gas_resistance, bme680.gas_resistance / 1000.0);
|
||||
|
||||
Serial.println("BME680:");
|
||||
Serial.print("Temperature: ");
|
||||
Serial.print(bme680.temperature, 3);
|
||||
Serial.println(" °C");
|
||||
Serial.print("Rel. humidity: ");
|
||||
Serial.print(bme680.humidity, 2);
|
||||
Serial.println(" %");
|
||||
Serial.print("Pressure: ");
|
||||
Serial.print(bme680.pressure / 100.0, 2);
|
||||
Serial.println(" hPa");
|
||||
Serial.print("Gas resistance: ");
|
||||
Serial.print(bme680.gas_resistance);
|
||||
Serial.println(" Ohm");
|
||||
Serial.println("");
|
||||
}
|
||||
|
||||
Serial.println("SCD30:");
|
||||
Serial.print("CO2: ");
|
||||
Serial.print(scd30.CO2, 3);
|
||||
Serial.println(" ppm");
|
||||
|
@ -403,9 +497,14 @@ void loop(void)
|
|||
epaper_draw_and_hibernate(draw_epaper_callback, false);
|
||||
Serial.println("Display updated.");
|
||||
|
||||
timeseries_prune(&ts_scd30_humidity, 3600); // keep the last hour
|
||||
timeseries_prune(&ts_scd30_temperature, 3600); // keep the last hour
|
||||
timeseries_prune(&ts_scd30_co2, 3600); // keep the last hour
|
||||
// keep the last hour
|
||||
timeseries_prune(&ts_scd30_humidity, 3600);
|
||||
timeseries_prune(&ts_scd30_temperature, 3600);
|
||||
timeseries_prune(&ts_scd30_co2, 3600);
|
||||
timeseries_prune(&ts_bme680_temperature, 3600);
|
||||
timeseries_prune(&ts_bme680_humidity, 3600);
|
||||
timeseries_prune(&ts_bme680_pressure, 3600);
|
||||
timeseries_prune(&ts_bme680_gas_resistance, 3600);
|
||||
}
|
||||
|
||||
delay(1000);
|
||||
|
|
Loading…
Reference in a new issue