#include <Fuzzy.h>
#include <FuzzyInput.h>
#include <FuzzyOutput.h>
#include <FuzzyRule.h>
#include <FuzzyRuleAntecedent.h>
#include <FuzzyRuleConsequent.h>
#include <FuzzySet.h>
#include <DHT.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// ===== PIN ESP32 =====
#define DHTPIN 15
#define LED_PIN 2 // Pin yang mendukung PWM pada ESP32
#define DHTTYPE DHT22
// OLED Setup
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// DHT Object
DHT dht(DHTPIN, DHTTYPE);
// Fuzzy Object
Fuzzy *fuzzy = new Fuzzy();
void setup() {
Serial.begin(115200);
dht.begin();
// Inisialisasi pin LED sebagai OUTPUT
pinMode(LED_PIN, OUTPUT);
// ===== OLED =====
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
// Tampilkan splash screen
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(2);
display.setCursor(10, 15);
display.println("FUZZY");
display.setCursor(10, 35);
display.println("TEMP LED");
display.setTextSize(1);
display.setCursor(30, 55);
display.println("Starting...");
display.display();
delay(1500);
// ===== Membership Function Suhu =====
FuzzySet *dingin = new FuzzySet(0, 0, 20, 24);
FuzzySet *normal = new FuzzySet(22, 26, 30, 34);
FuzzySet *panas = new FuzzySet(32, 36, 45, 45);
FuzzyInput *suhu = new FuzzyInput(1);
suhu->addFuzzySet(dingin);
suhu->addFuzzySet(normal);
suhu->addFuzzySet(panas);
fuzzy->addFuzzyInput(suhu);
// ===== OUTPUT LED (0–255) =====
FuzzySet *off = new FuzzySet(0, 0, 0, 5);
FuzzySet *low = new FuzzySet(10, 20, 40, 60);
FuzzySet *mid = new FuzzySet(70, 100, 130, 160);
FuzzySet *high = new FuzzySet(170, 210, 255, 255);
FuzzyOutput *ledOut = new FuzzyOutput(1);
ledOut->addFuzzySet(off);
ledOut->addFuzzySet(low);
ledOut->addFuzzySet(mid);
ledOut->addFuzzySet(high);
fuzzy->addFuzzyOutput(ledOut);
// ===== PERUBAHAN RULES: LOGIKA DIBALIK =====
// Rule 1: Jika dingin → LED HIGH (dibanding OFF)
FuzzyRuleAntecedent *IF_dingin = new FuzzyRuleAntecedent();
IF_dingin->joinSingle(dingin);
FuzzyRuleConsequent *THEN_high = new FuzzyRuleConsequent(); // Changed to HIGH
THEN_high->addOutput(high);
fuzzy->addFuzzyRule(new FuzzyRule(1, IF_dingin, THEN_high));
// Rule 2: Jika normal → LED MID (tetap sama)
FuzzyRuleAntecedent *IF_normal = new FuzzyRuleAntecedent();
IF_normal->joinSingle(normal);
FuzzyRuleConsequent *THEN_mid = new FuzzyRuleConsequent();
THEN_mid->addOutput(mid);
fuzzy->addFuzzyRule(new FuzzyRule(2, IF_normal, THEN_mid));
// Rule 3: Jika panas → LED OFF (dibanding HIGH)
FuzzyRuleAntecedent *IF_panas = new FuzzyRuleAntecedent();
IF_panas->joinSingle(panas);
FuzzyRuleConsequent *THEN_off = new FuzzyRuleConsequent(); // Changed to OFF
THEN_off->addOutput(off);
fuzzy->addFuzzyRule(new FuzzyRule(3, IF_panas, THEN_off));
Serial.println("System Ready!");
Serial.println("Logika terbalik: Dingin->HIGH, Panas->OFF");
Serial.println("==========================");
}
void loop() {
float t = dht.readTemperature();
if (isnan(t)) {
Serial.println("Sensor Error!");
// Tampilkan error di OLED dengan tampilan rapi
display.clearDisplay();
display.setTextSize(2);
display.setCursor(15, 10);
display.println("ERROR!");
display.setTextSize(1);
display.setCursor(10, 35);
display.println("DHT22 Sensor Not");
display.setCursor(25, 45);
display.println("Found");
display.setTextSize(1);
display.setCursor(20, 55);
display.println("Check Connection");
display.display();
delay(2000);
return;
}
// ===== FUZZY PROCESS =====
fuzzy->setInput(1, t);
fuzzy->fuzzify();
int output = fuzzy->defuzzify(1);
output = constrain(output, 0, 255); // Pastikan output dalam range 0-255
// Kontrol LED menggunakan analogWrite()
analogWrite(LED_PIN, output);
// Status LED berdasarkan output fuzzy
String status;
if (output < 10) {
status = "OFF";
} else if (output < 70) {
status = "LOW";
} else if (output < 160) {
status = "MID";
} else {
status = "HIGH";
}
// ===== OLED DISPLAY - TAMPILAN RAPI =====
display.clearDisplay();
// Header dengan box
display.drawRect(0, 0, 128, 16, WHITE);
display.fillRect(0, 0, 128, 16, WHITE);
display.setTextColor(BLACK);
display.setTextSize(1);
display.setCursor(10, 5);
display.println("FUZZY CONTROL");
display.setTextColor(WHITE);
// Informasi Suhu
display.setTextSize(1);
display.setCursor(0, 20);
display.print("SUHU:");
display.setTextSize(2);
display.setCursor(40, 18);
display.print(t, 1);
display.setTextSize(1);
display.setCursor(85, 25);
display.print("C");
// Separator line
display.drawLine(0, 38, 128, 38, WHITE);
// Status dan Output
display.setTextSize(1);
display.setCursor(0, 42);
// Warna status berdasarkan kondisi
if (status == "OFF") {
display.println("OFF");
} else if (status == "LOW") {
display.println("LOW");
} else if (status == "MID") {
display.println("MID");
} else {
display.println("HIGH");
}
display.setCursor(0, 52);
display.print(output);
display.print("/255");
// Bar meter LED dengan frame
display.drawRect(70, 42, 56, 20, WHITE);
// Isi bar meter (horizontal)
int barLength = map(output, 0, 255, 0, 54);
display.fillRect(72, 44, barLength, 16, WHITE);
// Label 0 dan 255 di bawah bar
display.setTextSize(1);
display.setCursor(70, 62);
display.print("0");
display.setCursor(120, 62);
display.print("255");
// Indicator segitiga di atas bar
int trianglePos = map(output, 0, 255, 70, 124);
display.fillTriangle(trianglePos, 41, trianglePos-3, 36, trianglePos+3, 36, WHITE);
display.display();
// Serial Monitor
Serial.print("Suhu: ");
Serial.print(t, 1);
Serial.print("C | Output: ");
Serial.print(output);
Serial.print(" | Status: ");
Serial.println(status);
delay(1000); // Update setiap 1 detik
}