Monitoring 2 Suhu via Website Hosting + Realtime Grafik DataLogger
Pada kesempatan kali ini saya akan menjelaskan mengenai bagaimana cara membuat sebuah alat yang daapaat memonitor 2 buah suhu secaraa terpisah tapi bisa dimasukkan ke dalam 1 website dan 1 database. untuk database saya menggunakan https://supabase.com dan untuk datamanager dan website saya menggunakan hosting dari infinityfree.com. untuk detailnya yaitu seperti berikut.
1. Skema
2. Interface
3. VIDEO HASILNYA
4. Program ESP32 - Batang / Semarang
#include <WiFi.h>
#include <HTTPClient.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <time.h>
// ================= WIFI =================
const char* ssid = "wifihpku";
const char* password = "12345678";
// ================= SUPABASE =================
String supabaseURL =
"https://yizpzxixllbgixxxxxxx.supabase.co/rest/v1/suhu_data";
String supabaseKey =
"sb_publishable_mJNp2PCt9civsxe26URVYg_dxxxxxxx";
// ================= DEVICE =================
// ESP32 pertama
String device = "ESP32_BATANG";
String kota = "Batang";
// ESP32 kedua ubah menjadi:
// String device = "ESP32_SEMARANG";
// String kota = "Semarang";
// ================= DS18B20 =================
#define ONE_WIRE_BUS 13
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
void setup(){
Serial.begin(115200);
sensors.begin();
// WIFI
WiFi.begin(ssid,password);
Serial.print("Connecting");
while(WiFi.status()!=WL_CONNECTED){
delay(500);
Serial.print(".");
}
Serial.println();
Serial.println("WiFi Connected");
// waktu WIB
configTime(
7*3600,
0,
"pool.ntp.org",
"time.nist.gov"
);
}
String getTime(){
struct tm timeinfo;
if(!getLocalTime(&timeinfo)){
return "NULL";
}
char waktu[30];
strftime(
waktu,
sizeof(waktu),
"%Y-%m-%d %H:%M:%S",
&timeinfo
);
return String(waktu);
}
void kirimSupabase(float suhu){
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 data = "{";
data += "\"device\":\""+device+"\",";
data += "\"kota\":\""+kota+"\",";
data += "\"suhu\":"+String(suhu)+",";
data += "\"waktu\":\""+getTime()+"\"";
data += "}";
Serial.println(data);
int code=http.POST(data);
Serial.print("Response Supabase : ");
Serial.println(code);
http.end();
}
}
void loop(){
sensors.requestTemperatures();
float suhu = sensors.getTempCByIndex(0);
if(suhu == -127){
Serial.println("Sensor DS18B20 tidak terbaca");
return;
}
Serial.print("Suhu ");
Serial.print(kota);
Serial.print(" : ");
Serial.println(suhu);
kirimSupabase(suhu);
delay(5000);
}
#include <HTTPClient.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <time.h>
// ================= WIFI =================
const char* ssid = "wifihpku";
const char* password = "12345678";
// ================= SUPABASE =================
String supabaseURL =
"https://yizpzxixllbgixxxxxxx.supabase.co/rest/v1/suhu_data";
String supabaseKey =
"sb_publishable_mJNp2PCt9civsxe26URVYg_dxxxxxxx";
// ================= DEVICE =================
// ESP32 pertama
String device = "ESP32_BATANG";
String kota = "Batang";
// ESP32 kedua ubah menjadi:
// String device = "ESP32_SEMARANG";
// String kota = "Semarang";
// ================= DS18B20 =================
#define ONE_WIRE_BUS 13
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
void setup(){
Serial.begin(115200);
sensors.begin();
// WIFI
WiFi.begin(ssid,password);
Serial.print("Connecting");
while(WiFi.status()!=WL_CONNECTED){
delay(500);
Serial.print(".");
}
Serial.println();
Serial.println("WiFi Connected");
// waktu WIB
configTime(
7*3600,
0,
"pool.ntp.org",
"time.nist.gov"
);
}
String getTime(){
struct tm timeinfo;
if(!getLocalTime(&timeinfo)){
return "NULL";
}
char waktu[30];
strftime(
waktu,
sizeof(waktu),
"%Y-%m-%d %H:%M:%S",
&timeinfo
);
return String(waktu);
}
void kirimSupabase(float suhu){
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 data = "{";
data += "\"device\":\""+device+"\",";
data += "\"kota\":\""+kota+"\",";
data += "\"suhu\":"+String(suhu)+",";
data += "\"waktu\":\""+getTime()+"\"";
data += "}";
Serial.println(data);
int code=http.POST(data);
Serial.print("Response Supabase : ");
Serial.println(code);
http.end();
}
}
void loop(){
sensors.requestTemperatures();
float suhu = sensors.getTempCByIndex(0);
if(suhu == -127){
Serial.println("Sensor DS18B20 tidak terbaca");
return;
}
Serial.print("Suhu ");
Serial.print(kota);
Serial.print(" : ");
Serial.println(suhu);
kirimSupabase(suhu);
delay(5000);
}
5. Api.php
<?php
$supabase_url = "https://yizpzxixllbgixxxxxxx.supabase.co/rest/v1/suhu_data";
$supabase_key = "sb_publishable_mJNp2PCt9civsxe26URVYg_dxxxxxxx";
$curl = curl_init();
curl_setopt_array($curl,[
CURLOPT_URL => $supabase_url."?select=*&order=id.desc&limit=100",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"apikey: ".$supabase_key,
"Authorization: Bearer ".$supabase_key,
"Content-Type: application/json"
]
]);
$response = curl_exec($curl);
curl_close($curl);
header("Content-Type: application/json");
echo $response;
?>
$supabase_url = "https://yizpzxixllbgixxxxxxx.supabase.co/rest/v1/suhu_data";
$supabase_key = "sb_publishable_mJNp2PCt9civsxe26URVYg_dxxxxxxx";
$curl = curl_init();
curl_setopt_array($curl,[
CURLOPT_URL => $supabase_url."?select=*&order=id.desc&limit=100",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"apikey: ".$supabase_key,
"Authorization: Bearer ".$supabase_key,
"Content-Type: application/json"
]
]);
$response = curl_exec($curl);
curl_close($curl);
header("Content-Type: application/json");
echo $response;
?>
6. index.php
<!DOCTYPE html>
<html>
<head>
<title>Monitoring Suhu ESP32</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
*{
box-sizing:border-box;
}
body{
margin:0;
font-family:'Segoe UI',Arial,sans-serif;
background:#120021;
color:#ffd700;
}
.header{
background:linear-gradient(135deg,#5a189a,#240046);
padding:25px;
text-align:center;
box-shadow:0 5px 20px #000;
}
.header h1{
margin:0;
font-size:34px;
}
.header p{
color:#fff3a0;
}
.container{
width:92%;
margin:auto;
}
.map-box{
margin-top:25px;
background:#240046;
padding:25px;
border-radius:25px;
box-shadow:0 0 20px #000;
text-align:center;
}
.map-box h2{
color:#ffd700;
}
.peta{
width:90%;
max-width:1000px;
height:260px;
object-fit:cover;
border-radius:20px;
border:3px solid #7b2cbf;
}
.cards{
display:grid;
grid-template-columns:repeat(2,1fr);
gap:25px;
margin-top:25px;
}
.card{
background:#240046;
padding:25px;
border-radius:25px;
text-align:center;
box-shadow:0 0 20px #000;
}
.card h2{
color:#ffd700;
}
.nilai{
font-size:70px;
font-weight:bold;
color:#ffd700;
}
.status{
color:#00ff99;
font-weight:bold;
}
.panel{
background:#240046;
margin-top:25px;
padding:25px;
border-radius:25px;
box-shadow:0 0 20px #000;
}
.chart{
height:400px;
}
canvas{
width:100%!important;
height:100%!important;
}
table{
width:100%;
border-collapse:collapse;
}
th{
background:#5a189a;
color:#ffd700;
}
td,th{
padding:12px;
text-align:center;
border-bottom:1px solid #7b2cbf;
}
tr:hover{
background:#3c096c;
}
@media(max-width:700px){
.cards{
grid-template-columns:1fr;
}
}
</style>
</head>
<body>
<div class="header">
<h1>🌡 MONITORING SUHU ESP32</h1>
<p>DS18B20 Temperature Sensor</p>
</div>
<div class="container">
<!-- PETA -->
<div class="map-box">
<h2>🗺 PETA JAWA</h2>
<img src="jawa-map.png" class="peta">
</div>
<!-- NILAI SUHU -->
<div class="cards">
<div class="card">
<h2>📍 ESP32 BATANG</h2>
<div id="batang" class="nilai">
-- °C
</div>
<div class="status">
● ONLINE
</div>
</div>
<div class="card">
<h2>📍 ESP32 SEMARANG</h2>
<div id="semarang" class="nilai">
-- °C
</div>
<div class="status">
● ONLINE
</div>
</div>
</div>
<!-- GRAFIK -->
<div class="panel">
<h2>📈 Grafik Suhu Batang</h2>
<div class="chart">
<canvas id="grafikBatang"></canvas>
</div>
</div>
<div class="panel">
<h2>📈 Grafik Suhu Semarang</h2>
<div class="chart">
<canvas id="grafikSemarang"></canvas>
</div>
</div>
<!-- LOGGER -->
<div class="panel">
<h2>📋 Logger Data 100 Terakhir</h2>
<table>
<tr>
<th>No</th>
<th>Device</th>
<th>Kota</th>
<th>Suhu</th>
<th>Waktu</th>
</tr>
<tbody id="logger"></tbody>
</table>
</div>
</div>
<script>
let chartBatang;
let chartSemarang;
function loadData(){
fetch("api.php")
.then(res=>res.json())
.then(data=>{
let batang=[];
let semarang=[];
let waktuBatang=[];
let waktuSemarang=[];
let suhuBatang=0;
let suhuSemarang=0;
let idBatang=0;
let idSemarang=0;
data.slice().reverse().forEach(item=>{
if(item.device=="ESP32_BATANG"){
batang.push(Number(item.suhu));
waktuBatang.push(item.waktu);
if(Number(item.id)>idBatang){
idBatang=item.id;
suhuBatang=item.suhu;
}
}
if(item.device=="ESP32_SEMARANG"){
semarang.push(Number(item.suhu));
waktuSemarang.push(item.waktu);
if(Number(item.id)>idSemarang){
idSemarang=item.id;
suhuSemarang=item.suhu;
}
}
});
document.getElementById("batang").innerHTML =
Number(suhuBatang).toFixed(2)+" °C";
document.getElementById("semarang").innerHTML =
Number(suhuSemarang).toFixed(2)+" °C";
if(chartBatang){
chartBatang.destroy();
}
chartBatang=new Chart(
document.getElementById("grafikBatang"),
{
type:"line",
data:{
labels:waktuBatang,
datasets:[{
label:"ESP32 BATANG",
data:batang,
borderColor:"#ffd700",
backgroundColor:"rgba(255,215,0,0.2)",
fill:true,
tension:0.4,
borderWidth:3
}]
},
options:{
responsive:true,
maintainAspectRatio:false
}
}
);
if(chartSemarang){
chartSemarang.destroy();
}
chartSemarang=new Chart(
document.getElementById("grafikSemarang"),
{
type:"line",
data:{
labels:waktuSemarang,
datasets:[{
label:"ESP32 SEMARANG",
data:semarang,
borderColor:"#00ffff",
backgroundColor:"rgba(0,255,255,0.2)",
fill:true,
tension:0.4,
borderWidth:3
}]
},
options:{
responsive:true,
maintainAspectRatio:false
}
}
);
let html="";
data.forEach((item,index)=>{
html+=`
<tr>
<td>${index+1}</td>
<td>${item.device}</td>
<td>${item.kota}</td>
<td>${item.suhu} °C</td>
<td>${item.waktu}</td>
</tr>
`;
});
document.getElementById("logger").innerHTML=html;
});
}
loadData();
setInterval(loadData,5000);
</script>
</body>
</html>
<html>
<head>
<title>Monitoring Suhu ESP32</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
*{
box-sizing:border-box;
}
body{
margin:0;
font-family:'Segoe UI',Arial,sans-serif;
background:#120021;
color:#ffd700;
}
.header{
background:linear-gradient(135deg,#5a189a,#240046);
padding:25px;
text-align:center;
box-shadow:0 5px 20px #000;
}
.header h1{
margin:0;
font-size:34px;
}
.header p{
color:#fff3a0;
}
.container{
width:92%;
margin:auto;
}
.map-box{
margin-top:25px;
background:#240046;
padding:25px;
border-radius:25px;
box-shadow:0 0 20px #000;
text-align:center;
}
.map-box h2{
color:#ffd700;
}
.peta{
width:90%;
max-width:1000px;
height:260px;
object-fit:cover;
border-radius:20px;
border:3px solid #7b2cbf;
}
.cards{
display:grid;
grid-template-columns:repeat(2,1fr);
gap:25px;
margin-top:25px;
}
.card{
background:#240046;
padding:25px;
border-radius:25px;
text-align:center;
box-shadow:0 0 20px #000;
}
.card h2{
color:#ffd700;
}
.nilai{
font-size:70px;
font-weight:bold;
color:#ffd700;
}
.status{
color:#00ff99;
font-weight:bold;
}
.panel{
background:#240046;
margin-top:25px;
padding:25px;
border-radius:25px;
box-shadow:0 0 20px #000;
}
.chart{
height:400px;
}
canvas{
width:100%!important;
height:100%!important;
}
table{
width:100%;
border-collapse:collapse;
}
th{
background:#5a189a;
color:#ffd700;
}
td,th{
padding:12px;
text-align:center;
border-bottom:1px solid #7b2cbf;
}
tr:hover{
background:#3c096c;
}
@media(max-width:700px){
.cards{
grid-template-columns:1fr;
}
}
</style>
</head>
<body>
<div class="header">
<h1>🌡 MONITORING SUHU ESP32</h1>
<p>DS18B20 Temperature Sensor</p>
</div>
<div class="container">
<!-- PETA -->
<div class="map-box">
<h2>🗺 PETA JAWA</h2>
<img src="jawa-map.png" class="peta">
</div>
<!-- NILAI SUHU -->
<div class="cards">
<div class="card">
<h2>📍 ESP32 BATANG</h2>
<div id="batang" class="nilai">
-- °C
</div>
<div class="status">
● ONLINE
</div>
</div>
<div class="card">
<h2>📍 ESP32 SEMARANG</h2>
<div id="semarang" class="nilai">
-- °C
</div>
<div class="status">
● ONLINE
</div>
</div>
</div>
<!-- GRAFIK -->
<div class="panel">
<h2>📈 Grafik Suhu Batang</h2>
<div class="chart">
<canvas id="grafikBatang"></canvas>
</div>
</div>
<div class="panel">
<h2>📈 Grafik Suhu Semarang</h2>
<div class="chart">
<canvas id="grafikSemarang"></canvas>
</div>
</div>
<!-- LOGGER -->
<div class="panel">
<h2>📋 Logger Data 100 Terakhir</h2>
<table>
<tr>
<th>No</th>
<th>Device</th>
<th>Kota</th>
<th>Suhu</th>
<th>Waktu</th>
</tr>
<tbody id="logger"></tbody>
</table>
</div>
</div>
<script>
let chartBatang;
let chartSemarang;
function loadData(){
fetch("api.php")
.then(res=>res.json())
.then(data=>{
let batang=[];
let semarang=[];
let waktuBatang=[];
let waktuSemarang=[];
let suhuBatang=0;
let suhuSemarang=0;
let idBatang=0;
let idSemarang=0;
data.slice().reverse().forEach(item=>{
if(item.device=="ESP32_BATANG"){
batang.push(Number(item.suhu));
waktuBatang.push(item.waktu);
if(Number(item.id)>idBatang){
idBatang=item.id;
suhuBatang=item.suhu;
}
}
if(item.device=="ESP32_SEMARANG"){
semarang.push(Number(item.suhu));
waktuSemarang.push(item.waktu);
if(Number(item.id)>idSemarang){
idSemarang=item.id;
suhuSemarang=item.suhu;
}
}
});
document.getElementById("batang").innerHTML =
Number(suhuBatang).toFixed(2)+" °C";
document.getElementById("semarang").innerHTML =
Number(suhuSemarang).toFixed(2)+" °C";
if(chartBatang){
chartBatang.destroy();
}
chartBatang=new Chart(
document.getElementById("grafikBatang"),
{
type:"line",
data:{
labels:waktuBatang,
datasets:[{
label:"ESP32 BATANG",
data:batang,
borderColor:"#ffd700",
backgroundColor:"rgba(255,215,0,0.2)",
fill:true,
tension:0.4,
borderWidth:3
}]
},
options:{
responsive:true,
maintainAspectRatio:false
}
}
);
if(chartSemarang){
chartSemarang.destroy();
}
chartSemarang=new Chart(
document.getElementById("grafikSemarang"),
{
type:"line",
data:{
labels:waktuSemarang,
datasets:[{
label:"ESP32 SEMARANG",
data:semarang,
borderColor:"#00ffff",
backgroundColor:"rgba(0,255,255,0.2)",
fill:true,
tension:0.4,
borderWidth:3
}]
},
options:{
responsive:true,
maintainAspectRatio:false
}
}
);
let html="";
data.forEach((item,index)=>{
html+=`
<tr>
<td>${index+1}</td>
<td>${item.device}</td>
<td>${item.kota}</td>
<td>${item.suhu} °C</td>
<td>${item.waktu}</td>
</tr>
`;
});
document.getElementById("logger").innerHTML=html;
});
}
loadData();
setInterval(loadData,5000);
</script>
</body>
</html>


No comments:
Post a Comment