Monitoring Suhu Kelembaban via Website Fitur Grafik dan Datalogger Realtime
Pada kesempatan kali ini saya akan menjelaskan mengenai bagaimana cara membuat sebuah alat untuk memonitoring suhu dan kelembaban dengan sensor DHT11 kemudian data tersebuut masuk ke database https://supabase.com setelah masuk ke dalam web itu untuk tampilannya saya gunakan https://www.infinityfree.com/ jadi saya gunakan 2 web itu karena jika saya gunakan infinityfree saja ada masalah saat pengiriman datanya. untuk lebih jelasnya berikut koding dan interfacenya.
1. Skema
2. Interface
3. Koding Arduino IDE
#include <WiFi.h>
#include <HTTPClient.h>
#include <DHT.h>
#define DHTPIN 13
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
// WIFI
const char* ssid = "wifihpku";
const char* password = "123456789";
// SUPABASE
String supabaseURL = "https://yizpzxixllbgixxxxxxx.supabase.co/rest/v1/dht11_data";
String supabaseKey = "sb_publishable_mJNp2PCt9civsxe26URVYg_xxxxxxxx";
void setup() {
Serial.begin(115200);
dht.begin();
WiFi.begin(ssid,password);
Serial.print("Menghubungkan WiFi");
while(WiFi.status()!=WL_CONNECTED){
delay(500);
Serial.print(".");
}
Serial.println();
Serial.println("WiFi Terhubung");
}
void loop() {
int suhu = dht.readTemperature();
int kelembaban = dht.readHumidity();
if(isnan(suhu) || isnan(kelembaban)){
Serial.println("Sensor gagal membaca");
delay(1000);
return;
}
Serial.print("Suhu : ");
Serial.println(suhu);
Serial.print("Kelembaban : ");
Serial.println(kelembaban);
if(WiFi.status()==WL_CONNECTED){
HTTPClient http;
http.begin(supabaseURL);
http.addHeader(
"Content-Type",
"application/json"
);
http.addHeader(
"apikey",
supabaseKey
);
http.addHeader(
"Authorization",
"Bearer " + supabaseKey
);
String json =
"{"
"\"suhu\":" + String(suhu) +
",\"kelembaban\":" + String(kelembaban) +
"}";
Serial.println("Kirim:");
Serial.println(json);
int response = http.POST(json);
Serial.print("Response: ");
Serial.println(response);
Serial.println(http.getString());
http.end();
}
delay(1000);
}
#include <HTTPClient.h>
#include <DHT.h>
#define DHTPIN 13
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
// WIFI
const char* ssid = "wifihpku";
const char* password = "123456789";
// SUPABASE
String supabaseURL = "https://yizpzxixllbgixxxxxxx.supabase.co/rest/v1/dht11_data";
String supabaseKey = "sb_publishable_mJNp2PCt9civsxe26URVYg_xxxxxxxx";
void setup() {
Serial.begin(115200);
dht.begin();
WiFi.begin(ssid,password);
Serial.print("Menghubungkan WiFi");
while(WiFi.status()!=WL_CONNECTED){
delay(500);
Serial.print(".");
}
Serial.println();
Serial.println("WiFi Terhubung");
}
void loop() {
int suhu = dht.readTemperature();
int kelembaban = dht.readHumidity();
if(isnan(suhu) || isnan(kelembaban)){
Serial.println("Sensor gagal membaca");
delay(1000);
return;
}
Serial.print("Suhu : ");
Serial.println(suhu);
Serial.print("Kelembaban : ");
Serial.println(kelembaban);
if(WiFi.status()==WL_CONNECTED){
HTTPClient http;
http.begin(supabaseURL);
http.addHeader(
"Content-Type",
"application/json"
);
http.addHeader(
"apikey",
supabaseKey
);
http.addHeader(
"Authorization",
"Bearer " + supabaseKey
);
String json =
"{"
"\"suhu\":" + String(suhu) +
",\"kelembaban\":" + String(kelembaban) +
"}";
Serial.println("Kirim:");
Serial.println(json);
int response = http.POST(json);
Serial.print("Response: ");
Serial.println(response);
Serial.println(http.getString());
http.end();
}
delay(1000);
}
4. Program index.html
<!DOCTYPE html>
<html>
<head>
<title>ESP32 DHT11 Monitoring</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
*{
box-sizing:border-box;
}
body{
margin:0;
font-family:Arial,sans-serif;
background:#052e22;
color:white;
}
.header{
text-align:center;
padding:25px;
font-size:30px;
font-weight:bold;
}
.container{
width:92%;
margin:auto;
}
/* CARD */
.cards{
display:flex;
justify-content:center;
gap:25px;
flex-wrap:wrap;
}
.card{
background:#0b5139;
width:280px;
padding:25px;
border-radius:20px;
text-align:center;
box-shadow:0 5px 20px #0005;
}
.value{
font-size:45px;
font-weight:bold;
color:#00ff99;
}
/* BUTTON */
.btn-download{
background:#00a86b;
color:white;
border:none;
padding:12px 25px;
border-radius:25px;
font-size:16px;
cursor:pointer;
font-weight:bold;
margin-bottom:20px;
}
.btn-download:hover{
background:#00ff99;
color:#003b25;
}
/* CHART */
.chart-box{
background:#083b2b;
margin-top:25px;
padding:20px;
border-radius:20px;
cursor:pointer;
}
.chart-container{
height:230px;
}
.chart-container.fullscreen{
position:fixed;
top:20px;
left:20px;
right:20px;
bottom:20px;
height:auto;
background:#052e22;
z-index:999;
padding:30px;
border-radius:20px;
}
.chart-container canvas{
width:100%!important;
height:100%!important;
}
/* TABLE */
.table-box{
background:#083b2b;
margin-top:25px;
padding:20px;
border-radius:20px;
}
table{
width:100%;
border-collapse:collapse;
}
th{
background:#00a86b;
padding:14px;
}
td{
padding:12px;
text-align:center;
}
tr:nth-child(even){
background:#0b5139;
}
tr:nth-child(odd){
background:#06452f;
}
tr:hover{
background:#007f5f;
}
.badge-suhu{
background:#ff7b54;
padding:7px 15px;
border-radius:20px;
font-weight:bold;
}
.badge-hum{
background:#3498db;
padding:7px 15px;
border-radius:20px;
font-weight:bold;
}
</style>
</head>
<body>
<div class="header">
🌿 ESP32 DHT11 MONITORING
</div>
<div class="container">
<div class="cards">
<div class="card">
<h2>🌡 Suhu</h2>
<div class="value">
<span id="suhu">0</span> °C
</div>
</div>
<div class="card">
<h2>💧 Kelembaban</h2>
<div class="value">
<span id="kelembaban">0</span> %
</div>
</div>
</div>
<div class="chart-box">
<h2>📈 Grafik Suhu</h2>
<div class="chart-container"
onclick="besarGrafik(this)">
<canvas id="grafikSuhu"></canvas>
</div>
</div>
<div class="chart-box">
<h2>📈 Grafik Kelembaban</h2>
<div class="chart-container"
onclick="besarGrafik(this)">
<canvas id="grafikHum"></canvas>
</div>
</div>
<div class="table-box">
<h2>📋 Logger 100 Data Terakhir</h2>
<button class="btn-download"
onclick="downloadExcel()">
📥 Download Excel
</button>
<table>
<thead>
<tr>
<th>No</th>
<th>Waktu</th>
<th>Suhu</th>
<th>Kelembaban</th>
</tr>
</thead>
<tbody id="tabel">
</tbody>
</table>
</div>
</div>
<script type="module">
import { createClient }
from "https://cdn.jsdelivr.net/npm/@supabase/supabase-js/+esm";
// SUPABASE
const SUPABASE_URL =
"https://yizpzxixllbgixxxxxxx.supabase.co";
const SUPABASE_KEY =
"sb_publishable_mJNp2PCt9civsxe26URVYg_xxxxxxxx";
const supabase =
createClient(
SUPABASE_URL,
SUPABASE_KEY
);
let chartSuhu;
let chartHum;
let dataExcel=[];
async function loadData(){
let {data,error}=await supabase
.from("dht11_data")
.select("*")
.order("id",{ascending:false})
.limit(100);
if(error){
console.log(error);
return;
}
dataExcel=data;
data=data.reverse();
let waktu=[];
let suhu=[];
let hum=[];
data.forEach(item=>{
waktu.push(
new Date(item.waktu)
.toLocaleTimeString()
);
suhu.push(item.suhu);
hum.push(item.kelembaban);
});
document.getElementById("suhu").innerHTML=
suhu[suhu.length-1] ?? 0;
document.getElementById("kelembaban").innerHTML=
hum[hum.length-1] ?? 0;
let isi="";
let no=1;
data.slice().reverse().forEach(item=>{
isi+=`
<tr>
<td>${no}</td>
<td>
${new Date(item.waktu).toLocaleString()}
</td>
<td>
<span class="badge-suhu">
${item.suhu} °C
</span>
</td>
<td>
<span class="badge-hum">
${item.kelembaban} %
</span>
</td>
</tr>
`;
no++;
});
document.getElementById("tabel").innerHTML=isi;
if(chartSuhu)
chartSuhu.destroy();
chartSuhu=new Chart(
document.getElementById("grafikSuhu"),
{
type:"line",
data:{
labels:waktu,
datasets:[{
label:"Suhu °C",
data:suhu,
borderColor:"#00ff99",
backgroundColor:
"rgba(0,255,153,.2)",
fill:true,
tension:.4
}]
},
options:{
responsive:true,
maintainAspectRatio:false
}
}
);
if(chartHum)
chartHum.destroy();
chartHum=new Chart(
document.getElementById("grafikHum"),
{
type:"line",
data:{
labels:waktu,
datasets:[{
label:"Kelembaban %",
data:hum,
borderColor:"#3498db",
backgroundColor:
"rgba(52,152,219,.2)",
fill:true,
tension:.4
}]
},
options:{
responsive:true,
maintainAspectRatio:false
}
}
);
}
window.besarGrafik=function(el){
el.classList.toggle("fullscreen");
}
window.downloadExcel=function(){
let csv="No,Waktu,Suhu,Kelembaban\n";
dataExcel.forEach((item,index)=>{
csv+=
`${index+1},${item.waktu},${item.suhu},${item.kelembaban}\n`;
});
let blob=new Blob(
[csv],
{
type:"text/csv"
}
);
let url=URL.createObjectURL(blob);
let a=document.createElement("a");
a.href=url;
a.download="logger_DHT11.csv";
a.click();
URL.revokeObjectURL(url);
}
setInterval(loadData,2000);
loadData();
</script>
</body>
</html>
<html>
<head>
<title>ESP32 DHT11 Monitoring</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
*{
box-sizing:border-box;
}
body{
margin:0;
font-family:Arial,sans-serif;
background:#052e22;
color:white;
}
.header{
text-align:center;
padding:25px;
font-size:30px;
font-weight:bold;
}
.container{
width:92%;
margin:auto;
}
/* CARD */
.cards{
display:flex;
justify-content:center;
gap:25px;
flex-wrap:wrap;
}
.card{
background:#0b5139;
width:280px;
padding:25px;
border-radius:20px;
text-align:center;
box-shadow:0 5px 20px #0005;
}
.value{
font-size:45px;
font-weight:bold;
color:#00ff99;
}
/* BUTTON */
.btn-download{
background:#00a86b;
color:white;
border:none;
padding:12px 25px;
border-radius:25px;
font-size:16px;
cursor:pointer;
font-weight:bold;
margin-bottom:20px;
}
.btn-download:hover{
background:#00ff99;
color:#003b25;
}
/* CHART */
.chart-box{
background:#083b2b;
margin-top:25px;
padding:20px;
border-radius:20px;
cursor:pointer;
}
.chart-container{
height:230px;
}
.chart-container.fullscreen{
position:fixed;
top:20px;
left:20px;
right:20px;
bottom:20px;
height:auto;
background:#052e22;
z-index:999;
padding:30px;
border-radius:20px;
}
.chart-container canvas{
width:100%!important;
height:100%!important;
}
/* TABLE */
.table-box{
background:#083b2b;
margin-top:25px;
padding:20px;
border-radius:20px;
}
table{
width:100%;
border-collapse:collapse;
}
th{
background:#00a86b;
padding:14px;
}
td{
padding:12px;
text-align:center;
}
tr:nth-child(even){
background:#0b5139;
}
tr:nth-child(odd){
background:#06452f;
}
tr:hover{
background:#007f5f;
}
.badge-suhu{
background:#ff7b54;
padding:7px 15px;
border-radius:20px;
font-weight:bold;
}
.badge-hum{
background:#3498db;
padding:7px 15px;
border-radius:20px;
font-weight:bold;
}
</style>
</head>
<body>
<div class="header">
🌿 ESP32 DHT11 MONITORING
</div>
<div class="container">
<div class="cards">
<div class="card">
<h2>🌡 Suhu</h2>
<div class="value">
<span id="suhu">0</span> °C
</div>
</div>
<div class="card">
<h2>💧 Kelembaban</h2>
<div class="value">
<span id="kelembaban">0</span> %
</div>
</div>
</div>
<div class="chart-box">
<h2>📈 Grafik Suhu</h2>
<div class="chart-container"
onclick="besarGrafik(this)">
<canvas id="grafikSuhu"></canvas>
</div>
</div>
<div class="chart-box">
<h2>📈 Grafik Kelembaban</h2>
<div class="chart-container"
onclick="besarGrafik(this)">
<canvas id="grafikHum"></canvas>
</div>
</div>
<div class="table-box">
<h2>📋 Logger 100 Data Terakhir</h2>
<button class="btn-download"
onclick="downloadExcel()">
📥 Download Excel
</button>
<table>
<thead>
<tr>
<th>No</th>
<th>Waktu</th>
<th>Suhu</th>
<th>Kelembaban</th>
</tr>
</thead>
<tbody id="tabel">
</tbody>
</table>
</div>
</div>
<script type="module">
import { createClient }
from "https://cdn.jsdelivr.net/npm/@supabase/supabase-js/+esm";
// SUPABASE
const SUPABASE_URL =
"https://yizpzxixllbgixxxxxxx.supabase.co";
const SUPABASE_KEY =
"sb_publishable_mJNp2PCt9civsxe26URVYg_xxxxxxxx";
const supabase =
createClient(
SUPABASE_URL,
SUPABASE_KEY
);
let chartSuhu;
let chartHum;
let dataExcel=[];
async function loadData(){
let {data,error}=await supabase
.from("dht11_data")
.select("*")
.order("id",{ascending:false})
.limit(100);
if(error){
console.log(error);
return;
}
dataExcel=data;
data=data.reverse();
let waktu=[];
let suhu=[];
let hum=[];
data.forEach(item=>{
waktu.push(
new Date(item.waktu)
.toLocaleTimeString()
);
suhu.push(item.suhu);
hum.push(item.kelembaban);
});
document.getElementById("suhu").innerHTML=
suhu[suhu.length-1] ?? 0;
document.getElementById("kelembaban").innerHTML=
hum[hum.length-1] ?? 0;
let isi="";
let no=1;
data.slice().reverse().forEach(item=>{
isi+=`
<tr>
<td>${no}</td>
<td>
${new Date(item.waktu).toLocaleString()}
</td>
<td>
<span class="badge-suhu">
${item.suhu} °C
</span>
</td>
<td>
<span class="badge-hum">
${item.kelembaban} %
</span>
</td>
</tr>
`;
no++;
});
document.getElementById("tabel").innerHTML=isi;
if(chartSuhu)
chartSuhu.destroy();
chartSuhu=new Chart(
document.getElementById("grafikSuhu"),
{
type:"line",
data:{
labels:waktu,
datasets:[{
label:"Suhu °C",
data:suhu,
borderColor:"#00ff99",
backgroundColor:
"rgba(0,255,153,.2)",
fill:true,
tension:.4
}]
},
options:{
responsive:true,
maintainAspectRatio:false
}
}
);
if(chartHum)
chartHum.destroy();
chartHum=new Chart(
document.getElementById("grafikHum"),
{
type:"line",
data:{
labels:waktu,
datasets:[{
label:"Kelembaban %",
data:hum,
borderColor:"#3498db",
backgroundColor:
"rgba(52,152,219,.2)",
fill:true,
tension:.4
}]
},
options:{
responsive:true,
maintainAspectRatio:false
}
}
);
}
window.besarGrafik=function(el){
el.classList.toggle("fullscreen");
}
window.downloadExcel=function(){
let csv="No,Waktu,Suhu,Kelembaban\n";
dataExcel.forEach((item,index)=>{
csv+=
`${index+1},${item.waktu},${item.suhu},${item.kelembaban}\n`;
});
let blob=new Blob(
[csv],
{
type:"text/csv"
}
);
let url=URL.createObjectURL(blob);
let a=document.createElement("a");
a.href=url;
a.download="logger_DHT11.csv";
a.click();
URL.revokeObjectURL(url);
}
setInterval(loadData,2000);
loadData();
</script>
</body>
</html>
4. VIDEO HASILNYA


No comments:
Post a Comment