Embedded System Project 10: ESP32 with Data Visualization

Fikri Naufal Hamdi
7 min readMay 7, 2023

--

Halo, semuanya!
Kembali lagi dalam rangkaian project ESP32, kali ini aku ingin melanjutkan project sebelumnya terkait penyimpanan data hasil pembacaan sensor BMP280 dari ESP32 pada MySQL database. Namun, pada project ini kita akan menampilkan data tersebut dengan visualisasi yang lebih menarik dan intuitif. Langsung saja kita mulai!

— Objective

Tujuan dari project 10 ini adalah menampilkan data hasil pembacaan sensor yang tersimpan pada database dengan visualisasi yang lebih menarik dan intuitif.

— Requirements

Beberapa tools yang perlu disiapkan untuk memulai project ini adalah

  • Microcontroller ESP32 Devkit V1
  • Kabel data (USB Type A to Micro USB)
  • Arduino IDE yang terinstall pada Laptop/PC
  • Kabel jumper Male to Male
  • Sensor BMP280
  • Breadboard
  • Hosting server dan nama domain
  • PHP script untuk insert data ke MySQL dan penampilannya
  • MySQL database untuk menyimpan data hasil pembacaan sensor

— Steps

Secara umum, project kali ini hampir sama dengan project 09 sebelumnya. Hal yang membedakan hanya pada visualisasi data yang ditampilkan. Skema high-level dari project kali ini sebagai berikut.

Source: https://randomnerdtutorials.com/visualize-esp32-esp8266-sensor-readings-from-anywhere/

Dalam project ini, aku masih menggunakan web hosting dan domain yang sama seperti project sebelumnya, yaitu pada 000webhost. Selain itu, kita juga perlu menyiapkan MySQL database dan PHP script untuk HTTP POST yang akan melakukan inserting data pembacaan sensor pada MySQL database.

Apabila belum melakukan tahap tersebut, project 09 sebelumnya akan menuntun dan menjelaskan proses-proses dari tahap tersebut. Karena tahap tersebut sudah dilakukan pada project sebelumnya, aku akan langsung ke tahap berikutnya.

  • Selanjutnya, kita akan membuat PHP script untuk visualisasi data pada database dalam bentuk chart. Untuk melakukannya, masuk ke dalam folder ‘public_html’ dan buat file php baru, misalnya ‘esp-chart.php’.
Pembuatan PHP script baru untuk visualisasi
  • Setelah itu, salin PHP script berikut ke dalam file yang baru dibuat sebelumnya.
<!--
This code references to: Rui Santos
Complete project details at https://RandomNerdTutorials.com

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

-->
<?php

$servername = "localhost";

// REPLACE with your Database name
$dbname = "REPLACE_WITH_YOUR_DATABASE_NAME";
// REPLACE with Database user
$username = "REPLACE_WITH_YOUR_USERNAME";
// REPLACE with Database user password
$password = "REPLACE_WITH_YOUR_PASSWORD";

// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$sql = "SELECT id, value1, value2, value3, reading_time FROM SensorData order by reading_time desc limit 40";
$result = $conn->query($sql) or die($conn->error);
while ($data = $result->fetch_assoc()){
$sensor_data[] = $data;
}
$readings_time = array_column($sensor_data, 'reading_time');
$i = 0;
foreach ($readings_time as $reading){
$readings_time[$i] = date("Y-m-d H:i:s", strtotime("$reading + 7 hours")); //convert timezone to +7
$i += 1;
}
$value1 = json_encode(array_reverse(array_column($sensor_data, 'value1')), JSON_NUMERIC_CHECK);
$value2 = json_encode(array_reverse(array_column($sensor_data, 'value2')), JSON_NUMERIC_CHECK);
$value3 = json_encode(array_reverse(array_column($sensor_data, 'value3')), JSON_NUMERIC_CHECK);
$reading_time = json_encode(array_reverse($readings_time), JSON_NUMERIC_CHECK);
/*echo $value1;
echo $value2;
echo $value3;
echo $reading_time;*/
$result->free();
$conn->close();
?>
<!DOCTYPE html>
<html>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://code.highcharts.com/highcharts.js"></script>
<style>
body {
min-width: 310px;
max-width: 1280px;
height: 500px;
margin: 0 auto;
}
h2 {
font-family: Arial;
font-size: 2.5rem;
text-align: center;
}
</style>
<body>
<h2>ESP Weather Station</h2>
<div id="chart-temperature" class="container"></div>
<div id="chart-approximate-altitude" class="container"></div>
<div id="chart-pressure" class="container"></div>
<script>
var value1 = <?php echo $value1; ?>;
var value2 = <?php echo $value2; ?>;
var value3 = <?php echo $value3; ?>;
var reading_time = <?php echo $reading_time; ?>;
var chartT = new Highcharts.Chart({
chart:{ renderTo : 'chart-temperature' },
title: { text: 'BMP280 Temperature' },
series: [{
showInLegend: false,
data: value1
}],
plotOptions: {
line: { animation: false,
dataLabels: { enabled: true }
},
series: { color: '#059e8a' }
},
xAxis: {
type: 'datetime',
categories: reading_time
},
yAxis: {
title: { text: 'Temperature (Celsius)' }
//title: { text: 'Temperature (Fahrenheit)' }
},
credits: { enabled: false }
});
var chartH = new Highcharts.Chart({
chart:{ renderTo:'chart-pressure' },
title: { text: 'BMP280 Pressure' },
series: [{
showInLegend: false,
data: value2
}],
plotOptions: {
line: { animation: false,
dataLabels: { enabled: true }
}
},
xAxis: {
type: 'datetime',
//dateTimeLabelFormats: { second: '%H:%M:%S' },
categories: reading_time
},
yAxis: {
title: { text: 'Pressure (Pa)' }
},
credits: { enabled: false }
});
var chartP = new Highcharts.Chart({
chart:{ renderTo:'chart-approximate-altitude' },
title: { text: 'BMP280 Approximate Altitude' },
series: [{
showInLegend: false,
data: value3
}],
plotOptions: {
line: { animation: false,
dataLabels: { enabled: true }
},
series: { color: '#18009c' }
},
xAxis: {
type: 'datetime',
categories: reading_time
},
yAxis: {
title: { text: 'Approximate Altitude (m)' }
},
credits: { enabled: false }
});
</script>
</body>
</html>
  • Jangan lupa untuk mengubah nama, username, dan password dari database sesuai yang sudah dibuat.
// Your Database name 
$dbname = "example_esp_data";
// Your Database user
$username = "example_esp_board";
// Your Database user password
$password = "YOUR_USER_PASSWORD";
  • Jika sudah menyimpan file PHP script yang akan membuat visualisasi datanya, buat lagi rangkaian ESP32 seperti project sebelumnya. Skema rangkaiannya sebagai berikut.
Schematic Rangkaian
  • Lalu, upload code ESP32 yang juga sama seperti project sebelumnya. Dengan itu, ESP32 akan mengirimkan kembali hasil pembacaan sensor dari BMP280 menuju database dan kemudian akan divisualisasikan oleh PHP script terbaru yang sudah dibuat.

Berikut adalah code untuk rangkaian ESP32.

/*
This code references to: Rui Santos
Complete project details at https://RandomNerdTutorials.com/esp32-esp8266-mysql-database-php/

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*/
#include <WiFi.h>
#include <HTTPClient.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP280.h>
// Replace with your network credentials
const char* ssid = "Realme GT Master Edition";
const char* password = "rizasatria123";
// REPLACE with your Domain name and URL path or IP address with path
const char* serverName = "https://fiknaufalh-emsys.000webhostapp.com/post-esp-data.php";
// Keep this API Key value to be compatible with the PHP code provided in the project page.
// If you change the apiKeyValue value, the PHP file /post-esp-data.php also needs to have the same key
String apiKeyValue = "tPmAT5Ab3j7F9";
String sensorName = "BMP280";
String sensorLocation = "Office";
#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BMP280 bmp; // I2C
//Adafruit_BMP280 bmp(BMP_CS); // hardware SPI
//Adafruit_BMP280 bmp(BMP_CS, BMP_MOSI, BMP_MISO, BMP_SCK);
void setup() {
Serial.begin(115200);

WiFi.begin(ssid, password);
Serial.println("Connecting");
while(WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to WiFi network with IP Address: ");
Serial.println(WiFi.localIP());
// (you can also pass in a Wire library object like &Wire2)
bool status = bmp.begin(0x76);
if (!status) {
Serial.println("Could not find a valid BMP280 sensor, check wiring or change I2C address!");
while (1);
}
}
void loop() {
//Check WiFi connection status
if(WiFi.status()== WL_CONNECTED){
HTTPClient http;

// Your Domain name with URL path or IP address with path
http.begin(serverName);

// Specify content-type header
http.addHeader("Content-Type", "application/x-www-form-urlencoded");

// Prepare your HTTP POST request data
String httpRequestData = "api_key=" + apiKeyValue + "&sensor=" + sensorName
+ "&location=" + sensorLocation + "&value1=" + String(bmp.readTemperature())
+ "&value2=" + String(bmp.readPressure()) + "&value3=" + String((bmp.readAltitude(SEALEVELPRESSURE_HPA))) + "";
Serial.print("httpRequestData: ");
Serial.println(httpRequestData);

// You can comment the httpRequestData variable above
// then, use the httpRequestData variable below (for testing purposes without the BMP280 sensor)
//String httpRequestData = "api_key=tPmAT5Ab3j7F9&sensor=BMP280&location=Office&value1=24.75&value2=49.54&value3=1005.14";
// Send HTTP POST request
int httpResponseCode = http.POST(httpRequestData);

// If you need an HTTP request with a content type: text/plain
//http.addHeader("Content-Type", "text/plain");
//int httpResponseCode = http.POST("Hello, World!");

// If you need an HTTP request with a content type: application/json, use the following:
//http.addHeader("Content-Type", "application/json");
//int httpResponseCode = http.POST("{\"value1\":\"19\",\"value2\":\"67\",\"value3\":\"78\"}");

if (httpResponseCode>0) {
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
}
else {
Serial.print("Error code: ");
Serial.println(httpResponseCode);
}
// Free resources
http.end();
}
else {
Serial.println("WiFi Disconnected");
}
//Send an HTTP POST request every 30 seconds (30.000 mili seconds)
delay(30000);
}

— Result

Tada! Sekarang data yang ada di database dapat ditampilkan dengan lebih menarik dan intuitif, sehingga kita dapat mengetahui pergerakan dari pembacaan sensor dengan baik.

Visualisasi Data Temperatur
Visualisasi Data Estimasi Ketinggian dan Tekanan

Itu dia untuk project 10kali ini, stay tune untuk project berikutnya :D

--

--