There are individual Arduino sketches provided for each sensor, but to make things simple, I recommend using the final sketch called 16atmosphere_web. This sketch connects your ESP32 to a Wi-Fi hotspot and displays all the weather data on a webpage.
#include <WiFi.h>
#include <WebServer.h>
#include <ACB_Atmospheric.h>
#include <ACB_DHT11.h>
#include <ACB_WindCup.h>
#include <ACB_Ultraviolet.h>
#include <ACB_PM25.h>
#include <U8g2lib.h>
#include <Wire.h>
#include "Arduino.h"
#include "esp_http_server.h"
#include <ESP32Servo.h>
#include "soc/rtc_wdt.h"
#include "esp_task_wdt.h"
// set wifi name
#define WIFI_SSID "ACEBOTT"
// set wifi password
#define WIFI_PASSWORD "12345678"
#define WIFI_CONNECT_MAX_TIMEOUT 5 // time out of connetion
int wifiConnectRetryNum = 0; // WIFI reconnect num
int wifiConnectState = false; // WIFI connect state
ACB_Atmospheric BMP;
ACB_Ultraviolet uv;
ACB_PM25 PM25;
ACB_WindCup wind;
ACB_DHT11 dht23(23);
Servo myservo1;
int val=0;
int pm25_value;
typedef struct {
httpd_req_t *req;
size_t len;
} jpg_chunking_t;
httpd_handle_t camera_httpd = NULL;
// data of sensors
int light=0;
int raindrop=0;
int Vibration;
int Vibration1 = 1;
int hum;
int tem;
float bmp_pressure;
float bmp_temp;
float _PM25;
float wincup;
int uv_light;
WebServer server(80);
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);
void startCameraServer();
void setup() { // initialize
Serial.begin(115200); // set the baud rate to 115200
myservo1.attach(4);
myservo1.write(90);
connectWifi();
startCameraServer();
BMP.Atmospheric_init();
uv.setpin(33);
PM25.setpin(17,16);
wind.setpin(32);
pinMode(36, INPUT); // set pin light sensor as input
pinMode(39, INPUT); // set pin raindrop sensor as input
pinMode(18, INPUT); // set pin vibration sensor as input
pinMode(23, INPUT); // set pin DHT11 sensor as input
u8g2.setI2CAddress(0x3C*2);
u8g2.begin();
u8g2.enableUTF8Print();
esp_task_wdt_init(10000, true);
xTaskCreatePinnedToCore(loopMotorTask, "MotorTask",20000,NULL,5,NULL,0);
}
void connectWifi()
{
WiFi.setTxPower(WIFI_POWER_19_5dBm);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
delay(1000);
Serial.println(".");
wifiConnectRetryNum++;
if (wifiConnectRetryNum > WIFI_CONNECT_MAX_TIMEOUT)
{
break;
}
}
if (WiFi.status() != WL_CONNECTED)
{
wifiConnectState = false;
}
else
{
wifiConnectState = true;
}
Serial.print("IP:");
Serial.println(WiFi.localIP());
}
void loop() {
u8g2.firstPage();
do
{
Page1();
}while(u8g2.nextPage());
xTaskCreatePinnedToCore(loopMotorTask1, "MotorTask",20000,NULL,5,NULL,0);
}
int getpm25Value()
{
pm25_value = PM25.read();
// Serial.println(pm25_value);
return pm25_value;
}
void loopMotorTask(void *pvParameters) {
for (;;) {
getpm25Value();
esp_task_wdt_reset();
}
}
void Page1() {//define content of OLED
tem = dht23.get_Temperature_Data();//get temperatur value
hum = dht23.get_Humidity_Data();//get humidity value
raindrop = analogRead(39);
if(raindrop>1000){
u8g2.setFontPosBottom();
u8g2.setFont(u8g2_font_open_iconic_all_4x_t);//rain
u8g2.drawGlyph(0,0+4*8,241);
}
else{
u8g2.setFontPosBottom();
u8g2.setFont(u8g2_font_open_iconic_all_4x_t);//sun
u8g2.drawGlyph(0,0+4*8,259);
}
if (wifiConnectState){
u8g2.setFont(u8g2_font_timR08_tf);
u8g2.setFontPosTop();
u8g2.setCursor(50,0);
u8g2.print(WiFi.localIP());//display Wifi IP
} else {
u8g2.setFont(u8g2_font_timR08_tf);
u8g2.setFontPosTop();
u8g2.setCursor(50,0);
u8g2.print("Connect WiFi Fail");//display error of wifi connection
}
u8g2.setFont(u8g2_font_timR10_tf);
u8g2.setFontPosTop();
u8g2.setCursor(50,12);
u8g2.print(String(tem)+String("°c") );//display temperature value
u8g2.setFont(u8g2_font_timR10_tf);
u8g2.setFontPosTop();
u8g2.setCursor(95,12);
u8g2.print(String(hum)+String("%") );//display humidity value
u8g2.setFont(u8g2_font_timR10_tf);
u8g2.setCursor(50,25);
u8g2.print(String("PM2.5 : ") + String(PM25.read()));//display PM2.5 value
u8g2.setFont(u8g2_font_timR08_tf);
u8g2.setCursor(0,43);
u8g2.print(String("Lt: ") + String(light));//display light value
u8g2.setCursor(0,55);
u8g2.print(String("Uv: ") + String(uv.read("level")));//display UV index
u8g2.setCursor(50,43);
u8g2.print(String("P: ") + String(int(BMP.read("Press"))));//display barometric pressure
u8g2.setCursor(50,55);
u8g2.print(String("w: ") + String(wind.read()));//display wind speed value
u8g2.setCursor(95,43);
u8g2.print(String("R: ") + String(raindrop));//display raindrop value
u8g2.setCursor(95,55);
u8g2.print(String("V: ") + String(Vibration1));//display vibration value
}
static esp_err_t data_handler(httpd_req_t *req) {
// get data of sensors
bmp_pressure = BMP.read("Press");
bmp_temp = BMP.read("Temp");
_PM25 = pm25_value;
light = analogRead(36);
tem = dht23.get_Temperature_Data();
wincup = wind.read();
uv_light = uv.read("level");
raindrop = analogRead(39);
// creat jason string
String response = "{";
response += "\"temp\":" + String(tem) + ",";
response += "\"hum\":" + String(hum) + ",";
response += "\"press\":" + String(bmp_pressure) + ",";
response += "\"alt\":" + String(_PM25) + ",";
response += "\"light\":" + String(light) + ",";
response += "\"wind\":" + String(wincup) + ",";
response += "\"vib\":" + String(Vibration1) + ",";
response += "\"uv\":" + String(uv_light) + ",";
response += "\"raindrop\":" + String(raindrop);
response += "}";
// et the response header and send the response
httpd_resp_set_type(req, "application/json");
httpd_resp_send(req, response.c_str(), response.length());
// return ESP_OK;
Vibration1 = 1;
char* buf;
size_t buf_len;
char variable[32] = {0,};
char value[32] = {0,};
char s1_value[32] = {0,};
buf_len = httpd_req_get_url_query_len(req) + 1;
if (buf_len > 1) {
buf = (char*)malloc(buf_len);
if(!buf){
httpd_resp_send_500(req);
return ESP_FAIL;
}
if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
if ((httpd_query_key_value(buf, "var", variable, sizeof(variable)) == ESP_OK &&
httpd_query_key_value(buf, "val", value, sizeof(value)) == ESP_OK &&
httpd_query_key_value(buf, "s1", s1_value, sizeof(s1_value)) == ESP_OK)){
} else {
free(buf);
httpd_resp_send_404(req);
return ESP_FAIL;
}
} else {
free(buf);
httpd_resp_send_404(req);
return ESP_FAIL;
}
free(buf);
} else {
httpd_resp_send_404(req);
return ESP_FAIL;
}
int val = atoi(value);
int s1 = atoi(s1_value);
int res = 0;
if(!strcmp(variable, "qx")) {
if (val == 1){
myservo1.write(s1);
}
} else {
res = -1;
}
if(res){ return httpd_resp_send_500(req); }
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
return httpd_resp_send(req, NULL, 0);
}
// get vibration value
int getvibrationValue()
{
Vibration = digitalRead(18);
if (Vibration==0){
Vibration1 = 0;
}
return Vibration1;
}
void loopMotorTask1(void *pvParameters) {
for (;;) {
// getpm25Value();
getvibrationValue();
esp_task_wdt_reset();
}
}
//*************************Web_HTML*************************
static const char PROGMEM INDEX_HTML[] = R"rawliteral(
<!doctype html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Weather Station</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #ffffff;
color: #24292e;
margin: 0;
padding: 20px;
}
.container {
padding: 20px;
background-color: #f9f9f9;
border-radius: 10px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
}
h1 {
font-size: 2.5rem;
font-weight: bold;
text-align: center;
margin: 2px 0 10px;
}
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
.card {
padding: 10px;
background-color: #ffffff;
border: 1px solid #eaeaea;
border-radius: 10px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 150px;
margin: 0;
}
.text-purple {
color: #6a0dad;
font-size: 1.2rem;
margin: 0;
}
.value {
font-size: 22px;
margin: 0;
}
.slider-container {
display: flex;
justify-content: center;
align-items: center;
margin-top: 10px;
}
.slider-container p {
margin-right: 10px;
color: #000;
}
input[type="range"] {
width: 200px;
}
</style>
</head>
<body>
<div>
<h1>Weather Station</h1>
<div class="grid">
<div class="card">
<span class="text-purple">Temperature</span>
<p class="value" id="temperature"></p> <!-- Temperature -->
</div>
<div class="card">
<span class="text-purple"> Humidity </span>
<p class="value" id="humidity"></p> <!-- humidity -->
</div>
<div class="card">
<span class="text-purple"> Pressure </span>
<p class="value" id="pressure"></p> <!-- barometric pressure -->
</div>
<div class="card">
<span class="text-purple">PM2.5</span>
<p class="value" id="altitude"></p> <!-- pm2.5 -->
</div>
<div class="card">
<span class="text-purple">Light</span>
<p class="value" id="light"></p> <!-- lightness -->
</div>
<div class="card">
<span class="text-purple">Wind</span>
<p class="value" id="wind"></p> <!-- wind speed -->
</div>
<div class="card">
<span class="text-purple">Vibration</span>
<p class="value" id="vibration"></p> <!-- vibration -->
</div>
<div class="card">
<span class="text-purple">Ultraviolet</span>
<p class="value" id="uv"></p> <!-- UV level -->
</div>
<div class="card">
<span class="text-purple">Raindrop</span>
<p class="value" id="raindrop"></p> <!-- rain -->
</div>
</div>
<div class="slider-container">
<p>Servo:</p>
<input type="range" style="width: 200px;" id="slider1" min="0" max="180" value="90" ontouchend="fetch(document.location.origin+'/control?var=car&val=3');" oninput="sendSliderValue11();" onmousedown="sendSliderValue11();" onchange="updateValue1(this.value);">
<p id="sliderValue1" style="color: black; width: 25px; margin-left: 10px;">90</p>
</div>
</div>
<script>
setInterval(() => {
fetch('/data')
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
document.getElementById('temperature').innerText = data.temp + '°C';
document.getElementById('humidity').innerText = data.hum + '%';
document.getElementById('pressure').innerText = data.press + ' hPa';
document.getElementById('altitude').innerText = data.alt;
document.getElementById('light').innerText = data.light;
document.getElementById('wind').innerText = data.wind + 'm/s';
document.getElementById('vibration').innerText = data.vib;
document.getElementById('uv').innerText = data.uv;
document.getElementById('raindrop').innerText = data.raindrop;
})
.catch(error => {
console.error('Fetching data failed:', error);
});
}, 500);
function sendSliderValue11() {
var sliderValue1 = document.getElementById("slider1").value;
var url = document.location.origin + "/data?var=qx&val=1&s1=" + sliderValue1;
fetch(url);
}
function updateValue1(value) {
document.getElementById("sliderValue1").textContent = value;
}
</script>
</body>
</html>
)rawliteral";
static esp_err_t index_handler(httpd_req_t *req){
httpd_resp_set_type(req, "text/html");
return httpd_resp_send(req, (const char *)INDEX_HTML, strlen(INDEX_HTML));
}
void startCameraServer() {
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
httpd_uri_t index_uri = {
.uri = "/",
.method = HTTP_GET,
.handler = index_handler,
.user_ctx = NULL
};
httpd_uri_t data_uri = {
.uri = "/data",
.method = HTTP_GET,
.handler = data_handler,
.user_ctx = NULL
};
Serial.printf("Starting web server on port: '%d'\n", config.server_port);
if (httpd_start(&camera_httpd, &config) == ESP_OK) {
httpd_register_uri_handler(camera_httpd, &index_uri);
httpd_register_uri_handler(camera_httpd, &data_uri);
} else {
Serial.println("Failed to start server!");
}
}