#include <WiFi.h>
#include <WebServer.h>
#include <Preferences.h>
#include <EEPROM.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>
#include <DHT.h>
#include <Keypad.h>
#include <time.h>
// ================== KONFIGURASI AWAL ====================
#define DHTPIN1 26
#define DHTPIN2 25
#define DHTTYPE DHT22
DHT dht1(DHTPIN1, DHTTYPE);
DHT dht2(DHTPIN2, DHTTYPE);
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define I2C_ADDRESS 0x3C
Adafruit_SH1106G display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Preferences preferences;
WebServer server(80);
// ================== KONFIG WIFI NTP =====================
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 7 * 3600; // Jakarta
const int daylightOffset_sec = 0;
// ================== KEYPAD SETUP ========================
#define ROWS 2
#define COLS 2
char keyMap[ROWS][COLS] = {
{'3', '4'},
{'1', '5'}
};
uint8_t rowPins[ROWS] = {14, 27}; // GPIO14, GPIO27
uint8_t colPins[COLS] = {33, 32}; // GPIO33, GPIO32
Keypad keypad = Keypad(makeKeymap(keyMap), rowPins, colPins, ROWS, COLS);
// ================== VARIABEL SISTEM =====================
float TempAct, HumAct;
float celsius;
int TempActS, HumActS;
int ShwThNow, ShwThM1, ShwThP1;
int PLADt, ABSDt, PETGDt, PETG_CFDt;
int TPUDt, PC_ABSDt, PA_CFDt;
int NowFlmnt;
int SetTimer;
String FlmtType, FlmtM1, FlmtP1;
String CautionTmp;
bool ActCursorOnOff = false;
String CondtiTime = "OFF";
int VirThM5, VirThM2;
int DayCo, HCo, MCo, SCo;
int DayCoC, HCoC, SCoCDs;
int DayCoCD, HCoCD;
String HCoInc = " ", MCoInc = " ", SCoInc = " ";
int DelyHeat = 0, VirThFan = 1800;
int ActCursorY = 0, ActCursorQRsh = 0;
bool Heat1, Heat2, Heat3, Fan1;
int FlmtTypeDt = 0;
float suhu = 0;
float kelembapan = 0;
int lastSavedShwThNow = -1;
// ================== STRUKTUR WIFI CONFIG ==================
const char* ap_ssid = "AutoConnectAP";
const char* ap_password = "password";
String ssid, password;
// --- Fungsi: Baca Sensor ---
void updateSensor() {
suhu = dht1.readTemperature();
kelembapan = dht1.readHumidity();
if (isnan(suhu) || isnan(kelembapan)) {
Serial.println("Gagal membaca data dari DHT22");
suhu = 0;
kelembapan = 0;
} else {
Serial.println("Suhu: " + String(suhu) + "°C");
Serial.println("Kelembapan: " + String(kelembapan) + "%");
}
}
// --- Halaman Utama ---
void handleRoot() {
updateSensor();
String html = "<!DOCTYPE html><html><head><meta charset='UTF-8'><title>ESP32 Setup</title>";
html += "<style>";
html += "body{font-family:sans-serif;padding:10px;max-width:480px;margin:auto;background:#f9f9f9;}";
html += "h2,h3{text-align:center;}";
html += "label,input{display:inline-block;font-size:16px;margin:5px;}";
html += ".row{display:flex;align-items:center;justify-content:space-between;margin:8px 0;}";
html += ".sensor{font-size:2rem;text-align:center;}";
html += ".param{margin:12px 0;text-align:center;}";
html += "button{padding:10px 20px;font-size:16px;margin:5px;border:none;border-radius:5px;background-color:#007BFF;color:white;cursor:pointer;}";
html += "button:hover{background-color:#0056b3;}";
html += "</style></head><body>";
html += "<h2>WiFi Configuration</h2>";
html += "<form action='/save' method='post'>";
html += "<div class='row'><label>SSID:</label><input type='text' name='ssid' value='" + ssid + "' style='flex:1;'></div>";
html += "<div class='row'><label>Password:</label><input type='password' name='pass' value='" + password + "' style='flex:1;'></div>";
html += "<div style='text-align:center;'><button type='submit'>Simpan</button></div>";
html += "</form><hr>";
html += "<h3>Sensor & Countdown</h3>";
html += "<div class='sensor'><span id='suhu'></span>°C || <span id='hum'></span>%</div>";
html += "<div class='sensor'><span id='day'></span> D - <span id='hour'></span>:<span id='mint'></span></div>";
html += "<hr>";
html += "<h3>Parameter</h3>";
html += "<div class='param'>Treshold: <span id='labelShw'>" + String(ShwThNow) + "</span> °C</div>";
html += "<div class='row' style='justify-content:center;'><input type='number' id='shwInput' value='" + String(ShwThNow) + "'>";
html += "<button onclick='setShw()'>SET</button></div>";
html += "<div class='param'>Filament Type:</div>";
html += "<div class='row' style='justify-content:center;'>";
html += "<button onclick='setFlmt(\"dec\")'>⟵</button>";
html += "<div id='labelFlmt' style='padding:0 15px;font-weight:bold;'>" + FlmtType + "</div>";
html += "<button onclick='setFlmt(\"inc\")'>⟶</button></div>";
html += "<div class='param'>Countdown: <span id='labelHCo'>" + String(HCo) + "</span> hour</div>";
html += "<div class='param'>Status heater: <span id='heaterState'>" + String(ActCursorOnOff ? "ON" : "OFF") + "</span></div>";
html += "<div class='row' style='justify-content:center;'>";
html += "<button onclick='setHCo(\"dec\")'>−</button>";
html += "<button id='toggleBtn' onclick='toggleCursor()'>" + String(ActCursorOnOff ? "Turn OFF" : "Turn ON") + "</button>";
html += "<button onclick='setHCo(\"inc\")'>+</button>";
html += "</div>";
html += "<hr><p style='text-align:center;'>Mode: " + String(WiFi.getMode() == WIFI_AP ? "AP Mode" : "STA Mode") + "<br>IP: " + WiFi.localIP().toString() + "</p>";
html += "<script>";
html += "function setShw(){let v=document.getElementById('shwInput').value;";
html += "fetch('/setshw?val='+v).then(r=>r.text()).then(t=>document.getElementById('labelShw').innerText=t);}";
html += "function setFlmt(dir){";
html += "fetch('/flmt?dir='+dir).then(r=>r.text()).then(t=>{";
html += "document.getElementById('labelFlmt').innerText = t;";
html += "fetch('/shwvalue').then(r=>r.text()).then(val=>{";
html += "document.getElementById('labelShw').innerText = val;";
html += "document.getElementById('shwInput').value = val;";
html += "});});}";
html += "function toggleCursor(){fetch('/togglecursor').then(()=>location.reload());}";
html += "function setHCo(cmd){fetch('/hco?cmd='+cmd).then(r=>r.text()).then(val=>{";
html += "if(document.getElementById('labelHCo')) document.getElementById('labelHCo').innerText=val;";
html += "});}";
html += "setInterval(()=>{fetch('/dht').then(r=>r.json()).then(d=>{";
html += "document.getElementById('suhu').innerText = d.suhu.toFixed(1);";
html += "document.getElementById('hum').innerText = d.kelembapan.toFixed(1);";
html += "document.getElementById('day').innerText = d.DayCoCD.toFixed(0);";
html += "document.getElementById('hour').innerText = d.HCoCD.toFixed(0);";
html += "document.getElementById('mint').innerText = d.MCo.toFixed(0);";
html += "document.getElementById('labelFlmt').innerText = d.FlmtType;";
html += "document.getElementById('labelShw').innerText = d.ShwThNow;";
//html += "document.getElementById('shwInput').value = d.ShwThNow;";
html += "document.getElementById('labelHCo').innerText = d.HCoCD;";
html += "document.getElementById('heaterState').innerText = d.ActCursorOnOff ? 'ON' : 'OFF';";
html += "document.getElementById('toggleBtn').innerText = d.ActCursorOnOff ? 'Turn OFF' : 'Turn ON';";
html += "});}, 3000);";
html += "</script>";
html += "</body></html>";
server.send(200, "text/html", html);
}
// --- Simpan WiFi ---
void handleSave() {
if (server.hasArg("ssid") && server.hasArg("pass")) {
ssid = server.arg("ssid");
password = server.arg("pass");
preferences.putString("ssid", ssid);
preferences.putString("password", password);
server.send(200, "text/html", "<h3>WiFi Disimpan! Restarting...</h3>");
delay(1000);
ESP.restart();
} else {
server.send(400, "text/plain", "Parameter tidak lengkap");
}
}
// --- Set TempAct Threshold ---
void handleSetShw() {
if (server.hasArg("val")) {
ShwThNow = server.arg("val").toInt();
Serial.println("Nilai ShwThNow: " + String(ShwThNow));
server.send(200, "text/plain", String(ShwThNow));
} else {
server.send(400, "text/plain", "Parameter tidak valid");
}
}
enum HeaterMode {
HEAT_OFF,
HEAT_STAGE1,
HEAT_STAGE2,
HEAT_STAGE3,
HEAT_HOLD,
HEAT_FAN_ONLY
};
HeaterMode heaterMode = HEAT_OFF;
// ================== Bit Map QR code ==================
static const uint8_t image_data_Saraarray[1040] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x80, 0x01, 0x87, 0xf9, 0x98, 0x18, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x80, 0x01, 0x87, 0xf9, 0x98, 0x18, 0x00, 0x1f, 0xdd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x9f, 0xf9, 0xff, 0xe6, 0x78, 0x19, 0xff, 0x9f, 0x9c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x9f, 0xf9, 0xff, 0xe6, 0x78, 0x19, 0xff, 0x9f, 0x1c, 0x78, 0x00, 0x1e, 0x7e, 0x01, 0x80, 0x01,
0x98, 0x19, 0x9e, 0x00, 0x7f, 0x99, 0x81, 0x9e, 0x1c, 0x38, 0x00, 0x1e, 0x7e, 0x01, 0x80, 0x01,
0x98, 0x19, 0x9e, 0x00, 0x7f, 0x99, 0x81, 0x9c, 0x1c, 0x19, 0xff, 0x99, 0x9f, 0x9f, 0x9f, 0xf9,
0x98, 0x19, 0x86, 0x66, 0x1f, 0xf9, 0x81, 0x9e, 0x1c, 0x39, 0xff, 0x99, 0x9f, 0x9f, 0x9f, 0xf9,
0x98, 0x19, 0x86, 0x66, 0x1f, 0xf9, 0x81, 0x9f, 0x1c, 0x79, 0x81, 0x9e, 0x78, 0x07, 0x98, 0x19,
0x98, 0x19, 0x80, 0x78, 0x00, 0x79, 0x81, 0x9f, 0x9c, 0xf9, 0x81, 0x9e, 0x78, 0x07, 0x98, 0x19,
0x98, 0x19, 0x80, 0x78, 0x00, 0x79, 0x81, 0x9f, 0xdd, 0xf9, 0x81, 0x98, 0x07, 0xe1, 0x98, 0x19,
0x9f, 0xf9, 0xe7, 0x99, 0xe1, 0xf9, 0xff, 0x9f, 0xff, 0xf9, 0x81, 0x98, 0x07, 0xe1, 0x98, 0x19,
0x9f, 0xf9, 0xe7, 0x99, 0xe1, 0xf9, 0xff, 0x9f, 0xff, 0xf9, 0x81, 0x98, 0x1e, 0x7f, 0x98, 0x19,
0x80, 0x01, 0x99, 0x99, 0x99, 0x98, 0x00, 0x1f, 0xff, 0xf9, 0x81, 0x98, 0x1e, 0x7f, 0x98, 0x19,
0x80, 0x01, 0x99, 0x99, 0x99, 0x98, 0x00, 0x1f, 0xff, 0xf9, 0xff, 0x98, 0x79, 0xe1, 0x9f, 0xf9,
0xff, 0xff, 0xe6, 0x78, 0x06, 0x7f, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0x98, 0x79, 0xe1, 0x9f, 0xf9,
0xff, 0xff, 0xe6, 0x78, 0x06, 0x7f, 0xff, 0xfb, 0xdf, 0xf8, 0x00, 0x19, 0x99, 0x99, 0x80, 0x01,
0x80, 0x79, 0x9f, 0xe1, 0xe6, 0x07, 0x81, 0x98, 0x0f, 0xf8, 0x00, 0x19, 0x99, 0x99, 0x80, 0x01,
0x80, 0x79, 0x9f, 0xe1, 0xe6, 0x07, 0x81, 0x9b, 0xff, 0xff, 0xff, 0xfe, 0x18, 0x79, 0xff, 0xff,
0x98, 0x07, 0xe7, 0xff, 0xfe, 0x19, 0xe7, 0xfb, 0xff, 0xff, 0xff, 0xfe, 0x18, 0x79, 0xff, 0xff,
0x98, 0x07, 0xe7, 0xff, 0xfe, 0x19, 0xe7, 0xff, 0xff, 0xfe, 0x61, 0x80, 0x01, 0x9e, 0x60, 0x67,
0x99, 0x81, 0x9f, 0xe1, 0x98, 0x07, 0x99, 0x9b, 0xfe, 0x7e, 0x61, 0x80, 0x01, 0x9e, 0x60, 0x67,
0x99, 0x81, 0x9f, 0xe1, 0x98, 0x07, 0x99, 0x9f, 0xfd, 0xb8, 0x06, 0x78, 0x60, 0x67, 0x9f, 0x81,
0xff, 0x87, 0x9e, 0x18, 0x79, 0x81, 0xff, 0x9f, 0xfd, 0xb8, 0x06, 0x78, 0x60, 0x67, 0x9f, 0x81,
0xff, 0x87, 0x9e, 0x18, 0x79, 0x81, 0xff, 0x9c, 0x1d, 0xbf, 0xfe, 0x06, 0x01, 0x98, 0x18, 0x07,
0x80, 0x00, 0x66, 0x66, 0x1f, 0x86, 0x19, 0xfb, 0xec, 0x0f, 0xfe, 0x06, 0x01, 0x98, 0x18, 0x07,
0x80, 0x00, 0x66, 0x66, 0x1f, 0x86, 0x19, 0xfb, 0xef, 0xf8, 0x01, 0xff, 0xfe, 0x78, 0x07, 0x81,
0xf8, 0x1f, 0x80, 0x7e, 0x66, 0x00, 0x60, 0x1b, 0xed, 0xe8, 0x01, 0xff, 0xfe, 0x78, 0x07, 0x81,
0xf8, 0x1f, 0x80, 0x7e, 0x66, 0x00, 0x60, 0x1d, 0xdc, 0x09, 0x99, 0x87, 0x98, 0x1f, 0x9f, 0x87,
0x86, 0x61, 0xf9, 0x81, 0xf8, 0x01, 0xe6, 0x1f, 0xfd, 0xe9, 0x99, 0x87, 0x98, 0x1f, 0x9f, 0x87,
0x86, 0x61, 0xf9, 0x81, 0xf8, 0x01, 0xe6, 0x1c, 0x7f, 0xf8, 0x18, 0x79, 0xf9, 0xff, 0x80, 0x1f,
0xff, 0xff, 0xe1, 0x87, 0x99, 0x98, 0x19, 0xfb, 0xbf, 0xf8, 0x18, 0x79, 0xf9, 0xff, 0x80, 0x1f,
0xff, 0xff, 0xe1, 0x87, 0x99, 0x98, 0x19, 0xfb, 0xbf, 0xff, 0x80, 0x00, 0x01, 0xe0, 0x61, 0xf9,
0x9e, 0x18, 0x1e, 0x79, 0x87, 0xf8, 0x60, 0x7b, 0xbf, 0xef, 0x80, 0x00, 0x01, 0xe0, 0x61, 0xf9,
0x9e, 0x18, 0x1e, 0x79, 0x87, 0xf8, 0x60, 0x7c, 0x7f, 0xff, 0xe7, 0xf8, 0x06, 0x1e, 0x79, 0xe1,
0xe1, 0xff, 0xe1, 0x87, 0x99, 0x9f, 0xe6, 0x1f, 0xfc, 0xef, 0xe7, 0xf8, 0x06, 0x1e, 0x79, 0xe1,
0xe1, 0xff, 0xe1, 0x87, 0x99, 0x9f, 0xe6, 0x18, 0x3b, 0x69, 0xe6, 0x06, 0x79, 0x80, 0x01, 0xf9,
0x99, 0xe0, 0x78, 0x06, 0x7e, 0x7e, 0x00, 0x1f, 0x7b, 0x69, 0xe6, 0x06, 0x79, 0x80, 0x01, 0xf9,
0x99, 0xe0, 0x78, 0x06, 0x7e, 0x7e, 0x00, 0x1f, 0xbb, 0x6f, 0xff, 0xf8, 0x01, 0x99, 0xf9, 0xe7,
0xf9, 0xe6, 0x67, 0x86, 0x00, 0x7f, 0xff, 0x9f, 0xbd, 0x8f, 0xff, 0xf8, 0x01, 0x99, 0xf9, 0xe7,
0xf9, 0xe6, 0x67, 0x86, 0x00, 0x7f, 0xff, 0x98, 0x7f, 0xf8, 0x00, 0x19, 0x99, 0xf9, 0x98, 0x61,
0xe6, 0x78, 0x06, 0x1f, 0x9e, 0x00, 0x01, 0x9f, 0xff, 0xf8, 0x00, 0x19, 0x99, 0xf9, 0x98, 0x61,
0xe6, 0x78, 0x06, 0x1f, 0x9e, 0x00, 0x01, 0x9f, 0x7f, 0xf9, 0xff, 0x9f, 0x9e, 0x79, 0xf8, 0x67,
0xff, 0xff, 0x87, 0x9e, 0x79, 0x9f, 0x86, 0x78, 0x1f, 0xf9, 0xff, 0x9f, 0x9e, 0x79, 0xf8, 0x67,
0xff, 0xff, 0x87, 0x9e, 0x79, 0x9f, 0x86, 0x7f, 0x6f, 0xf9, 0x81, 0x98, 0x06, 0x78, 0x01, 0x87,
0x80, 0x01, 0xe6, 0x01, 0x9f, 0x99, 0x80, 0x7f, 0xdf, 0xf9, 0x81, 0x98, 0x06, 0x78, 0x01, 0x87,
0x80, 0x01, 0xe6, 0x01, 0x9f, 0x99, 0x80, 0x7f, 0xff, 0xf9, 0x81, 0x98, 0x07, 0x9f, 0x98, 0x79,
0x9f, 0xf9, 0xff, 0xe0, 0x61, 0x9f, 0x9f, 0xff, 0xff, 0xf9, 0x81, 0x98, 0x07, 0x9f, 0x98, 0x79,
0x9f, 0xf9, 0xff, 0xe0, 0x61, 0x9f, 0x9f, 0xff, 0xff, 0xf9, 0x81, 0x9e, 0x67, 0x81, 0xff, 0x87,
0x98, 0x19, 0xf9, 0x9e, 0x61, 0x80, 0x1e, 0x1f, 0xff, 0xf9, 0x81, 0x9e, 0x67, 0x81, 0xff, 0x87,
0x98, 0x19, 0xf9, 0x9e, 0x61, 0x80, 0x1e, 0x1f, 0xdd, 0xf9, 0xff, 0x98, 0x66, 0x18, 0x7e, 0x07,
0x98, 0x19, 0x86, 0x18, 0x60, 0x7f, 0x98, 0x7f, 0x9c, 0xf9, 0xff, 0x98, 0x66, 0x18, 0x7e, 0x07,
0x98, 0x19, 0x86, 0x18, 0x60, 0x7f, 0x98, 0x7f, 0x1c, 0x78, 0x00, 0x1f, 0x81, 0x87, 0x98, 0x01,
0x98, 0x19, 0x98, 0x66, 0x79, 0xe0, 0x79, 0x9e, 0x1c, 0x38, 0x00, 0x1f, 0x81, 0x87, 0x98, 0x01,
0x98, 0x19, 0x98, 0x66, 0x79, 0xe0, 0x79, 0x9c, 0x1c, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x9f, 0xf9, 0x9e, 0x7f, 0xfe, 0x7e, 0x19, 0x9e, 0x1c, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x9f, 0xf9, 0x9e, 0x7f, 0xfe, 0x7e, 0x19, 0x9f, 0x1c, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x80, 0x01, 0x99, 0xf9, 0xe6, 0x01, 0xfe, 0x7f, 0x9c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x80, 0x01, 0x99, 0xf9, 0xe6, 0x01, 0xfe, 0x7f, 0xdd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
const uint8_t frameHeaterOff[] PROGMEM = {
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b01111111
};
const uint8_t frameFanOff[] PROGMEM = {
0b00000000,
0b00000000,
0b00001000,
0b00001000,
0b00110110,
0b00001000,
0b00001000,
0b00000000
};
// 4 Frame animasi HEATER (frame1 - frame4)
const uint8_t heaterFrames[][8] PROGMEM = {
{
0b00000000,
0b01000100,
0b01100110,
0b00010001,
0b00110011,
0b01000100,
0b00100010,
0b01111111
},
{
0b00000000,
0b00100010,
0b00010001,
0b00110011,
0b01000100,
0b01100110,
0b00010001,
0b01111111
},
{
0b00000000,
0b00010001,
0b00110011,
0b01000100,
0b01100110,
0b00010001,
0b00100010,
0b01111111
},
{
0b00000000,
0b00100010,
0b01000100,
0b01100110,
0b00010001,
0b00110011,
0b01000100,
0b01111111
}
};
// 4 Frame animasi FAN (frame5 - frame8)
const uint8_t fanFrames[][8] PROGMEM = {
{
0b00000000,
0b00111000,
0b00001100,
0b00110101,
0b01101011,
0b01010110,
0b00011000,
0b00001110
},
{
0b00000000,
0b00001100,
0b00000100,
0b001110100,
0b00101001,
0b00010111,
0b00010000,
0b00011000
},
{
0b00000000,
0b01100001,
0b00010001,
0b00001010,
0b00011100,
0b00101000,
0b01000100,
0b01000011
},
{
0b00000000,
0b00110000,
0b00011001,
0b00001011,
0b00110110,
0b01101000,
0b01001100,
0b00000110
}
};
const int numFrames = 4;
uint8_t frameIndex = 0;
unsigned long previousMillis = 0;
const unsigned long frameInterval = 250;
void setup() {//=================================== setup =================================
Serial.begin(115200);
dht1.begin();
dht2.begin();
EEPROM.begin(128);
preferences.begin("wifi_config", false);
pinMode(5, OUTPUT);
pinMode(17, OUTPUT);
pinMode(16, OUTPUT);
pinMode(4, OUTPUT);
digitalWrite(5, HIGH);
digitalWrite(17, HIGH);
digitalWrite(16, HIGH);
digitalWrite(4, HIGH);
display.begin(I2C_ADDRESS, true);
display.setTextColor(SH110X_WHITE);
display.setTextSize(1);
display.clearDisplay();
display.setCursor(0, 0);
display.println(F("Inisialisasi..."));
display.display();
// Load suhu preset filament & konfigurasi countdown
PLADt = EEPROM.read(50);
ABSDt = EEPROM.read(51);
PETGDt = EEPROM.read(52);
PETG_CFDt = EEPROM.read(53);
TPUDt = EEPROM.read(54);
PC_ABSDt = EEPROM.read(55);
PA_CFDt = EEPROM.read(56);
NowFlmnt = EEPROM.read(57);
SetTimer = EEPROM.read(58);
DayCo = EEPROM.read(59);
HCo = EEPROM.read(60);
// Pemulihan nilai default jika EEPROM kosong
if (PLADt >= 100) PLADt = 50; EEPROM.write(50, PLADt);
if (ABSDt >= 100) ABSDt = 80; EEPROM.write(51, ABSDt);
if (PETGDt >= 100) PETGDt = 65; EEPROM.write(52, PETGDt);
if (PETG_CFDt >= 100) PETG_CFDt = 65; EEPROM.write(53, PETG_CFDt);
if (TPUDt >= 100) TPUDt = 65; EEPROM.write(54, TPUDt);
if (PC_ABSDt >= 100) PC_ABSDt = 65; EEPROM.write(55, PC_ABSDt);
if (PA_CFDt >= 100) PA_CFDt = 65; EEPROM.write(56, PA_CFDt);
if (NowFlmnt > 6) NowFlmnt = 0; EEPROM.write(57, NowFlmnt);
if (DayCo > 10) DayCo = 0; EEPROM.write(59, DayCo);
if (HCo > 24) HCo = 5; EEPROM.write(60, HCo); EEPROM.commit();
// Terapkan konfigurasi berdasarkan NowFlmnt
aturFilament(); // akan set FlmtType, ShwThNow, M1/P1, dan ShwThM1/M2
// Timer jam
DayCoCD = DayCo;
HCoCD = HCo;
MCo = 0;
SCo = 0;
HCoInc = (HCo < 10) ? " " : "";
MCoInc = (MCo < 10) ? " " : "";
SCoInc = (SCo < 10) ? " " : "";
SCoCDs = 0;
ssid = preferences.getString("ssid", "");
password = preferences.getString("password", "");
WiFi.mode(WIFI_AP_STA);
if (ssid != "" && password != "") {
WiFi.begin(ssid.c_str(), password.c_str());
Serial.print("Menghubungkan ke ");
Serial.println(ssid);
unsigned long startTime = millis();
while (WiFi.status() != WL_CONNECTED && millis() - startTime < 8000) {
delay(500);
Serial.print(".");
}
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\nTersambung ke STA! IP: " + WiFi.localIP().toString());
} else {
Serial.println("\nGagal konek ke STA");
}
WiFi.softAP(ap_ssid, ap_password);
Serial.println("AP aktif di IP: " + WiFi.softAPIP().toString());
configTime(7 * 3600, 0, "pool.ntp.org", "time.nist.gov"); // Offset waktu Jakarta
display.begin(0x3C, true);
display.setTextColor(SH110X_WHITE);
display.setTextSize(1);
display.clearDisplay();
display.display();
// ROUTES
server.on("/", handleRoot);
server.on("/save", HTTP_POST, handleSave);
server.on("/setshw", HTTP_GET, handleSetShw);
server.on("/flmt", HTTP_GET, []() {
if (server.hasArg("dir")) {
String dir = server.arg("dir");
if (dir == "inc") {
NowFlmnt = min(NowFlmnt + 1, 6);
} else if (dir == "dec") {
NowFlmnt = max(NowFlmnt - 1, 0);
}
EEPROM.write(57, NowFlmnt);
EEPROM.commit();
aturFilament();
server.send(200, "text/plain", FlmtType);
} else {
server.send(400, "text/plain", "Argumen tidak valid");
}
});
server.on("/togglecursor", HTTP_GET, []() {
ActCursorOnOff = !ActCursorOnOff;
CondtiTime = ActCursorOnOff ? "ON " : "OFF";
Serial.println("ActCursorOnOff: " + String(ActCursorOnOff));
server.send(200, "text/plain", String(ActCursorOnOff));
});
server.on("/shwvalue", HTTP_GET, []() {
server.send(200, "text/plain", String(ShwThNow));
});
server.on("/dht", HTTP_GET, []() {
updateSensor();
String json = "{";
json += "\"suhu\":" + String(suhu) + ",";
json += "\"kelembapan\":" + String(kelembapan) + ",";
json += "\"DayCoCD\":" + String(DayCoCD) + ",";
json += "\"HCoCD\":" + String(HCoCD) + ",";
json += "\"MCo\":" + String(MCo) + ",";
json += "\"NowFlmnt\":" + String(NowFlmnt) + ",";
json += "\"FlmtType\":\"" + FlmtType + "\",";
json += "\"ShwThNow\":" + String(ShwThNow) + ",";
json += "\"ActCursorOnOff\":" + String(ActCursorOnOff);
json += "}";
server.send(200, "application/json", json);
});
server.on("/hco", HTTP_GET, []() {
if (server.hasArg("cmd")) {
String cmd = server.arg("cmd");
if (cmd == "inc") {
HCo = (HCo + 1) % 24;
} else if (cmd == "dec") {
HCo = (HCo == 0) ? 23 : HCo - 1;
}
EEPROM.write(60, HCo);
EEPROM.commit();
HCoCD = HCo;
server.send(200, "text/plain", String(HCo));
} else {
server.send(400, "text/plain", "Argumen tidak valid");
}
});
server.begin();
Serial.println("Web server aktif");
} //================================================= setup =================================
void MLcd0() {
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SH110X_WHITE);
display.setCursor(0, 0);
display.print(" "); display.print(TempActS); display.print((char)247); display.print("C| ");
display.print(HumActS); display.println("%");
display.print(" "); display.println(FlmtType);
display.print("Th: "); display.print(ShwThNow); display.println((char)247);
display.setTextSize(1);
display.print("C: "); display.print(DayCoCD); display.print("D ");
display.print(HCoInc); display.print(HCoCD); display.print(":");
display.print(MCoInc); display.print(MCo); display.print(":");
display.print(SCoInc); display.println(SCoCDs);
// Baca status relay aktif-low
bool heat1 = (digitalRead(5) == LOW);
bool heat2 = (digitalRead(17) == LOW);
bool heat3 = (digitalRead(16) == LOW);
bool fan = (digitalRead(4) == LOW);
// Animasi heater
for (int i = 0; i < 3; i++) {
const uint8_t* bitmap =
((i == 0 && heat1) || (i == 1 && heat2) || (i == 2 && heat3))
? heaterFrames[frameIndex]
: frameHeaterOff;
display.drawBitmap(i * 8, 56, bitmap, 8, 8, SH110X_WHITE);
}
// Animasi fan
const uint8_t* fanBitmap = fan ? fanFrames[frameIndex] : frameFanOff;
display.drawBitmap(3 * 8, 56, fanBitmap, 8, 8, SH110X_WHITE);
display.setCursor(35, 56);
display.print("-"); display.print(CautionTmp); display.print("-"); display.print(celsius); display.print((char)247); display.println("C");
display.display();
display.display();
}
void MLcd1() {
display.clearDisplay();
display.setTextSize(3); // Normal 1:1 pixel scale
display.setTextColor(SH110X_BLACK,SH110X_WHITE); // Draw white text
display.setCursor(0, 0); // Start at top-left corner
display.write(0xAE); display.print(" "); display.print(CondtiTime); display.print(" ");display.write(0xAF); display.println("");
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SH110X_WHITE);
display.print("Off "); display.print(TempActS); display.print((char)247); display.print("C | "); display.print(HumActS); display.println("% On");
display.print(" "); display.println(FlmtType);
display.print("Th: "); display.print(ShwThNow); display.print((char)247); display.println("C");
display.print("C: "); display.print(DayCoCD); display.print("D "); display.print(HCoInc); display.print(HCoCD); display.print(":"); display.print(MCoInc); display.print(MCo); display.print(":"); display.print(SCoInc); display.print(SCoCDs); display.println("s");
// Baca status relay aktif-low
bool heat1 = (digitalRead(5) == LOW);
bool heat2 = (digitalRead(17) == LOW);
bool heat3 = (digitalRead(16) == LOW);
bool fan = (digitalRead(4) == LOW);
// Animasi heater
for (int i = 0; i < 3; i++) {
const uint8_t* bitmap =
((i == 0 && heat1) || (i == 1 && heat2) || (i == 2 && heat3))
? heaterFrames[frameIndex]
: frameHeaterOff;
display.drawBitmap(i * 8, 56, bitmap, 8, 8, SH110X_WHITE);
}
// Animasi fan
const uint8_t* fanBitmap = fan ? fanFrames[frameIndex] : frameFanOff;
display.drawBitmap(3 * 8, 56, fanBitmap, 8, 8, SH110X_WHITE);
display.setCursor(35, 56);
display.print("-"); display.print(CautionTmp); display.print("-"); display.print(celsius); display.print((char)247); display.println("C");
display.display();
}
void MLcd2() {
display.clearDisplay();
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SH110X_WHITE); // Draw white text
display.setCursor(0, 0); // Start at top-left corner
display.print(" "); display.print(TempAct); display.print((char)247); display.print("C | "); display.print(HumAct); display.println("% ");
display.setTextSize(3); // Normal 1:1 pixel scale
display.setTextColor(SH110X_BLACK,SH110X_WHITE);
display.print(""); display.print(FlmtType); display.println("");
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SH110X_WHITE);
display.print(FlmtM1); display.print(" "); display.write(0xAE); display.write(0xAF); display.print(" "); display.println(FlmtP1);
display.print("Th: "); display.print(ShwThNow); display.print((char)247); display.println("C");
display.print("C: "); display.print(DayCoCD); display.print("D "); display.print(HCoInc); display.print(HCoCD); display.print(":"); display.print(MCoInc); display.print(MCo); display.print(":"); display.print(SCoInc); display.print(SCoCDs); display.println("s");
// Baca status relay aktif-low
bool heat1 = (digitalRead(5) == LOW);
bool heat2 = (digitalRead(17) == LOW);
bool heat3 = (digitalRead(16) == LOW);
bool fan = (digitalRead(4) == LOW);
// Animasi heater
for (int i = 0; i < 3; i++) {
const uint8_t* bitmap =
((i == 0 && heat1) || (i == 1 && heat2) || (i == 2 && heat3))
? heaterFrames[frameIndex]
: frameHeaterOff;
display.drawBitmap(i * 8, 56, bitmap, 8, 8, SH110X_WHITE);
}
// Animasi fan
const uint8_t* fanBitmap = fan ? fanFrames[frameIndex] : frameFanOff;
display.drawBitmap(3 * 8, 56, fanBitmap, 8, 8, SH110X_WHITE);
display.setCursor(35, 56);
display.print("-"); display.print(CautionTmp); display.print("-"); display.print(celsius); display.print((char)247); display.println("C");
display.display();
}
void MLcd3() {
display.clearDisplay();
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SH110X_WHITE); // Draw white text
display.setCursor(0, 0); // Start at top-left corner
display.print(" "); display.print(TempAct); display.print((char)247); display.print("C | "); display.print(HumAct); display.println("% "); // Normal 1:1 pixel scale
display.print(" "); display.println(FlmtType);
display.setTextSize(3); // Normal 1:1 pixel scale
display.setTextColor(SH110X_BLACK,SH110X_WHITE);
display.write(0xAE); display.print(" "); display.print(ShwThNow); display.print((char)247); display.print("C"); display.write(0xAF); display.println("");
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SH110X_WHITE);
display.print(" "); display.print(ShwThM1); display.print(" "); display.write(0xAE); display.write(0xAF); display.print(" "); display.println(ShwThP1);
display.print("C: "); display.print(DayCoCD); display.print("D "); display.print(HCoInc); display.print(HCoCD); display.print(":"); display.print(MCoInc); display.print(MCo); display.print(":"); display.print(SCoInc); display.print(SCoCDs); display.println("s");
// Baca status relay aktif-low
bool heat1 = (digitalRead(5) == LOW);
bool heat2 = (digitalRead(17) == LOW);
bool heat3 = (digitalRead(16) == LOW);
bool fan = (digitalRead(4) == LOW);
// Animasi heater
for (int i = 0; i < 3; i++) {
const uint8_t* bitmap =
((i == 0 && heat1) || (i == 1 && heat2) || (i == 2 && heat3))
? heaterFrames[frameIndex]
: frameHeaterOff;
display.drawBitmap(i * 8, 56, bitmap, 8, 8, SH110X_WHITE);
}
// Animasi fan
const uint8_t* fanBitmap = fan ? fanFrames[frameIndex] : frameFanOff;
display.drawBitmap(3 * 8, 56, fanBitmap, 8, 8, SH110X_WHITE);
display.setCursor(35, 56);
display.print("-"); display.print(CautionTmp); display.print("-"); display.print(celsius); display.print((char)247); display.println("C");
display.display();
}
void MLcd4() {
display.clearDisplay();
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SH110X_WHITE); // Draw white text
display.setCursor(0, 0); // Start at top-left corner
display.print(" "); display.print(TempAct); display.print((char)247); display.print("C | "); display.print(HumAct); display.println("% ");
display.print(" "); display.println(FlmtType);
display.print("Th: "); display.print(ShwThNow); display.print((char)247); display.println("C");
display.setTextSize(3); // Draw 2X-scale text
display.setTextColor(SH110X_BLACK,SH110X_WHITE);
display.write(0xAE); display.print(DayCo); display.print("D"); display.print(HCoInc); display.print(HCo); display.print("H"); display.write(0xAF); display.println("");
display.setTextSize(1); // Draw 2X-scale text
display.setTextColor(SH110X_WHITE);
display.print("-"); display.print(" "); display.write(0xAE); display.print("C: "); display.print(DayCoCD); display.print("D "); display.print(HCoInc); display.print(HCoCD); display.print(":"); display.print(MCoInc); display.print(MCo); display.print(":"); display.print(SCoInc); display.print(SCoCDs); display.print("s"); display.write(0xAF); display.print(" "); display.println("+");
// Baca status relay aktif-low
bool heat1 = (digitalRead(5) == LOW);
bool heat2 = (digitalRead(17) == LOW);
bool heat3 = (digitalRead(16) == LOW);
bool fan = (digitalRead(4) == LOW);
// Animasi heater
for (int i = 0; i < 3; i++) {
const uint8_t* bitmap =
((i == 0 && heat1) || (i == 1 && heat2) || (i == 2 && heat3))
? heaterFrames[frameIndex]
: frameHeaterOff;
display.drawBitmap(i * 8, 56, bitmap, 8, 8, SH110X_WHITE);
}
// Animasi fan
const uint8_t* fanBitmap = fan ? fanFrames[frameIndex] : frameFanOff;
display.drawBitmap(3 * 8, 56, fanBitmap, 8, 8, SH110X_WHITE);
display.setCursor(35, 56);
display.print("-"); display.print(CautionTmp); display.print("-"); display.print(celsius); display.print((char)247); display.println("C");
display.display();
}
void tampilkanMenuWiFi() {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SH110X_BLACK,SH110X_WHITE);
display.setCursor(0, 0);
display.print("WiFi Mode: "); display.println(WiFi.getMode() == WIFI_AP ? "AP Mode" : "AP & STA ");
display.write(0xAE); display.print(" AP | AP & STA "); display.write(0xAF); display.println("");
display.setTextColor(SH110X_WHITE);
display.println("SSID: AutoConnectAP");
display.println("PASS: password");
display.println("AP IP : " + WiFi.softAPIP().toString());
display.print("STA IP: "); display.println(WiFi.localIP());
struct tm waktuSekarang;
if (getLocalTime(&waktuSekarang)) {
display.print("Time: "); display.println(&waktuSekarang, "%H:%M:%S");
} else {
display.println("Time: XX:XX:XX");
}
// Baca status relay aktif-low
bool heat1 = (digitalRead(5) == LOW);
bool heat2 = (digitalRead(17) == LOW);
bool heat3 = (digitalRead(16) == LOW);
bool fan = (digitalRead(4) == LOW);
// Animasi heater
for (int i = 0; i < 3; i++) {
const uint8_t* bitmap =
((i == 0 && heat1) || (i == 1 && heat2) || (i == 2 && heat3))
? heaterFrames[frameIndex]
: frameHeaterOff;
display.drawBitmap(i * 8, 56, bitmap, 8, 8, SH110X_WHITE);
}
// Animasi fan
const uint8_t* fanBitmap = fan ? fanFrames[frameIndex] : frameFanOff;
display.drawBitmap(3 * 8, 56, fanBitmap, 8, 8, SH110X_WHITE);
display.setCursor(35, 56);
display.print("-"); display.print(CautionTmp); display.print("-"); display.print(celsius); display.print((char)247); display.println("C");
display.display();
}
void tampilkanQR() {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SH110X_WHITE);
display.setCursor(0, 0);
display.print("WiFi Mode: "); display.println(WiFi.getMode() == WIFI_AP ? "AP Mode" : "STA Mode");
display.setTextColor(SH110X_BLACK,SH110X_WHITE);
display.println("SSID: AutoConnectAP ");
display.println("PASS: password ");
display.print (" show QR ");display.write(0xAF); display.write(0xAF); display.write(0xAF); display.println("");
display.setTextColor(SH110X_WHITE);
display.println("AP IP : " + WiFi.softAPIP().toString());
display.print("STA IP: "); display.println(WiFi.localIP());
struct tm waktuSekarang;
if (getLocalTime(&waktuSekarang)) {
display.print("Time: "); display.println(&waktuSekarang, "%H:%M:%S");
} else {
display.println("Time: XX:XX:XX");
}
// Baca status relay aktif-low
bool heat1 = (digitalRead(5) == LOW);
bool heat2 = (digitalRead(17) == LOW);
bool heat3 = (digitalRead(16) == LOW);
bool fan = (digitalRead(4) == LOW);
// Animasi heater
for (int i = 0; i < 3; i++) {
const uint8_t* bitmap =
((i == 0 && heat1) || (i == 1 && heat2) || (i == 2 && heat3))
? heaterFrames[frameIndex]
: frameHeaterOff;
display.drawBitmap(i * 8, 56, bitmap, 8, 8, SH110X_WHITE);
}
// Animasi fan
const uint8_t* fanBitmap = fan ? fanFrames[frameIndex] : frameFanOff;
display.drawBitmap(3 * 8, 56, fanBitmap, 8, 8, SH110X_WHITE);
display.setCursor(35, 56);
display.print("-"); display.print(CautionTmp); display.print("-"); display.print(celsius); display.print((char)247); display.println("C");
display.display();
}
void tampilkanAPIP() {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SH110X_WHITE);
display.setCursor(0, 0);
display.print("WiFi Mode: "); display.println(WiFi.getMode() == WIFI_AP ? "AP Mode" : "STA Mode");
display.println("SSID: AutoConnectAP ");
display.println("PASS: password ");
display.setTextColor(SH110X_BLACK,SH110X_WHITE);
display.println("Acess Point IP : ");
display.setTextColor(SH110X_WHITE);
display.print (" ");display.println(WiFi.softAPIP().toString());
display.print("STA IP: "); display.println(WiFi.localIP());
struct tm waktuSekarang;
if (getLocalTime(&waktuSekarang)) {
display.print("Time: "); display.println(&waktuSekarang, "%H:%M:%S");
} else {
display.println("Time: XX:XX:XX");
}
// Baca status relay aktif-low
bool heat1 = (digitalRead(5) == LOW);
bool heat2 = (digitalRead(17) == LOW);
bool heat3 = (digitalRead(16) == LOW);
bool fan = (digitalRead(4) == LOW);
// Animasi heater
for (int i = 0; i < 3; i++) {
const uint8_t* bitmap =
((i == 0 && heat1) || (i == 1 && heat2) || (i == 2 && heat3))
? heaterFrames[frameIndex]
: frameHeaterOff;
display.drawBitmap(i * 8, 56, bitmap, 8, 8, SH110X_WHITE);
}
// Animasi fan
const uint8_t* fanBitmap = fan ? fanFrames[frameIndex] : frameFanOff;
display.drawBitmap(3 * 8, 56, fanBitmap, 8, 8, SH110X_WHITE);
display.setCursor(35, 56);
display.print("-"); display.print(CautionTmp); display.print("-"); display.print(celsius); display.print((char)247); display.println("C");
display.display();
}
void tampilkanSTAIP() {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SH110X_WHITE);
display.setCursor(0, 0);
display.print("WiFi Mode: "); display.println(WiFi.getMode() == WIFI_AP ? "AP Mode" : "STA Mode");
display.println("SSID: AutoConnectAP ");
display.println("PASS: password ");
display.println("Acess Point IP : ");
display.setTextColor(SH110X_BLACK,SH110X_WHITE);
display.println("Station Mode IP: ");
display.setTextColor(SH110X_WHITE);
display.print (" "); display.println(WiFi.localIP());
struct tm waktuSekarang;
if (getLocalTime(&waktuSekarang)) {
display.print("Time: "); display.println(&waktuSekarang, "%H:%M:%S");
} else {
display.println("Time: XX:XX:XX");
}
// Baca status relay aktif-low
bool heat1 = (digitalRead(5) == LOW);
bool heat2 = (digitalRead(17) == LOW);
bool heat3 = (digitalRead(16) == LOW);
bool fan = (digitalRead(4) == LOW);
// Animasi heater
for (int i = 0; i < 3; i++) {
const uint8_t* bitmap =
((i == 0 && heat1) || (i == 1 && heat2) || (i == 2 && heat3))
? heaterFrames[frameIndex]
: frameHeaterOff;
display.drawBitmap(i * 8, 56, bitmap, 8, 8, SH110X_WHITE);
}
// Animasi fan
const uint8_t* fanBitmap = fan ? fanFrames[frameIndex] : frameFanOff;
display.drawBitmap(3 * 8, 56, fanBitmap, 8, 8, SH110X_WHITE);
display.setCursor(35, 56);
display.print("-"); display.print(CautionTmp); display.print("-"); display.print(celsius); display.print((char)247); display.println("C");
display.display();
}
void tampilkanHeaterQR() {
display.clearDisplay();
display.drawBitmap(0, 0, image_data_Saraarray, 128, 64, 1);
display.display();
}
void loop() {//================================ loop ========================================
server.handleClient();
if (ShwThNow != lastSavedShwThNow) {
simpanSuhuPreset();
lastSavedShwThNow = ShwThNow;
}
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= frameInterval) {
previousMillis = currentMillis;
frameIndex = (frameIndex + 1) % 4;
}
suhu = dht1.readTemperature();
kelembapan = dht1.readHumidity();
TempAct = dht1.readTemperature();
HumAct = dht1.readHumidity();
celsius = dht2.readTemperature();
TempActS = TempAct;
HumActS = HumAct;
switch (ActCursorY) {
case 0: MLcd0(); break;
case 1: MLcd1(); break;
case 2: MLcd2(); break;
case 3: MLcd3(); break;
case 4: MLcd4(); break;
case 5: tampilkanMenuWiFi(); break;
case 6: ActCursorQRsh == 0 ? tampilkanQR() : tampilkanHeaterQR(); break;
case 7: tampilkanAPIP(); break;
case 8: tampilkanSTAIP(); break;
default: MLcd0(); break;
}
char key = keypad.getKey();
if (key) {
int KeyData = (int)key;
prosesKeypad(KeyData);
}
if (ActCursorOnOff) {
VirThM5 = ShwThNow - 5;
VirThM2 = ShwThNow - 2;
if ((SCo <= 0) && (MCo >= 1)) {
MCo -= 1;
SCo = 598;
SCoCDs = SCo / 10;
MCoInc = (MCo <= 9) ? " " : "";
}
if ((SCo <= 0) && (MCo <= 0) && (HCoC >= 1)) {
HCoC -= 1;
HCoCD = HCoC;
MCo = 59;
MCoInc = "";
SCo = 598;
SCoCDs = SCo / 10;
HCoInc = (HCo <= 9) ? " " : "";
}
if ((SCo <= 0) && (MCo <= 0) && (HCoC <= 0) && (DayCoC >= 1)) {
DayCoC -= 1;
DayCoCD = DayCoC;
HCoC = 23;
HCoCD = HCoC;
MCo = 59;
MCoInc = "";
SCo = 598;
SCoCDs = SCo / 10;
SCoInc = "";
}
if ((SCo <= 0) && (MCo <= 0) && (HCoC <= 0) && (DayCoC <= 0)) {
ActCursorOnOff = false;
CondtiTime = "OFF";
}
if (SCo >= 1) {
SCo -= 1;
SCoCDs = SCo / 10;
SCoInc = (SCo <= 9) ? " " : "";
if (DelyHeat <= 40) {
DelyHeat += 1;
}
}
if (TempAct <= VirThM5) {
if (DelyHeat <= 9) heaterMode = HEAT_OFF;
else if (DelyHeat <= 20) heaterMode = HEAT_STAGE1;
else if (DelyHeat <= 30) heaterMode = HEAT_STAGE2;
else heaterMode = HEAT_STAGE3;
VirThFan = 1800;
}
else if ((TempAct > VirThM5) && (TempAct <= VirThM2) && (DelyHeat >= 41)) {
heaterMode = HEAT_STAGE2;
VirThFan = 1800;
}
else if ((TempAct > VirThM2) && (TempAct <= ShwThNow)) {
heaterMode = HEAT_HOLD;
VirThFan = 1800;
}
else if ((TempAct > ShwThNow) && (VirThFan > 0)) {
heaterMode = HEAT_FAN_ONLY;
VirThFan -= 2;
}
else if ((TempAct > ShwThNow) && (VirThFan <= 0)) {
heaterMode = HEAT_OFF;
}
switch (heaterMode) {
case HEAT_OFF:
digitalWrite(5, HIGH);
digitalWrite(17, HIGH);
digitalWrite(16, HIGH);
digitalWrite(4, HIGH);
break;
case HEAT_STAGE1:
digitalWrite(5, LOW);
digitalWrite(17, HIGH);
digitalWrite(16, HIGH);
digitalWrite(4, LOW);
break;
case HEAT_STAGE2:
digitalWrite(5, LOW);
digitalWrite(17, LOW);
digitalWrite(16, HIGH);
digitalWrite(4, LOW);
break;
case HEAT_STAGE3:
digitalWrite(5, LOW);
digitalWrite(17, LOW);
digitalWrite(16, LOW);
digitalWrite(4, LOW);
break;
case HEAT_HOLD:
digitalWrite(5, HIGH);
digitalWrite(17, LOW);
digitalWrite(16, HIGH);
digitalWrite(4, LOW);
break;
case HEAT_FAN_ONLY:
digitalWrite(5, HIGH);
digitalWrite(17, HIGH);
digitalWrite(16, HIGH);
digitalWrite(4, LOW);
break;
}
delay(68);
}
if (!ActCursorOnOff) {
heaterMode = (VirThFan > 0) ? HEAT_FAN_ONLY : HEAT_OFF;
if (VirThFan > 0) VirThFan -= 2;
switch (heaterMode) {
case HEAT_FAN_ONLY:
digitalWrite(5, HIGH);
digitalWrite(17, HIGH);
digitalWrite(16, HIGH);
digitalWrite(4, LOW);
break;
case HEAT_OFF:
digitalWrite(5, HIGH);
digitalWrite(17, HIGH);
digitalWrite(16, HIGH);
digitalWrite(4, HIGH);
break;
default:
break;
}
HCoCD = HCo;
HCoC = HCo;
MCo = 0;
MCoInc = " ";
SCoCDs = 0;
SCo = 0;
SCoInc = " ";
DayCoCD = DayCo;
DayCoC = DayCo;
DelyHeat = 0;
}
if (TempActS >= 85) {
digitalWrite(5, HIGH);
digitalWrite(17, HIGH);
digitalWrite(16, HIGH);
CautionTmp = "WARNIG";
}
else if ((TempActS >= 35) && (VirThFan <= 0)) {
digitalWrite(4, LOW);
CautionTmp = "SAFE";
}
}//=========================================== loop ========================================
void prosesKeypad(int KeyData) {
switch (KeyData) {
case '1': // ⬅️ Tombol turun
ActCursorY = (ActCursorY + 1 > 8) ? 0 : ActCursorY + 1;
ActCursorQRsh = 0;
break;
case '3': // ⬅️ Tombol naik
ActCursorY = (ActCursorY - 1 < 0) ? 8 : ActCursorY - 1;
ActCursorQRsh = 0;
break;
case '4': // ⬅️ Tombol kanan (aksi)
if (ActCursorY == 1) {
ActCursorOnOff = true;
CondtiTime = "ON ";
}
else if (ActCursorY == 2) {
NowFlmnt = min(NowFlmnt + 1, 6);
EEPROM.write(57, NowFlmnt);
EEPROM.commit();
aturFilament();
}
else if (ActCursorY == 3 && ShwThNow < 90) {
ShwThNow++;
ShwThM1 = ShwThNow - 1;
ShwThP1 = ShwThNow + 1;
simpanSuhuPreset();
}
else if (ActCursorY == 4) {
HCo = (HCo + 1) % 24;
EEPROM.write(60, HCo);
EEPROM.commit();
HCoCD = HCo;
DayCo = (HCo == 0) ? (DayCo + 1) % 11 : DayCo;
DayCoCD = DayCo;
EEPROM.write(59, DayCo);
EEPROM.commit();
}
else if (ActCursorY == 5) {
//hubungkanWiFi();
Serial.println("hubungkanWiFi");
}
else if (ActCursorY == 6) {
ActCursorQRsh = 1;
}
break;
case '5': // ⬅️ Tombol kiri (kembali/stop)
if (ActCursorY == 1) {
ActCursorOnOff = false;
CondtiTime = "OFF";
}
else if (ActCursorY == 2) {
NowFlmnt = max(NowFlmnt - 1, 0);
EEPROM.write(57, NowFlmnt);
EEPROM.commit();
aturFilament();
}
else if (ActCursorY == 3 && ShwThNow > 1) {
ShwThNow--;
ShwThM1 = ShwThNow - 1;
ShwThP1 = ShwThNow + 1;
simpanSuhuPreset();
}
else if (ActCursorY == 4) {
HCo = (HCo == 0) ? 23 : HCo - 1;
EEPROM.write(60, HCo);
EEPROM.commit();
HCoCD = HCo;
DayCo = (HCo == 23 && DayCo > 0) ? DayCo - 1 : DayCo;
DayCoCD = DayCo;
EEPROM.write(59, DayCo);
EEPROM.commit();
}
else if (ActCursorY == 5) {
//putuskanWiFi();
Serial.println("putuskanWiFi");
}
else if (ActCursorY == 6) {
ActCursorQRsh = 0;
}
break;
}
}
void aturFilament() {
switch (NowFlmnt) {
case 0: FlmtType = " PLA "; FlmtM1 = " NONE "; FlmtP1 = " ABS "; break;
case 1: FlmtType = " ABS "; FlmtM1 = " PLA "; FlmtP1 = " PETG "; break;
case 2: FlmtType = " PETG "; FlmtM1 = " ABS "; FlmtP1 = "PETG CF"; break;
case 3: FlmtType = "PETG CF"; FlmtM1 = " PETG "; FlmtP1 = " TPU "; break;
case 4: FlmtType = " TPU "; FlmtM1 = "PETG CF"; FlmtP1 = " PC ABS"; break;
case 5: FlmtType = " PC ABS"; FlmtM1 = " TPU "; FlmtP1 = " PA CF "; break;
case 6: FlmtType = " PA CF "; FlmtM1 = " PC ABS"; FlmtP1 = " NONE "; break;
}
ShwThNow = EEPROM.read(50 + NowFlmnt); // Ambil suhu preset sesuai filamen aktif
ShwThM1 = ShwThNow - 1;
ShwThP1 = ShwThNow + 1;
}
void simpanSuhuPreset() {
int addr = 50 + NowFlmnt;
EEPROM.write(addr, ShwThNow);
EEPROM.commit();
}
void tampilkanJamDiLCD() {
struct tm waktuSekarang;
if (!getLocalTime(&waktuSekarang)) {
Serial.println("Gagal mendapatkan waktu NTP");
return;
}
char buffer[6];
strftime(buffer, sizeof(buffer), "%H:%M:%S", &waktuSekarang);
display.fillRect(88, 0, 40, 10, SH110X_BLACK); // Hapus area kanan atas
display.setCursor(80, 0); // Posisi pojok kanan atas
display.print(buffer);
display.display();
}