webserver + ajax dengan Nodemcu (esp8266) (aplikasi monitoring suhu dan kelembaban)

Monitoring atau kegiatan pemantauan bisa dilakukan dari jarak jauh melalui sistem komunikasi internet maupun metode komunikasi lainnya. Salah satu unsur monitoring data adalah display atau tampilan dimana beberapa aspek yang perlu diperhatikan adalah :

  1. Informatif, data yang ditampilkan mampu memberikan perspektif kondisi yang ada, sebagai contoh tampilan grafik: selain menunjukkan data juga akan memberikan gambaran pergerakan dari data-data sebelumnya (naik/turun).
  2. Real time. yaitu datayang tampil merupakan data lapangan saat ini dan terus diperbaharui dalam frekuensi tertentu dimana semakin besar akan semakin realtime.
  3. Bandwidth, adalah besarnya lalu lintas data yang terpakai oleh aktifitas monitoring, jadi sistem yang baik perlu mempertimbangkan metode lalu lintas data sekecil mungkin tanpa mengurangi aspek lainnya.
  4. Kenyamanan, berkaitan dengan design dan pola dinamik tampilan saat perubahan data.

Ajax

Asynchronous Javascript and XML (Ajax) adalah metode lalu lintas data web secara asynchronous (dibelakang layar) antara interface web (browser) dengan server yang bertujuan memberikan fitur interaktif kepada pengguna.

penggunaan ajax memungkinkan update data fleksibel tanpa perlu melakukan aksi (menekan tombl update) atau refresh halaman web.

Tampilan monitoring suhu dan kelembaban menggunakan nodemcu:

Komponen yang digunakan dalam perancangan monitoring suhu dan kelembaban berbasis webserver nodemcu :

  1. Nodemcu
  2. DHT11

Skema ajax webserver dengan nodemcu:

Sketch/program webserver nodemcu dengan ajax relatime:

#define jumlahData        5
#define hotspotSSID       "XXXXXXXX"
#define hotspotPassword   "XXXXXXXX"
#define pinDHT            D4

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>

#include <dht.h>

dht DHT;

ESP8266WebServer server(80);

struct Data
{
  uint32_t index;
  float temperatur;
  float kelembaban;
};

Data data[jumlahData];
byte ringIndex;
uint32_t indexDataDHT;
long millisBacaSensor;

void handleRoot() {
  char buffer[] =
    "<html><head>"
    "  <title>Temperatur dan Kelembaban</title>"
    "  <meta charset='UTF-8'>"
    "  <script src='https://code.highcharts.com/highcharts.js'></script>"
    "</head>"
    "<body>"
    "  <center>"
    "    <h1>Temperatur dan Kelembaban</h1>"
    "    <h2>Grafik Temperatur dan Kelembaban</h2>"
    "    <div id='grafik' style='height:400px;'></div>"
    "  </center>"
    "<script type='text/javascript'>"
    "  var timerId = setInterval('updateGrafik()', 1000);"
    "  var grafik = Highcharts.chart('grafik', {"
    "    title: {text: ''},"
    "    xAxis: {title: {text: 'index'},categories: [],rotation:90,},"
    "    yAxis: ["
    "      {labels: {format: '{value} °C',style: {color: Highcharts.getOptions().colors[1]}},title: {text: 'Temperatur'},},"
    "      {labels: {format: '{value} %',style: {color: Highcharts.getOptions().colors[1]}},title: {text: 'Kelembaban'},opposite: true,}, ],"
    "    credits: {enabled: false},"
    "    series: ["
    "      {name: 'Temperatur',yAxis: 0,data: []}, "
    "      {name: 'Kelembaban',yAxis: 1,data: []}, ]"
    "  });"
    "  function updateGrafik(){"
    "    var xhttp = new XMLHttpRequest();"
    "    xhttp.onreadystatechange = function() {"
    "      if (this.readyState == 4 && this.status == 200) {"
    "        eval(this.responseText.trim());}};"
    "    xhttp.open('GET', '/updateData', true);"
    "    xhttp.send(); }"
    "</script>"
    "</body></html>";
  server.send(200, "text/html", buffer);
}

void handleNotFound()
{
  server.send(404, "text/plain", "Alamat tidak ditemukan");
}

void updateData()
{
  char buffer[1000];
  byte index;

  strcpy(buffer, "grafik.xAxis[0].setCategories([");

  index = ringIndex;
  for (byte i = 0; i < jumlahData; i++)
  {
    sprintf(&buffer[strlen(buffer)], "%lu,", data[index].index);
    index++;
    index %= jumlahData;
  }
  strcpy(&buffer[strlen(buffer)], "]);");

  strcpy(&buffer[strlen(buffer)], "grafik.series[0].setData([");
  index = ringIndex;
  for (byte i = 0; i < jumlahData; i++)
  {
    dtostrf(data[index].temperatur, 8, 2, &buffer[strlen(buffer)]);
    strcpy(&buffer[strlen(buffer)], ",");
    index++;
    index %= jumlahData;
  }
  strcpy(&buffer[strlen(buffer)], "]);");

  strcpy(&buffer[strlen(buffer)], "grafik.series[1].setData([");
  index = ringIndex;
  for (byte i = 0; i < jumlahData; i++)
  {
    dtostrf(data[index].kelembaban, 8, 2, &buffer[strlen(buffer)]);
    strcpy(&buffer[strlen(buffer)], ",");
    index++;
    index %= jumlahData;
  }
  strcpy(&buffer[strlen(buffer)], "]);");

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

}


void setup(void) {
  Serial.begin(9600);
  Serial.println("Web server dengan fitur ajax menggunakan nodemcu (aplikasi monitor suhu dan kelembaban)");
  Serial.println("https://www.project.semesin.com");
  
  WiFi.mode(WIFI_STA);
  WiFi.begin(hotspotSSID, hotspotPassword);
  Serial.println("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(hotspotSSID);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  server.on("/", handleRoot);
  server.on("/updateData", updateData);
  server.onNotFound(handleNotFound);

  server.begin();
  Serial.println("HTTP server started");
}

void loop(void) {
  server.handleClient();

  if (millisBacaSensor < millis())
  {
    millisBacaSensor = millis() + 1000;

    if (DHT.read11(pinDHT) == DHTLIB_OK)
    {
      data[ringIndex].index = indexDataDHT;
      data[ringIndex].temperatur = DHT.temperature;
      data[ringIndex].kelembaban = DHT.humidity;

      indexDataDHT++;

      ringIndex++;
      ringIndex %= jumlahData;
    }
  }
}

Library:

Mengirim data detektor kebakaran dari arduino ke internet dengan antarmuka code igniter

Data sensor arduino

Sensor adalah instrumen atau komponen yang mampu mendeteksi perubahan kondisi objek dalam jangkauannya. Pengukuran besaran perubahan tersebut harus diubah dahulu menjadi bentuk digital sehingga dapat diproses oleh perangkat digital lainnya.

Data variabel ini bisa dimonitoring secara lokal melalui layar monitor maupun global melalui internet.

Hal yang mendukung keandalan sistem monitoring :

  1. realtime, yaitu data yang ditampilkan merupakan kondisi masa yang singkat, misalnya di perbarui setiap 1 detik.
  2. Data memiliki identitas seperti lokasi, waktu.
  3. Data yang diterima memiliki mekanisme penyaringan sehingga data yang ditampilkan terjamin.

Sensor detektor kebakaran

Terdapat beberapa Indikasi kebakaran yaitu :

  1. Api dideteksi dengan sensor flame
  2. Suhu dibaca dengan sensor suhu
  3. Asap dibaca dengan sensor asap (smoke detector)

Dalam hal pencegahan kebakaran, ketiga variabel ini terus menerus dimonitoring secara lokal.

Monitoring detektor kebakaran ini secara global juga diperlukan untuk memberikan informasi kepada pihak terkait.

Dalam contoh ini ketiga (modul) sensor ini digunakan bersama arduino dan akan dikirimkan ke mysql server.

Akses informasi sensor dengan codeIgniter

Informasi data saat ini dapat dengan mudah diakses dimanapun, namun dengan menggunakan codeIgniter diperoleh beberapa keuntungan yaitu :

  1. Pengembangan lebih mudah dengan baris program yang dapat disederhanakan.
  2. Aksesibilitas dapat dengan mudah dikontrol.
  3. Perlindungan terhadap server terutama server data lebih terjamin.

Skema Monitoring detektor kebakaran dengan codeIgniter

Komponen yang digunakan :

  1. Arduino Uno
  2. ESP8266
  3. Flame detector
  4. Sensor asap MQ7
  5. Sensor suhu dht11
  6. Relay
  7. Buzzer

Sketch / koding monitoring detektor kebakaran esp8266 – WebServer.

#include "WiFiEsp.h"
#include <SoftwareSerial.h>
#include "DHT.h"
 
char ssid[] = "****";        // Isi dengan nama profil Wifi
char pass[] = "********";            // password wifi
char server[] = "x.x.x.x";

long waktuMintaData = 1000; //minta data setiap 1000ms

#define pinFlame    A0
#define pinMQ       A1
#define pinDHT      A2
#define pinBuzzer   8
#define pinRelay    9

float setSuhu = 31.0;

String Respon = "";
long waktuMulai;
bool responDariServer = false;
bool prosesKirimDataKeServer = false;
 
WiFiEspClient client;
int status = WL_IDLE_STATUS;

SoftwareSerial wifi(2,3);
DHT dht(pinDHT, DHT11);
 
void setup()
{
  pinMode(pinFlame, INPUT_PULLUP);
  pinMode(pinMQ, INPUT_PULLUP);
  pinMode(pinDHT, INPUT_PULLUP);
  pinMode(pinBuzzer, OUTPUT);
  digitalWrite(pinRelay, HIGH);
  pinMode(pinRelay, OUTPUT);

  Serial.begin(115200);
 
  wifi.begin(115200);
  WiFi.init(&wifi);
 
  // check for the presence of the shield
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // don't continue
    while (true);
  }
 
  // attempt to connect to WiFi network
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to WPA SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network
    status = WiFi.begin(ssid, pass);
  }
 
  // you're connected now, so print out the data
  Serial.println("You're connected to the network");
   
  printWifiStatus();
  dht.begin();
  waktuMulai = millis();
}
 
void loop()
{
  float suhu = dht.readTemperature();
//print status
  Serial.println();
  Serial.print("Api = ");
  Serial.println(digitalRead(pinFlame));
  Serial.print("Asap = ");
  Serial.println(digitalRead(pinMQ));
  Serial.print("suhu = ");
  Serial.println(suhu);
  
  if(!digitalRead(pinFlame) && !digitalRead(pinMQ) && (suhu < setSuhu))
  {
    digitalWrite(pinRelay, HIGH);
    digitalWrite(pinBuzzer, LOW);
    
  }
  if(digitalRead(pinFlame))
  {
    digitalWrite(pinRelay, LOW);
    digitalWrite(pinBuzzer, HIGH);
  }
  if(digitalRead(pinMQ))
  {
    digitalWrite(pinRelay, LOW);
    digitalWrite(pinBuzzer, HIGH);
  }
  if(suhu >= setSuhu)
  {
    digitalWrite(pinBuzzer, HIGH);
  }
  //kirim data
  if(waktuMintaData < millis() - waktuMulai)
  {
    waktuMulai = millis();
    prosesKirimDataKeServer = kirimDataKeServer();
  }

  while (client.available()) 
  {
    char c = client.read();
    Respon += c;
  }

  Serial.print("prosesKirimDataKeServer = ");
  Serial.println(prosesKirimDataKeServer);

  if (!client.connected() && prosesKirimDataKeServer) {
    Serial.println("Disconnecting from server...");
    client.stop();
    responDariServer = true;
    prosesKirimDataKeServer = false;
  }

  // penanganan data yang diterima dari server
  if(responDariServer)
  {
    responDariServer = false;
    Serial.println(Respon);
    int posisiData = Respon.indexOf("\r\n\r\n");
    String Data = Respon.substring(posisiData+4);
    Data.trim();
 
    String variabel;
    String nilai;
 
    Serial.println("Data dari server");
    posisiData = Data.indexOf('=');
    if(posisiData > 0)
    {
      variabel = Data.substring(0,posisiData);
      nilai = Data.substring(posisiData+1);
   
      //===========Penanganan respon disini
      if(variabel == "setSuhu")
      {
        setSuhu = nilai.toFloat();
      }
//      Serial.print(variabel);
//      Serial.print(" = ");
//      Serial.println(nilai);
    }
    Respon = "";
  }
}

bool kirimDataKeServer()
{
  Serial.println();
  Serial.println("Starting connection to server...");
  // if you get a connection, report back via serial
  if (client.connect(server, 80)) {
    Serial.println("Connected to server");
    // Make a HTTP request
 
    client.print("GET /index.php/databaseArduino/dariArduino");
    client.print("?Api=");
    client.print(digitalRead(pinFlame));
     
    client.print("&Asap=");
    client.print(digitalRead(pinMQ));

    client.print("&Suhu=");
    client.print(dht.readTemperature());
     
    client.println(" HTTP/1.1");
    client.print("Host: ");
    client.println(server);
    client.println("Connection: close");
    client.println();
    return true;
  }
  return false;
}
 
void printWifiStatus()
{
  // print the SSID of the network you're attached to
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());
 
  // print your WiFi shield's IP address
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);
 
  // print the received signal strength
  long rssi = WiFi.RSSI();
  Serial.print("Signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
 
  IPAddress gateway = WiFi.gatewayIP();
  Serial.print("gateway:");
  Serial.print(gateway);
  Serial.println(" ");
}

program codeIgniter untuk monitoring data sensor arduino:

databaseArduino.php

<?php
class databaseArduino extends CI_Controller {
  public function __construct() {
    parent::__construct();
  }

  public function dariBrowser() {
    $this->load->model('Model_databaseArduino');
    $this->Model_databaseArduino->salinDataDariBrowser();
    $data['dataSensor'] = $this->Model_databaseArduino->ambilDataDariArduino();
    $data['dataParameter'] = $this->Model_databaseArduino->ambilDataDariBrowser();

    $this->load->view("data_sensor", $data);
  }

    public function dariArduino() {
    $this->load->model('Model_databaseArduino');
    $this->Model_databaseArduino->salinDataDariArduino();
    $data['dataParameter'] = $this->Model_databaseArduino->ambilDataDariBrowser();

    $this->load->view("data_parameter", $data);
  }
}
?>

Model_databaseArduino.php

<?php
class Model_databaseArduino extends CI_Model {

  public $title;
  public $content;
  public $date;

  public function ambilDataDariArduino()
  {
    $this->load->database();
    $query = $this->db->query("SELECT * FROM (
    SELECT * FROM `data_sensor` ORDER BY `nomor` DESC LIMIT 10
    ) sub
    ORDER BY `nomor` ASC");
    $this->db->close();  
    return $query->result();
  }

  public function salinDataDariArduino()
  {
    date_default_timezone_set('Asia/Jakarta'); # add your city to set local time zone
    $now = date('Y-m-d H:i:s');

    $this->load->database();
    $this->db->set('waktu', $now);
    $this->db->set('api', $this->input->get('Api'));
    $this->db->set('asap', $this->input->get('Asap'));
    $this->db->set('suhu', $this->input->get('Suhu'));
    $this->db->insert('data_sensor');
    $this->db->close();
  }

  public function ambilDataDariBrowser()
  {
    $this->load->database();
    $query = $this->db->query("SELECT * FROM `data_parameter` ORDER BY `nomor` DESC LIMIT 1");
    $this->db->close();  
    return $query->row();
  }

  public function salinDataDariBrowser()
  {
    date_default_timezone_set('Asia/Jakarta'); # add your city to set local time zone
    $now = date('Y-m-d H:i:s');

    $this->load->database();
    $this->db->set('waktu', $now);
    $this->db->set('setSuhu', $this->input->post('setSuhu'));
    $this->db->insert('data_parameter');
    $this->db->close();  
  }
}
?>

data_sensor.php

<?php
  defined('BASEPATH') OR exit('No direct script access allowed');

  if(isset($dataParameter))
  {
    echo "setSuhu=";
    echo $dataParameter->setSuhu;
  }
?>

data_parameter.php

<?php
defined('BASEPATH') OR exit('No direct script access allowed');
?>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Welcome to CodeIgniter</title>

  <style type="text/css">

  ::selection { background-color: #E13300; color: white; }
  ::-moz-selection { background-color: #E13300; color: white; }

  body {
    background-color: #fff;
    margin: 40px;
    font: 13px/20px normal Helvetica, Arial, sans-serif;
    color: #4F5155;
  }

  a {
    color: #003399;
    background-color: transparent;
    font-weight: normal;
  }

  h1 {
    color: #444;
    background-color: transparent;
    border-bottom: 1px solid #D0D0D0;
    font-size: 19px;
    font-weight: normal;
    margin: 0 0 14px 0;
    padding: 14px 15px 10px 15px;
  }

  code {
    font-family: Consolas, Monaco, Courier New, Courier, monospace;
    font-size: 12px;
    background-color: #f9f9f9;
    border: 1px solid #D0D0D0;
    color: #002166;
    display: block;
    margin: 14px 0 14px 0;
    padding: 12px 10px 12px 10px;
  }

  #body {
    margin: 0 15px 0 15px;
  }

  p.footer {
    text-align: right;
    font-size: 11px;
    border-top: 1px solid #D0D0D0;
    line-height: 32px;
    padding: 0 10px 0 10px;
    margin: 20px 0 0 0;
  }

  #container {
    margin: 10px;
    border: 1px solid #D0D0D0;
    box-shadow: 0 0 8px #D0D0D0;
  }
  </style>
</head>
<body>



<!--
<form action="/form/data_submitted" method="get">
User Name: <input type="text" name="u_name" placeholder="Please Enter User Name" class="input_box">
<br>
User email: <input type="text" name="u_email" placeholder="Please Enter Email Address" class="input_box">
<input type="submit" value="Submit" class="submit">
</form>
-->

<?php

// echo $this->input->post('setSuhu');

echo form_open('databaseArduino/dariBrowser');
if(isset($dataParameter->setSuhu))
{
  echo form_input('setSuhu', $dataParameter->setSuhu);
}
else
{
  echo form_input('setSuhu', '30.0');
}
echo form_submit('suhuSubmit', 'Set Temperatur');
echo form_close();

echo "<br>";
echo "<strong>Data pembacaan sensor</strong>";
echo "<br>";
echo "<table>";

  echo "<tr>";
  echo "<td width='50'>Nomor</td>";
  echo "<td width='200'>Waktu</td>";
  echo "<td width='50'>Api</td>";
  echo "<td width='50'>Asap</td>";
  echo "<td width='50'>Suhu</td>";
  echo "</tr>";

  foreach ($dataSensor as $row)
{
  echo "<tr>";
  echo "<td>".$row->nomor."</td>";
  echo "<td>".$row->waktu."</td>";
  echo "<td>".$row->api."</td>";
  echo "<td>".$row->asap."</td>";
  echo "<td>".$row->suhu."</td>";
  echo "</tr>";
}
echo "</table>";
?>
</body>
</html>

file server : htdocs.zip

Prototipe pengkondisi suhu ruangan dengan perintah SMS

Prototipe ini merupakan aplikasi pengkondisi suhu ruangan kandang ayam berbasis SMS gateway/SMS server.

Kelebihan:

  1. Profil kondisi untuk ayam kecil, sedang dan besar.
  2. Mengeluarkan suara terjadwal anti stress bagi ayam
  3. Monitoring melalui SMS
  4. Pengaturan melalui SMS

Kelengkapan:

  1. Arduino Mega 2560
  2. Modem Wavecom fastrack supreme 10
  3. modul RTC DS1307
  4. DHT 11
  5. Modul max232
  6. Kipas 12v
  7. Elemen pemanas
  8. Relay 1 channel

link album: Galeri pengkondisi suhu ruangan

running text anti flicker (improved DMD) dengan arduino

DMD (dot matrix display) yang dikontrol dengan arduino dengan segala keterbatasannya memiliki permasalahan saat panel DMD disusun dalam lebih dari 4 panel. Flicker terjadi karena proses pengiriman data serial dari arduino harus mengantri sekian lama sehingga pergantian aktifasi baris per baris tertangkap oleh mata seperti berayun (berkedip) dan tentu membuat mata tidak nyaman.

Untuk itu saya melakukan improvisasi terhadap library arduino –DMD2– dengan prinsip kerja satu clock untuk lebih dari satu baris. contohnya untuk ukuran panel 4 kolom 2 baris kelompok DMD dibagi menjadi 2 bagian (baris 1 dan baris 2) dengan entri data yang sama setiap clock-nya.

Kelebihan alat DMD2 arduino:

  1. Sensor DHT11 untuk memantau keadaan suhu dan kelembaban sekitar
  2. Database waktu sholat 5 waktu (statis) dan dilengkapi buzzer yang menandakan waktu sholat telah masuk.

 

Komponen yang dibutuhkan :

  1. 8 Panel P10
  2. Arduino Mega 2560
  3. RTC DS1307
  4. DHT11
  5. Buzzer

DS1307 dapat diganti dengan DS3231 untuk keperluan presisi RTC.

berikut skema-nya :

berserta sketch atau program nya:

 

#include <DMD2.h>
#include <fonts/SystemFont5x7.h>
#include <fonts/Arial14.h>
#include <TimeLib.h>
#include <DS1307RTC.h>
#include "DHT.h"

byte DataPins[2] = {33, 35}; //pin jalur out
SoftDMD dmd(4, 2, 23, 25, 27, 31, 29, 2, DataPins); //kolom, baris, OE, A, B, SCK, CLK, jumlah jalur out, pin jalur out
//SoftDMD dmd(4,2,23,25,27,31,29,33); //standard

DMD_TextBox box(dmd, 0, 0, 78, 32);

DHT dht(A0, DHT11);
String namaSholat[] = {"  Subuh", "  Zuhur", "   Asar", " Maghrib", "   Isya"};
byte waktuSholat[][2] = {{5, 12},
                        {12, 32},
                        {15, 45},
                        {18, 35},
                        {19, 44}
};

#define waktunyaSholat 1
#define pesanSMS 2

int n = 123;
byte lastSecond = 60;
byte lastDay = 32;
byte lastH = 60;
byte lastT = 32;
String Sholat;
String pesanDisplay;
byte pesan;
int buzzer = 8;
bool buzz;
byte buzzCounter;

void setup() {
  Serial.begin(9600);
  Serial.println("Running text dengan Arduino bebas kedip");
  Serial.println("https://www.project.semesin.com");
  dht.begin();
  dmd.setBrightness(255);
  dmd.begin();

  pesan = pesanSMS;
  pesanDisplay = "  Selamat\n  datang";
  dmd.selectFont(Arial14);
  box.print(pesanDisplay);
}

void loop()
{
  tmElements_t tm;
  byte h = (byte)dht.readHumidity();
  byte t = (byte)dht.readTemperature();
  RTC.read(tm);

  if (pesan == waktunyaSholat)
  {
    buzzCounter++;
    if (!(buzzCounter % 32))
    {
      buzz = !buzz;
      digitalWrite(buzzer, buzz);
      pinMode(buzzer, OUTPUT);
    }
  }

  if (tm.Second != lastSecond)
  {
    String waktu = "";
    if (tm.Hour < 10)
      waktu += "0";
    waktu += tm.Hour;
    waktu += ":";
    if (tm.Minute < 10)
      waktu += "0";
    waktu += tm.Minute;
    waktu += ":";
    if (tm.Second < 10)
      waktu += "0";
    waktu += tm.Second;
    lastSecond = tm.Second;

    dmd.selectFont(SystemFont5x7);
    dmd.drawString(80, 0, waktu);

    if ((pesan == waktunyaSholat) && (tm.Second >= 58))
    {
      box.clear();
      dmd.selectFont(Arial14);
      box.print(pesanDisplay);
      pesan = pesanSMS;
      digitalWrite(buzzer, LOW);
    }
    else if (tm.Second <= 1)
    {
      for (byte i = 0; i < 5; i++)
      {
        if ((waktuSholat[i][0] == tm.Hour) && (waktuSholat[i][1] == tm.Minute))
        {
          Sholat = namaSholat[i];
          box.clear();
          dmd.selectFont(Arial14);
          box.println("  Sholat");
          box.print(Sholat);
          pesan = waktunyaSholat;
        }
      }
    }
  }
  if (tm.Day != lastDay)
  {
    String tanggal = "";
    if (tm.Day < 10)
      tanggal += "0";
    tanggal += tm.Day;
    tanggal += "/";
    if (tm.Month < 10)
      tanggal += "0";
    tanggal += tm.Month;
    tanggal += "/";
    if (tmYearToCalendar(tm.Year) < 10)
      tanggal += "0";
    tanggal += tmYearToCalendar(tm.Year);
    lastDay = tm.Day;

    dmd.selectFont(SystemFont5x7);
    dmd.drawString(80, 8, tanggal);
  }
  if ((h != lastH) || (t != lastT))
  {
    String suhu = "";
    if (t < 10)
      suhu += "0";
    suhu += t;
    suhu += "'C ";
    if (h < 10)
      suhu += "0";
    suhu += h;
    suhu += "%";

    lastT = t;
    lastH = h;

    dmd.selectFont(SystemFont5x7);
    dmd.drawString(80, 16, suhu);
  }
}

dokumentasi Galeri DMD arduino anti flicker

Library yang sudah dimodifikasi: DMD-GL

Jika menginginkan jadwal sholat yang dinamis (waktu matahari) bisa menggunakan library “PrayerTimes.h”.