379 lines
10 KiB
C++
379 lines
10 KiB
C++
#include "ESPAsyncWebServer.h"
|
|
#include <WiFi.h>
|
|
#include <Wire.h>
|
|
#include <time.h>
|
|
|
|
// Sensors
|
|
#include "HDC1080Sensor.h"
|
|
#include "CCS811Sensor.h"
|
|
#include "MS5611Sensor.h"
|
|
#include "BMP280Sensor.h"
|
|
|
|
//#include "src/ESPinfluxdb.h" // https://github.com/hwwong/ESP_influxdb // 14.04.2019
|
|
#include "http_static.h" // HTTP pages and JSON request templates
|
|
// ********************** Config **********************
|
|
|
|
// DeepSleep time send data every 60 seconds
|
|
const int sleepTimeS = 60;
|
|
|
|
// WiFi Config
|
|
#define WiFi_SSID "Ischtar"
|
|
#define WiFi_Password "highfive"
|
|
|
|
// NTP conf
|
|
const char* ntpServer = "pool.ntp.org";
|
|
const long gmtOffset_sec = 0;
|
|
const int daylightOffset_sec = 3600;
|
|
struct tm timeinfo;
|
|
|
|
// Create AsyncWebServer object on port 80
|
|
AsyncWebServer server(80);
|
|
|
|
// Globals for HDC1080 :: Temp/Humidity
|
|
HDC1080Sensor HDC1080_sensors;
|
|
double hdc1080_temp, hdc1080_humidity;
|
|
bool hdc1080_err;
|
|
|
|
// Globals for CCS811 :: eTVOC/eCO2
|
|
CCS811Sensor CCS811_sensors;
|
|
uint16_t ccs811_eco2, ccs811_etvoc, ccs811_errstat, ccs811_raw;
|
|
|
|
// Globals for MS5611 :: Pressure/Altitude
|
|
MS5611Sensor MS5611_sensors;
|
|
double ms5611_temp, ms5611_pressure, ms5611_altitude;
|
|
|
|
// Globals for BMP280 :: Temp/Hum/Pressure
|
|
BMP280Sensor BMP280_sensors;
|
|
float bmp280_temp, bmp280_humidity, bmp280_pressure, bmp280_altitude;
|
|
|
|
|
|
// loop cycle
|
|
#define workCycle 60 //seconds
|
|
// ******************** Config End ********************
|
|
|
|
void scanI2CDevices() {
|
|
byte error, address;
|
|
int nDevices;
|
|
|
|
Serial.println("Scanning...");
|
|
|
|
nDevices = 0;
|
|
for (address = 1; address < 127; address++) {
|
|
Wire.beginTransmission(address);
|
|
error = Wire.endTransmission();
|
|
|
|
if (error == 0) {
|
|
Serial.print("I2C device found at address 0x");
|
|
if (address < 16) {
|
|
Serial.print("0");
|
|
}
|
|
Serial.print(address, HEX);
|
|
Serial.println(" !");
|
|
|
|
nDevices++;
|
|
} else if (error == 4) {
|
|
Serial.print("Unknown error at address 0x");
|
|
if (address < 16) {
|
|
Serial.print("0");
|
|
}
|
|
Serial.println(address, HEX);
|
|
}
|
|
}
|
|
if (nDevices == 0) {
|
|
Serial.println("No I2C devices found\n");
|
|
} else {
|
|
Serial.println("done\n");
|
|
}
|
|
}
|
|
|
|
// ---------- HDC1080 ----------
|
|
String readHDC1080Temperature() {
|
|
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
|
|
if (isnan(hdc1080_temp)) {
|
|
Serial.println("Failed to read from HDC1080 sensor!");
|
|
return "--";
|
|
}
|
|
else {
|
|
return String(hdc1080_temp);
|
|
}
|
|
}
|
|
|
|
String readHDC1080Humidity() {
|
|
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
|
|
if (isnan(hdc1080_humidity)) {
|
|
Serial.println("Failed to read from HDC1080 sensor!");
|
|
return "--";
|
|
}
|
|
else {
|
|
return String(hdc1080_humidity);
|
|
}
|
|
}
|
|
// ---------- End HDC1080 ----------
|
|
// ---------- CCS11 ----------
|
|
String processCCS811Error(err_t errstat) {
|
|
if ( errstat == CCS811_ERRSTAT_OK_NODATA ) {
|
|
Serial.println("CCS811: waiting for (new) data");
|
|
return "loading";
|
|
} else if ( errstat & CCS811_ERRSTAT_I2CFAIL ) {
|
|
Serial.println("CCS811: I2C error");
|
|
return "i2c error";
|
|
} else {
|
|
// Serial.print("CCS811: errstat="); Serial.print(errstat, HEX);
|
|
// Serial.print("="); Serial.println( ccs811.errstat_str(errstat) );
|
|
return "error";
|
|
}
|
|
}
|
|
|
|
String readCCS811TVOC() {
|
|
if( ccs811_errstat==CCS811_ERRSTAT_OK ){
|
|
return String(ccs811_etvoc);
|
|
} else {
|
|
return processCCS811Error(ccs811_errstat);
|
|
}
|
|
}
|
|
String readCCS811ECO2() {
|
|
if( ccs811_errstat==CCS811_ERRSTAT_OK ){
|
|
return String(ccs811_eco2);
|
|
} else {
|
|
return processCCS811Error(ccs811_errstat);
|
|
}
|
|
}
|
|
// ---------- End CCS11 ----------
|
|
|
|
// ---------- MS5611 ----------
|
|
String readMS5611Temperature() {
|
|
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
|
|
if (isnan(ms5611_temp)) {
|
|
Serial.println("Failed to read from MS5611 sensor!");
|
|
return "--";
|
|
}
|
|
else {
|
|
return String(ms5611_temp);
|
|
}
|
|
}
|
|
|
|
String readMS5611Pressure() {
|
|
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
|
|
if (isnan(ms5611_pressure)) {
|
|
Serial.println("Failed to read from MS5611 sensor!");
|
|
return "--";
|
|
}
|
|
else {
|
|
return String(ms5611_temp);
|
|
}
|
|
}
|
|
|
|
String readMS5611Altitude() {
|
|
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
|
|
if (isnan(ms5611_altitude)) {
|
|
Serial.println("Failed to read from MS5611 sensor!");
|
|
return "--";
|
|
}
|
|
else {
|
|
return String(ms5611_altitude);
|
|
}
|
|
}
|
|
// ---------- End MS5611 ----------
|
|
// ---------- BMP280 ----------
|
|
String readBMP280Temperature() {
|
|
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
|
|
if (isnan(bmp280_temp)) {
|
|
Serial.println("Failed to read from BMP280 sensor!");
|
|
return "--";
|
|
}
|
|
else {
|
|
return String(bmp280_temp);
|
|
}
|
|
}
|
|
|
|
String readBMP280Humidity() {
|
|
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
|
|
if (isnan(bmp280_humidity)) {
|
|
Serial.println("Failed to read from BMP280 sensor!");
|
|
return "--";
|
|
}
|
|
else {
|
|
return String(bmp280_humidity);
|
|
}
|
|
}
|
|
|
|
String readBMP280Pressure() {
|
|
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
|
|
if (isnan(bmp280_pressure)) {
|
|
Serial.println("Failed to read from BMP280 sensor!");
|
|
return "--";
|
|
}
|
|
else {
|
|
return String(bmp280_pressure);
|
|
}
|
|
}
|
|
|
|
String readBMP280Altitude() {
|
|
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
|
|
if (isnan(bmp280_altitude)) {
|
|
Serial.println("Failed to read from BMP280 sensor!");
|
|
return "--";
|
|
}
|
|
else {
|
|
return String(bmp280_altitude);
|
|
}
|
|
}
|
|
// ---------- End BMP280 ----------
|
|
String formatISO8601() {
|
|
char timestamp[20]; // Buffer for timestamp
|
|
|
|
// Format the time into ISO 8601 format
|
|
strftime(timestamp, sizeof(timestamp), "%Y-%m-%dT%H:%M:%SZ", &timeinfo);
|
|
|
|
// Convert the formatted timestamp to a String object
|
|
return String(timestamp);
|
|
}
|
|
|
|
|
|
// Replaces placeholder in HTML template with real values
|
|
// SSR if you will
|
|
String processor(const String& var){
|
|
if(var == "TEMPERATURE"){
|
|
return readHDC1080Temperature();
|
|
}
|
|
else if(var == "HUMIDITY"){
|
|
return readHDC1080Humidity();
|
|
}
|
|
else if(var == "TVOC"){
|
|
return readCCS811TVOC();
|
|
}
|
|
else if(var == "ECO2"){
|
|
return readCCS811ECO2();
|
|
} else if(var == "TIMESTAMP"){
|
|
return formatISO8601();
|
|
}
|
|
return String();
|
|
}
|
|
|
|
void connectToWiFi() {
|
|
WiFi.mode(WIFI_STA);
|
|
WiFi.begin(WiFi_SSID, WiFi_Password);
|
|
|
|
Serial.println();
|
|
Serial.print("Connecting to WiFi: ");
|
|
Serial.print(WiFi_SSID);
|
|
|
|
int attempts = 0;
|
|
while (WiFi.status() != WL_CONNECTED && attempts < 10) {
|
|
delay(500);
|
|
Serial.print(".");
|
|
attempts++;
|
|
}
|
|
|
|
if (WiFi.status() == WL_CONNECTED) {
|
|
Serial.println("\nWiFi connected");
|
|
Serial.print("IP address: http://");
|
|
Serial.println(WiFi.localIP());
|
|
} else {
|
|
Serial.println("\nFailed to connect to WiFi");
|
|
// Handle connection failure, e.g., retry or reset the ESP32
|
|
}
|
|
}
|
|
|
|
void setup()
|
|
{
|
|
Serial.begin(115200);
|
|
delay(10);
|
|
Serial.println("");
|
|
|
|
connectToWiFi();
|
|
delay(10);
|
|
Serial.println("");
|
|
// Config NTP
|
|
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
|
|
|
|
// i2c
|
|
Wire.begin();
|
|
|
|
// humidity and temperature
|
|
HDC1080_sensors.init();
|
|
// eCO2 and eTVOC, temp and humidity needed to adjust values
|
|
CCS811_sensors.init(&hdc1080_temp, &hdc1080_humidity);
|
|
// Todo add pointer to temp, we might allight Altimeter by another sens
|
|
// MS5611_sensors.init();
|
|
// humidity, temperature, pressure and altitude
|
|
BMP280_sensors.init();
|
|
|
|
// Pages and JSONs
|
|
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
|
|
request->send_P(200, "text/html", http_static::index_html, processor);
|
|
});
|
|
|
|
// Deprecated
|
|
server.on("/api/sensors.json", HTTP_GET, [](AsyncWebServerRequest *request){
|
|
request->send_P(200, "text/html", http_static::sensor_things_resp, processor);
|
|
});
|
|
|
|
// DEPRECATED lightweight named endpoints
|
|
server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
|
|
request->send_P(200, "text/plain", readHDC1080Temperature().c_str());
|
|
});
|
|
server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
|
|
request->send_P(200, "text/plain", readHDC1080Humidity().c_str());
|
|
});
|
|
server.on("/tvoc", HTTP_GET, [](AsyncWebServerRequest *request){
|
|
request->send_P(200, "text/plain", readCCS811TVOC().c_str());
|
|
});
|
|
server.on("/eco2", HTTP_GET, [](AsyncWebServerRequest *request){
|
|
request->send_P(200, "text/plain", readCCS811ECO2().c_str());
|
|
});
|
|
|
|
// For prometheus scrapping. to be deprecated as well
|
|
server.on("/metrics", HTTP_GET, [](AsyncWebServerRequest *request) {
|
|
String response = "hdc1080_temperature " + String(readHDC1080Temperature()) + "\n";
|
|
response += "hdc1080_humidity " + String(readHDC1080Humidity()) + "\n";
|
|
response += "ccs811_tvoc " + String(readCCS811TVOC()) + "\n";
|
|
response += "ccs811_eco2 " + String(readCCS811ECO2()) + "\n";
|
|
response += "bmp280_temperature " + String(readBMP280Temperature()) + "\n";
|
|
response += "bmp280_humidity " + String(readBMP280Humidity()) + "\n";
|
|
response += "bmp280_pressure " + String(readBMP280Pressure()) + "\n";
|
|
response += "bmp280_altitude " + String(readBMP280Altitude()) + "\n";
|
|
request->send(200, "text/plain", response);
|
|
});
|
|
|
|
// Start server
|
|
server.begin();
|
|
}
|
|
|
|
void loop()
|
|
{
|
|
if (WiFi.status() != WL_CONNECTED) {
|
|
Serial.println("WiFi connection lost. Reconnecting...");
|
|
connectToWiFi();
|
|
}
|
|
|
|
if(!getLocalTime(&timeinfo)){
|
|
Serial.println("Failed to obtain time");
|
|
return;
|
|
}
|
|
scanI2CDevices();
|
|
Serial.print(&timeinfo, "[%M-%d-%Y--%H:%M:%S]: ");
|
|
|
|
HDC1080_sensors.read_values(&hdc1080_temp, &hdc1080_humidity, &hdc1080_err);
|
|
CCS811_sensors.read_values(&ccs811_eco2, &ccs811_etvoc, &ccs811_errstat, &ccs811_raw);
|
|
BMP280_sensors.read_values(&bmp280_temp, &bmp280_humidity, &bmp280_pressure, &bmp280_altitude);
|
|
|
|
Serial.print("T=");
|
|
Serial.print(readHDC1080Temperature());
|
|
Serial.print(" / ");
|
|
Serial.print(readBMP280Temperature());
|
|
Serial.print(" °C ");
|
|
Serial.print("H=");
|
|
Serial.print(readHDC1080Humidity());
|
|
Serial.print(" / ");
|
|
Serial.print(readBMP280Humidity());
|
|
Serial.print(" % ");
|
|
Serial.print("eco2="); Serial.print(readCCS811ECO2()); Serial.print(" ppm ");
|
|
Serial.print("etvoc="); Serial.print(readCCS811TVOC()); Serial.print(" ppb ");
|
|
Serial.print("pressure="); Serial.print(readBMP280Pressure()); Serial.print(" Pa ");
|
|
Serial.print("alt="); Serial.print(readBMP280Altitude()); Serial.print(" m ");
|
|
Serial.println("");
|
|
// Wait
|
|
delay(workCycle*1000);
|
|
}
|