Skip to content

Instantly share code, notes, and snippets.

@realmayus
Created April 8, 2023 10:34
Show Gist options
  • Save realmayus/38919dc619caf3f4326c649dc5b22032 to your computer and use it in GitHub Desktop.
Save realmayus/38919dc619caf3f4326c649dc5b22032 to your computer and use it in GitHub Desktop.
ESP8266 + DHT22 temp + humid sensor with web GUI
// Load Wi-Fi library
#include <ESP8266WiFi.h>
#include <Adafruit_Sensor.h>
#include "DHT.h"
#include <stdio.h>
// Replace with your network credentials
const char* ssid = "SSID";
const char* password = "PASSWORD";
// Set web server port number to 80
WiFiServer server(80);
// Variable to store the HTTP request
String header;
DHT dht(5, DHT22);
// Current time
unsigned long currentTime = millis();
// Previous time
unsigned long previousTime = 0;
// Define timeout time in milliseconds (example: 2000ms = 2s)
const long timeoutTime = 2000;
void setup() {
Serial.begin(115200);
dht.begin();
// Connect to Wi-Fi network with SSID and password
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
// Print local IP address and start web server
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
delay(2000); //give sensor some time to initialize
server.begin();
}
void loop(){
WiFiClient client = server.available(); // Listen for incoming clients
if (client) { // If a new client connects,
Serial.println("New Client."); // print a message out in the serial port
String currentLine = ""; // make a String to hold incoming data from the client
currentTime = millis();
previousTime = currentTime;
while (client.connected() && currentTime - previousTime <= timeoutTime) { // loop while the client's connected
currentTime = millis();
if (client.available()) { // if there's bytes to read from the client,
char c = client.read(); // read a byte, then
Serial.write(c); // print it out the serial monitor
header += c;
if (c == '\n') { // if the byte is a newline character
// if the current line is blank, you got two newline characters in a row.
// that's the end of the client HTTP request, so send a response:
if (currentLine.length() == 0) {
// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
// and a content-type so the client knows what's coming, then a blank line:
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println("Connection: close");
client.println();
// turns the GPIOs on and off
if (header.indexOf("GET /data") >= 0) {
Serial.println("Requested data");
float humidity = dht.readHumidity();
Serial.println(humidity);
float temp = dht.readTemperature();
Serial.println(temp);
char response_str[50];
sprintf(response_str, "{ \"temp\": %.6f, \"humid\": %.6f }", temp, humidity);
client.println(response_str);
Serial.println(response_str);
break;
} else {
// Display the HTML web page (insert web.html here, replace newlines with spaces)
client.println("<!DOCTYPE html> <head> <title>ESP8266</title> <script src='https://cdn.jsdelivr.net/npm/chart.js'></script> <script src='https://cdn.jsdelivr.net/npm/luxon'></script> <script src='https://cdn.jsdelivr.net/npm/chartjs-adapter-luxon'></script> </head> <body> <div> <select id='filter' value='30'> <option value='30'>Last 30 seconds</option> <option value='60'>Last 1 minute</option> <option value='300'>Last 5 minutes</option> <option value='3600'>Last 1 hour</option> <option value='-1'>All time</option> </select> <input id='updateInterval' type='range' min='0.1' max='10' value='1' onchange='changeUpdateFrequency()'/> <canvas id='chart'></canvas> </div> </body> <script> const ctx = document.getElementById('chart'); const ds_temp = []; const ds_humid = []; const lastXSeconds = (arr, filter) => arr.filter(function(dataPoint) { return filter === -1 || dataPoint.x.getTime() > (new Date().getTime() - filter * 1000); }); let chart = new Chart(ctx, { type: 'line', data: { datasets: [{ label: 'Humidity', data: lastXSeconds(ds_humid), borderColor: 'blue', fill: false }, { label: 'Temperature', data: lastXSeconds(ds_temp), borderColor: 'red', fill: false }] }, options: { scales: { x: { type: 'time' }, y: { suggestedMin: 0, suggestedMax: 100 } }, plugins: { tooltip: { callbacks: { title: function(context) { let label = context.dataset.label; let val = context.dataset.formattedValue; if (label === 'Humidity') { val += '%' } else if (labal === 'Temperature') { val += ' °C' } return val } } } } } }); async function update() { const filter = document.getElementById('filter').value; const data = await fetch('/data'); const parsed = await data.json(); ds_temp.push({x: new Date(), y: parsed.temp}); ds_humid.push({x: new Date(), y: parsed.humid}); chart.data.datasets[0].data = lastXSeconds(ds_humid, Number(filter)); chart.data.datasets[1].data = lastXSeconds(ds_temp, Number(filter)); chart.update(); } const interval = setInterval(update, 1000); function changeUpdateFrequency() { const updateFrequency = document.getElementById('updateInterval').value; clearInterval(interval); const interval = setInterval(update, Number(updateFrequency) * 1000); } </script> </html>");
client.println("");
break;
}
} else { // if you got a newline, then clear currentLine
currentLine = "";
}
} else if (c != '\r') { // if you got anything else but a carriage return character,
currentLine += c; // add it to the end of the currentLine
}
}
}
// Clear the header variable
header = "";
// Close the connection
client.stop();
Serial.println("Client disconnected.");
Serial.println("");
}
}
<!DOCTYPE html>
<head>
<title>ESP8266</title>
<script src='https://cdn.jsdelivr.net/npm/chart.js'></script>
<script src='https://cdn.jsdelivr.net/npm/luxon'></script>
<script src='https://cdn.jsdelivr.net/npm/chartjs-adapter-luxon'></script>
</head>
<body>
<div>
<select id='filter' value='30'>
<option value='30'>Last 30 seconds</option>
<option value='60'>Last 1 minute</option>
<option value='300'>Last 5 minutes</option>
<option value='3600'>Last 1 hour</option>
<option value='-1'>All time</option>
</select>
<input id='updateInterval' type='range' min='0.1' max='10' value='1' onchange='changeUpdateFrequency()'/>
<canvas id='chart'></canvas>
</div>
</body>
<script>
const ctx = document.getElementById('chart');
const ds_temp = [];
const ds_humid = [];
const lastXSeconds = (arr, filter) => arr.filter(function(dataPoint) {
return filter === -1 || dataPoint.x.getTime() > (new Date().getTime() - filter * 1000);
});
let chart = new Chart(ctx, {
type: 'line',
data: {
datasets: [{
label: 'Humidity',
data: lastXSeconds(ds_humid),
borderColor: 'blue',
fill: false
}, {
label: 'Temperature',
data: lastXSeconds(ds_temp),
borderColor: 'red',
fill: false
}]
},
options: {
scales: {
x: {
type: 'time'
},
y: {
suggestedMin: 0,
suggestedMax: 100
}
},
plugins: {
tooltip: {
callbacks: {
title: function(context) {
let label = context.dataset.label;
let val = context.dataset.formattedValue;
if (label === 'Humidity') {
val += '%'
} else if (labal === 'Temperature') {
val += ' °C'
}
return val
}
}
}
}
}
});
async function update() {
const filter = document.getElementById("filter").value;
const data = await fetch('/data');
const parsed = await data.json();
ds_temp.push({x: new Date(), y: parsed.temp});
ds_humid.push({x: new Date(), y: parsed.humid});
chart.data.datasets[0].data = lastXSeconds(ds_humid, Number(filter));
chart.data.datasets[1].data = lastXSeconds(ds_temp, Number(filter));
chart.update();
}
const interval = setInterval(update, 1000);
function changeUpdateFrequency() {
const updateFrequency = document.getElementById('updateInterval').value;
clearInterval(interval);
const interval = setInterval(update, Number(updateFrequency) * 1000);
}
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment