Files
WxBox/src/main.cpp
2024-04-13 01:03:37 +03:00

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