first commit

This commit is contained in:
Myk
2024-04-05 18:51:21 +03:00
commit 90fde56762
13 changed files with 735 additions and 0 deletions

10
src/http_static.cpp Normal file
View File

@@ -0,0 +1,10 @@
#include "http_static.h"
namespace http_static {
const char index_html[] PROGMEM = R"rawliteral(
#include "./static/index.html"
)rawliteral";
const char sensor_things_resp[] PROGMEM = R"rawliteral(
#include "./static/sensor_things_tmpl.json"%"
)rawliteral";
}

258
src/main.cpp Normal file
View File

@@ -0,0 +1,258 @@
/***************************************************
Wemos D1 mini or NodeMCU 1.0
VCC - 3.3V
GND - G
SCL - D1 -- GPIO 5
SDA - D2 -- GPIO 4
WAK - D3 -- GPIO 0
ESP32
VCC - 3.3V
GND - G
SCL - 19
SDA - 18
WAK - 23
****************************************************/
#include "ESPAsyncWebServer.h"
#include <WiFi.h>
#include <Wire.h>
#include "ClosedCube_HDC1080.h" // HDC1080 library - https://github.com/closedcube/ClosedCube_HDC1080_Arduino // 14.04.2019
#include "ccs811.h" // CCS811 library - https://github.com/maarten-pennings/CCS811 // 13.03.2020
#include <time.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;
//Global sensor objects
#define CCS811_WAK 23
CCS811 ccs811(CCS811_WAK);
ClosedCube_HDC1080 hdc1080;
// 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;
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
// Globals for CCS811
uint16_t eco2, etvoc, errstat, raw;
// Globals for timestamp
struct tm timeinfo;
// loop cycle
#define workCycle 60 //seconds
// ******************** Config End ********************
String readHDC1080Temperature() {
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
float t = hdc1080.readTemperature();
if (isnan(t)) {
Serial.println("Failed to read from HDC1080 sensor!");
return "--";
}
else {
return String(t);
}
}
String readHDC1080Humidity() {
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
float h = hdc1080.readHumidity();
if (isnan(h)) {
Serial.println("Failed to read from HDC1080 sensor!");
return "--";
}
else {
return String(h);
}
}
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 "<span color='red' title='" + String(ccs811.errstat_str(errstat)) + "'>CCS811 sensor error</span>";
}
}
String readCCS811TVOC() {
return String(etvoc);
}
String readCCS811ECO2() {
return String(eco2);
}
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);
// hdc1080 info
hdc1080.begin(0x40);
Serial.print("Manufacturer ID=0x");
Serial.println(hdc1080.readManufacturerId(), HEX); // 0x5449 ID of Texas Instruments
Serial.print("Device ID=0x");
Serial.println(hdc1080.readDeviceId(), HEX); // 0x1050 ID of the device
// i2c
Wire.begin();
Serial.println("CCS811 test");
// Enable CCS811
bool ok = ccs811.begin();
if ( !ok ) Serial.println("setup: CCS811 begin FAILED");
// Print CCS811 versions
Serial.print("setup: hardware version: "); Serial.println(ccs811.hardware_version(), HEX);
Serial.print("setup: bootloader version: "); Serial.println(ccs811.bootloader_version(), HEX);
Serial.print("setup: application version: "); Serial.println(ccs811.application_version(), HEX);
// Start measuring
ok = ccs811.start(CCS811_MODE_1SEC);
if ( !ok ) Serial.println("init: CCS811 start FAILED");
// Pages and JSONs
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", http_static::index_html, processor);
});
server.on("/api/sensors.json", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", http_static::sensor_things_resp, processor);
});
// 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());
});
// 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;
}
Serial.print(&timeinfo, "[%M-%d-%Y--%H:%M:%S]: ");
Serial.print("H="); Serial.print(readHDC1080Temperature()); Serial.print(" °C ");
Serial.print("T="); Serial.print(readHDC1080Temperature()); Serial.print(" % ");
// Read CCS811
ccs811.read(&eco2,&etvoc,&errstat,&raw);
// Process CCS811
if( errstat==CCS811_ERRSTAT_OK ) {
Serial.print("eco2="); Serial.print(eco2); Serial.print(" ppm ");
Serial.print("etvoc="); Serial.print(etvoc); Serial.print(" ppb ");
} else if( errstat==CCS811_ERRSTAT_OK_NODATA ) {
Serial.print("waiting for (new) data");
} else if( errstat & CCS811_ERRSTAT_I2CFAIL ) {
Serial.print("I2C error");
} else {
Serial.print( "error: " );
Serial.print( ccs811.errstat_str(errstat) );
}
Serial.println();
// Wait
delay(workCycle*1000);
}

97
src/static/index.html Normal file
View File

@@ -0,0 +1,97 @@
<!DOCTYPE HTML>
<html>
<head>
<title>ESP32 WxServer</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
<style>
html {
font-family: Arial;
display: inline-block;
margin: 0px auto;
text-align: center;
}
h2 { font-size: 3.0rem; }
p { font-size: 3.0rem; }
.units { font-size: 1.2rem; }
.sensor-lable{
font-size: 1.5rem;
vertical-align:middle;
padding-bottom: 15px;
}
</style>
</head>
<body>
<h2>ESP32 CCS881 & HDC1080 Server</h2>
<h3>Loaded: %TIMESTAMP%</h3>
<p>
<i class="fas fa-thermometer-half" style="color:#059e8a;"></i>
<span class="sensor-lable">Temperature</span>
<span id="temperature">%TEMPERATURE%</span>
<sup class="units">&deg;C</sup>
</p>
<p>
<i class="fas fa-tint" style="color:#00add6;"></i>
<span class="sensor-lable">Humidity</span>
<span id="humidity">%HUMIDITY%</span>
<sup class="units">&percnt;</sup>
</p>
<p>
<i class="fas fa-gas-pump" style="color:#6959cd;"></i>
<span class="sensor-lable">CO2 concentration</span>
<span id="eco2">%ECO2%</span>
<sup class="units">ppm</sup>
</p>
<p>
<i class="fas fa-smog" style="color:#8b008b;"></i>
<span class="sensor-lable">TVOC concentration:</span>
<span id="tvoc">%TVOC%</span>
<sup class="units">ppb</sup>
</p>
</body>
<script>
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("temperature").innerHTML = this.responseText;
}
};
xhttp.open("GET", "/temperature", true);
xhttp.send();
}, 10000 ) ;
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("tvoc").innerHTML = this.responseText;
}
};
xhttp.open("GET", "/tvoc", true);
xhttp.send();
}, 10000 ) ;
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("eco2").innerHTML = this.responseText;
}
};
xhttp.open("GET", "/eco2", true);
xhttp.send();
}, 10000 ) ;
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("humidity").innerHTML = this.responseText;
}
};
xhttp.open("GET", "/humidity", true);
xhttp.send();
}, 10000 ) ;
</script>
</html>

View File

@@ -0,0 +1,105 @@
{
"id": "urn:myweatherstation:sensor1",
"name": "WeatherStation001",
"description": "A weather station providing temperature, humidity, TVOC, and eCO2 readings",
"encodingType": "application/json",
"metadata": "https://myweatherstation.com/metadata",
"Datastreams": [
{
"id": "urn:myweatherstation:datastream:temperature",
"name": "Temperature",
"description": "Temperature readings",
"unitOfMeasurement": {
"name": "Degree Celsius",
"symbol": "°C",
"definition": "http://www.qudt.org/qudt/owl/1.0.0/unit/Instances.html#DegreeCelsius"
},
"ObservedProperty": {
"name": "Temperature",
"definition": "http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html#Temperature"
},
"Sensor": {
"name": "Temperature Sensor",
"description": "Sensor for measuring temperature"
},
"Observations": [
{
"phenomenonTime": "%TIMESTAMP%",
"result": "%TEMPERATURE%"
}
]
},
{
"id": "urn:myweatherstation:datastream:humidity",
"name": "Humidity",
"description": "Humidity readings",
"unitOfMeasurement": {
"name": "Percent",
"symbol": "%%",
"definition": "http://www.qudt.org/qudt/owl/1.0.0/unit/Instances.html#Percent"
},
"ObservedProperty": {
"name": "Relative Humidity",
"definition": "http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html#RelativeHumidity"
},
"Sensor": {
"name": "Humidity Sensor",
"description": "Sensor for measuring humidity"
},
"Observations": [
{
"phenomenonTime": "%TIMESTAMP%",
"result": "%HUMIDITY%"
}
]
},
{
"id": "urn:myweatherstation:datastream:TVOC",
"name": "TVOC",
"description": "Total Volatile Organic Compounds readings",
"unitOfMeasurement": {
"name": "Parts Per Billion",
"symbol": "ppb",
"definition": "http://www.qudt.org/qudt/owl/1.0.0/unit/Instances.html#PartsPerBillion"
},
"ObservedProperty": {
"name": "Total Volatile Organic Compounds",
"definition": "http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html#TotalVolatileOrganicCompounds"
},
"Sensor": {
"name": "TVOC Sensor",
"description": "Sensor for measuring Total Volatile Organic Compounds"
},
"Observations": [
{
"phenomenonTime": "%TIMESTAMP%",
"result": "%TVOC%"
}
]
},
{
"id": "urn:myweatherstation:datastream:eCO2",
"name": "eCO2",
"description": "Equivalent Carbon Dioxide readings",
"unitOfMeasurement": {
"name": "Parts Per Million",
"symbol": "ppm",
"definition": "http://www.qudt.org/qudt/owl/1.0.0/unit/Instances.html#PartsPerMillion"
},
"ObservedProperty": {
"name": "Equivalent Carbon Dioxide",
"definition": "http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html#CarbonDioxideConcentration"
},
"Sensor": {
"name": "eCO2 Sensor",
"description": "Sensor for measuring Equivalent Carbon Dioxide"
},
"Observations": [
{
"phenomenonTime": "%TIMESTAMP%",
"result": "%ECO2%"
}
]
}
]
}