0% found this document useful (0 votes)
8 views18 pages

ESP32 Code

The document outlines the implementation of an ESP32 Dashboard featuring real-time monitoring of temperature, light, and humidity with a polished user interface. It includes a responsive layout, a real-time clock, and utilizes Chart.js for data visualization, while also supporting BLE notifications and a data API. The code provided includes setup for WiFi, BLE, and web server functionalities, along with HTML and JavaScript for the dashboard's front-end display.

Uploaded by

be2192005
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views18 pages

ESP32 Code

The document outlines the implementation of an ESP32 Dashboard featuring real-time monitoring of temperature, light, and humidity with a polished user interface. It includes a responsive layout, a real-time clock, and utilizes Chart.js for data visualization, while also supporting BLE notifications and a data API. The code provided includes setup for WiFi, BLE, and web server functionalities, along with HTML and JavaScript for the dashboard's front-end display.

Uploaded by

be2192005
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

/*

ESP32 Dashboard — Top-clock + polished UI (English)

- Temperature (left), Light (center), Humidity (right) in top half

- Real-time clock (hh:mm:ss.mmm) centered at top, updates every 10ms

- Chart.js for charts (CDN)

- Responsive + polished visuals

- BLE notifications & /data API preserved

*/

#include <WiFi.h>

#include <WiFiClient.h>

#include <WebServer.h>

#include <ESPmDNS.h>

#include <BLEDevice.h>

#include <BLEUtils.h>

#include <BLEServer.h>

#include <DHT.h>

#define DHTPIN 4

#define DHTTYPE DHT11

#define LDR_PIN 34 // Analog pin (ADC 0-4095)

const float MAX_LUX = 3000.0; // Adjust after calibration

const char *ssid = "Bin bin";


const char *password = "0935808037";

WebServer server(80);

DHT dht(DHTPIN, DHTTYPE);

// BLE UUIDs

#define SERVICE_UUID "12345678-1234-1234-1234-1234567890ab"

#define CHARACTERISTIC_UUID "abcdefab-1234-5678-90ab-abcdefabcdef"

BLECharacteristic *pCharacteristic;

void handleRoot() {

String html = R"rawliteral(

<!doctype html>

<html lang="en">

<head>

<meta charset="utf-8">

<meta name="viewport" content="width=device-width,initial-scale=1">

<title>ESP32 Dashboard — Real-time</title>

<!-- Google font + icons -->

<link href="https://fonts.googleapis.com/css2?
family=Inter:wght@300;400;600;800&display=swap" rel="stylesheet">

<link rel='stylesheet' href='https://use.fontawesome.com/releases/v5.7.2/css/all.css'>

<style>
:root{

--bg1: #0f1724;

--bg2: #0b3a66;

--card-bg: rgba(255,255,255,0.95);

--muted: #6b7280;

html,body{height:100%;margin:0;font-family: 'Inter', system-ui, -apple-system, 'Segoe UI',


Roboto, sans-serif;background: linear-gradient(180deg,#071428 0%, #0b2f4a 60%, #0f3b5a
100%); color:#0f1724;}

/* Top header with clock */

header {

width:100%;

display:flex;

align-items:center;

justify-content:center;

padding:18px 12px;

box-sizing:border-box;

position:sticky;

top:0;

z-index:40;

background: linear-gradient(90deg, rgba(255,255,255,0.04), rgba(255,255,255,0.02));

backdrop-filter: blur(6px);

border-bottom: 1px solid rgba(255,255,255,0.04);

.brand {

position:absolute;

left:18px;
color: #e6f0ff;

font-weight:700;

letter-spacing:0.2px;

font-size:1rem;

#clock {

color: #e6f7ff;

font-weight:800;

font-size:1.2rem;

background: linear-gradient(90deg, rgba(255,255,255,0.06), rgba(255,255,255,0.02));

padding:8px 14px;

border-radius:999px;

box-shadow: 0 6px 18px rgba(2,6,23,0.45);

border: 1px solid rgba(255,255,255,0.06);

font-family: 'Inter', sans-serif;

/* Main layout: top half with 3 equal cards */

.top-area {

display:grid;

grid-template-columns: 1fr 1fr 1fr;

gap:14px;

padding: 14px;

height:50vh; /* Top half */

box-sizing:border-box;

align-items:start; /* cards anchored to top */


}

.card {

background: linear-gradient(180deg, rgba(255,255,255,0.98), rgba(255,255,255,0.92));

border-radius:14px;

padding:14px;

box-shadow: 0 10px 30px rgba(2,6,23,0.45);

display:flex;

flex-direction:column;

align-items:center;

justify-content:flex-start;

min-height:100%;

overflow:hidden;

transition: transform 220ms ease, box-shadow 220ms ease;

.card:hover{ transform: translateY(-6px); box-shadow: 0 20px 40px rgba(2,6,23,0.55); }

.title {

color:#0b3a66;

font-weight:700;

font-size:1.15rem;

margin-bottom:6px;

display:flex;

align-items:center;

gap:8px;

}
.title i { color:#1f7aef; font-size:1.15rem; }

.chart-wrap {

width:100%;

height: calc(50vh - 170px); /* chart area reduced so title/vals fit */

display:flex;

align-items:center;

justify-content:center;

margin-bottom:8px;

.value-num {

font-weight:900;

font-size:1.5rem;

color:#0b3a66;

margin-top:6px;

.status {

font-size:1rem;

color:var(--muted);

margin-top:6px;

/* Nice footer note below top area (empty space) */

.bottom-space {

padding: 16px;
color: rgba(255,255,255,0.85);

font-size:0.95rem;

text-align:center;

opacity:0.9;

/* Responsive: stack vertically on small screens; make cards smaller and center */

@media (max-width: 880px) {

.top-area {

grid-template-columns: 1fr;

height: auto;

padding: 12px;

.chart-wrap { height: 240px; }

#clock { font-size:1.05rem; padding:6px 10px; }

.title { font-size:1rem; }

.value-num { font-size:1.25rem; }

</style>

<!-- Chart.js CDN -->

<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>

</head>

<body>

<header>

<div class="brand">ESP32 Dashboard</div>

<div id="clock">--:--:--.---</div>
</header>

<main>

<div class="top-area">

<div class="card" id="tempCol">

<div class="title"><i class="fas fa-thermometer-half"></i> Temperature</div>

<div class="chart-wrap"><canvas id="tempChart"></canvas></div>

<div class="value-num" id="tempVal">-- °C</div>

<div class="status" id="tempStatus">Status: --</div>

</div>

<div class="card" id="lightCol">

<div class="title"><i class="fas fa-sun"></i> Light (Lux)</div>

<div class="chart-wrap"><canvas id="lightChart"></canvas></div>

<div class="value-num" id="lightVal">-- lux</div>

<div class="status" id="lightStatus">Status: --</div>

</div>

<div class="card" id="humCol">

<div class="title"><i class="fas fa-tint"></i> Humidity</div>

<div class="chart-wrap"><canvas id="humChart"></canvas></div>

<div class="value-num" id="humVal">-- %</div>

<div class="status" id="humStatus">Status: --</div>

</div>

</div>
</main>

<script>

const MAX_LUX = )rawliteral";

html += String(MAX_LUX, 1);

html += R"rawliteral(;

// ---------- Clock (real-time with millisecond display) ----------

// Update every 10ms for millisecond resolution display.

function pad(n, width = 2) { return String(n).padStart(width, '0'); }

function updateClock() {

const d = new Date();

const hh = pad(d.getHours(),2);

const mm = pad(d.getMinutes(),2);

const ss = pad(d.getSeconds(),2);

const ms = pad(d.getMilliseconds(),3);

document.getElementById('clock').textContent = `${hh}:${mm}:${ss}.${ms}`;

// Start clock with 10ms interval (practical and shows ms)

setInterval(updateClock, 10);

updateClock();

// ---------- Classification functions (thresholds) ----------

function classifyTemperature(t) {

if (t === null) return {color:'#9ca3af', text:'--'};


if (t <= 24.0) return {color:'#16a34a', text:'Comfortable'};

if (t > 24.0 && t <= 28.0) return {color:'#d97706', text:'Warm'};

return {color:'#dc2626', text:'Hot'};

function classifyHumidity(h) {

if (h === null) return {color:'#9ca3af', text:'--'};

if (h >= 40.0 && h <= 60.0) return {color:'#16a34a', text:'Good'};

if ((h >= 30.0 && h < 40.0) || (h > 60.0 && h <= 70.0)) return {color:'#d97706',
text:'Acceptable'};

return {color:'#dc2626', text:'Uncomfortable'};

function classifyLight(lux) {

if (lux === null) return {color:'#9ca3af', text:'--'};

if (lux < 900.0) return {color:'#16a34a', text:'Very Bright'};

if (lux >= 900.0 && lux <= 2000.0) return {color:'#d97706', text:'Moderate'};

return {color:'#dc2626', text:'Dim / Low'};

// ---------- Chart setup ----------

let tempChart, humChart, lightChart;

function createCharts() {

// Temperature half-doughnut (0..50)

const tCtx = document.getElementById('tempChart').getContext('2d');

tempChart = new Chart(tCtx, {

type:'doughnut',

data:{
labels:['value','rest'],

datasets:[{ data:[0,50], backgroundColor:['#16a34a','#e6eef5'], borderWidth:0 }]

},

options:{

rotation:-90, circumference:180, cutout:'70%', maintainAspectRatio:false,

plugins:{legend:{display:false}}

});

// Humidity half-doughnut (0..100)

const hCtx = document.getElementById('humChart').getContext('2d');

humChart = new Chart(hCtx, {

type:'doughnut',

data:{ labels:['value','rest'], datasets:[{ data:[0,100], backgroundColor:


['#16a34a','#e6eef5'], borderWidth:0 }]},

options:{ rotation:-90, circumference:180, cutout:'70%', maintainAspectRatio:false,


plugins:{legend:{display:false}} }

});

// Light horizontal bar (x max = MAX_LUX)

const lCtx = document.getElementById('lightChart').getContext('2d');

lightChart = new Chart(lCtx, {

type:'bar',

data:{ labels:[''], datasets:[{ label:'Lux', data:[0], backgroundColor:['#16a34a'] }]},

options:{

indexAxis:'y', maintainAspectRatio:false, responsive:true,

plugins:{ legend:{display:false} },
scales:{

x:{ beginAtZero:true, max: MAX_LUX },

y:{ ticks:{ display:false } }

});

// ---------- UI update ----------

function updateUI(json) {

// Temp

if (json.temperature !== null) {

const t = parseFloat(json.temperature);

const cls = classifyTemperature(t);

document.getElementById('tempVal').textContent = t.toFixed(2) + ' °C';

document.getElementById('tempStatus').textContent = 'Status: ' + cls.text;

const topT = 50.0;

tempChart.data.datasets[0].data[0] = Math.min(Math.max(t,0),topT);

tempChart.data.datasets[0].data[1] = Math.max(topT - Math.min(Math.max(t,0),topT),


0.0001);

tempChart.data.datasets[0].backgroundColor[0] = cls.color;

} else {

document.getElementById('tempVal').textContent = '-- °C';

document.getElementById('tempStatus').textContent = 'Status: --';

tempChart.data.datasets[0].data[0] = 0; tempChart.data.datasets[0].data[1] = 50;

tempChart.data.datasets[0].backgroundColor[0] = '#9ca3af';
}

tempChart.update();

// Humidity

if (json.humidity !== null) {

const h = parseFloat(json.humidity);

const cls = classifyHumidity(h);

document.getElementById('humVal').textContent = h.toFixed(2) + ' %';

document.getElementById('humStatus').textContent = 'Status: ' + cls.text;

const topH = 100.0;

humChart.data.datasets[0].data[0] = Math.min(Math.max(h,0),topH);

humChart.data.datasets[0].data[1] = Math.max(topH - Math.min(Math.max(h,0),topH),


0.0001);

humChart.data.datasets[0].backgroundColor[0] = cls.color;

} else {

document.getElementById('humVal').textContent = '-- %';

document.getElementById('humStatus').textContent = 'Status: --';

humChart.data.datasets[0].data[0] = 0; humChart.data.datasets[0].data[1] = 100;

humChart.data.datasets[0].backgroundColor[0] = '#9ca3af';

humChart.update();

// Light

if (json.light_lux !== null) {

const lux = parseFloat(json.light_lux);

const cls = classifyLight(lux);


document.getElementById('lightVal').textContent = lux.toFixed(1) + ' lux';

document.getElementById('lightStatus').textContent = 'Status: ' + cls.text;

lightChart.data.datasets[0].data[0] = Math.min(Math.max(lux,0),MAX_LUX);

lightChart.data.datasets[0].backgroundColor[0] = cls.color;

} else {

document.getElementById('lightVal').textContent = '-- lux';

document.getElementById('lightStatus').textContent = 'Status: --';

lightChart.data.datasets[0].data[0] = 0;

lightChart.data.datasets[0].backgroundColor[0] = '#9ca3af';

lightChart.update();

// ---------- Polling ----------

async function pollData() {

try {

const res = await fetch('/data');

if (!res.ok) throw new Error('Network response not ok');

const json = await res.json();

updateUI(json);

} catch (err) {

console.error('Fetch error', err);

// Init
createCharts();

pollData();

setInterval(pollData, 2000);

</script>

</body>

</html>

)rawliteral";

server.send(200, "text/html", html);

// JSON API

void handleSensorData() {

float temp = dht.readTemperature();

float hum = dht.readHumidity();

int raw = analogRead(LDR_PIN);

float lux = (raw / 4095.0) * MAX_LUX;

String tempStr = isnan(temp) ? String("null") : String(temp, 2);

String humStr = isnan(hum) ? String("null") : String(hum, 2);

String rawStr = String(raw);

String luxStr = String(lux, 1);

String json = "{";

json += "\"temperature\":" + tempStr + ",";

json += "\"humidity\":" + humStr + ",";


json += "\"light_raw\":" + rawStr + ",";

json += "\"light_lux\":" + luxStr;

json += "}";

server.send(200, "application/json", json);

void setup() {

Serial.begin(115200);

dht.begin();

// BLE setup

BLEDevice::init("ESP32_BLE_Sensor");

BLEServer *pServer = BLEDevice::createServer();

BLEService *pService = pServer->createService(SERVICE_UUID);

pCharacteristic = pService->createCharacteristic(

CHARACTERISTIC_UUID,

BLECharacteristic::PROPERTY_READ |

BLECharacteristic::PROPERTY_NOTIFY

);

pCharacteristic->setValue("Waiting for data...");

pService->start();

BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();


pAdvertising->addServiceUUID(SERVICE_UUID);

pAdvertising->start();

// WiFi

WiFi.begin(ssid, password);

Serial.print("Connecting to WiFi");

while (WiFi.status() != WL_CONNECTED) {

delay(500);

Serial.print(".");

Serial.println();

Serial.println("Connected to WiFi!");

Serial.print("IP Address: ");

Serial.println(WiFi.localIP());

server.on("/", handleRoot);

server.on("/data", handleSensorData);

server.begin();

void loop() {

float temp = dht.readTemperature();

float hum = dht.readHumidity();

int raw = analogRead(LDR_PIN);

float lux = (raw / 4095.0) * MAX_LUX;


String tStr = isnan(temp) ? String("--") : String(temp, 2);

String hStr = isnan(hum) ? String("--") : String(hum, 2);

String bleData = "T: " + tStr + "C, H: " + hStr + "%, L: " + String(lux, 1) + " lux";

Serial.println(bleData);

pCharacteristic->setValue(bleData.c_str());

pCharacteristic->notify();

server.handleClient();

delay(500);

You might also like