// ================= THINGSPEAK CONFIG =================
#define THINGSPEAK_API_KEY "ISI_API_KEY_KAMU"
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <HX711.h>
#include <WiFi.h>
#include <HTTPClient.h>
// ================= PIN =================
#define LOADCELL_DOUT 32
#define LOADCELL_SCK 33
#define BUZZER 15
// PIN LED BARU
#define LED_RED 2
#define LED_YELLOW 4
#define LED_GREEN 5
#define BTN_ONOFF 25
#define BTN_UP 26
#define BTN_OK 27
#define BTN_DOWN 14
#define BTN_BACK 13
// ================= OBJEK =================
LiquidCrystal_I2C lcd(0x27, 16, 2);
HX711 scale;
// ================= VAR =================
float weightKg = 0;
float filteredKg = 0;
float beratFix = 0.0;
bool dataRecorded = false;
bool inMenu = false;
int menuIndex = 0;
bool inJenis = false;
int jenisIndex = 0;
bool isPowerOn = true;
bool wifiConnected = false;
struct DataSampah {
String nama;
int harga;
};
// Daftar 62 Jenis Sampah
const int JENIS_COUNT = 62;
DataSampah daftarSampah[JENIS_COUNT] = {
{"BOTOL PET A", 4000}, {"BOTOL PET B", 1200}, {"BOTOL PET C", 500},
{"BOTOL PET WARNA", 1000}, {"BOTOL PET PUTIH", 500}, {"GELAS PLASTK A", 3100},
{"GELAS PLASTK B", 1500}, {"GELAS MOUNTEA", 1300}, {"BOTOL PLASTIK HOPE/MAINAN", 2000},
{"BOTOL PLASTIK NASO", 3000}, {"PLASTIK PP INJECT", 3000}, {"EMBER WARNA", 1200},
{"EMBER HITAM", 700}, {"PLASTIK PS BENING/CRYSTAL", 3500}, {"TUTUP HD", 2000},
{"TUTUP LD", 2500}, {"GALON ISI ULANG", 4000}, {"GALON LEMINERAL", 3200},
{"BOTOL YAKULT", 400}, {"IMPACT KASAR", 500}, {"PARALON", 700},
{"ASSOY", 200}, {"PE PUTIH", 200}, {"PLASTIK SELOPAN", 150},
{"PLASTIK MIKA", 50}, {"PLASTIK SEDOTAN", 200}, {"KASET CD", 3000},
{"NILEK", 200}, {"MULTILAYER", 50}, {"GABRUKAN", 500}, {"BOTOL OLI", 2000},
{"KORAN", 1000}, {"KARDUS", 1500}, {"DUPLEX", 600},
{"KERTAS PUTIHAN", 1400}, {"KERTAS WARNA", 600}, {"LKS", 1000},
{"BUKU PELAJARAN", 1000}, {"KERTAS SEMEN", 1000}, {"TETRA PACK", 100},
{"TEMPAT TELOR", 200},
{"MONITOR/TV TABUNG", 10000}, {"LAPTOP/NOTEBOOK/LED/LCD", 20000}, {"MESIN CUCI 1 TABUNG", 30000},
{"MESIN CUCI 2 TABUNG", 35000}, {"LEMARI ES", 40000}, {"SMARTPHONE", 2500},
{"HP BIASA(GSM)", 5000}, {"SEPATU DAN SENDAL", 50},
{"BESI A", 3000}, {"BESI CAMPUR", 2000}, {"KALENG", 1800}, {"STAL/KABIN/ENAMEL", 2000},
{"ALUMUNIUM RONGSOK", 8000}, {"ALUMUNIUM PANCI", 9000}, {"BABET", 6000},
{"TEMBAGA KUPAS", 50000}, {"TEMBAGA BAKAR", 40000}, {"KUNINGAN", 30000},
{"AKI MOTOR/MOBIL", 6500},
{"BOTOL BELING", 200}, {"MINYAK JELANTAH", 5500}
};
String jenisDipilih = "-";
int hargaDipilih = 0;
unsigned long lastUpdate = 0;
bool lastBtn[5] = {HIGH, HIGH, HIGH, HIGH, HIGH};
// ================= WIFI =================
const char* WIFI_SSID = "Wokwi-GUEST";
const char* WIFI_PASS = "";
void connectWiFi() {
lcd.clear();
lcd.print("Connecting WiFi");
WiFi.begin(WIFI_SSID, WIFI_PASS);
int tries = 0;
while (WiFi.status() != WL_CONNECTED && tries < 20) {
delay(500);
lcd.setCursor(tries % 16, 1);
lcd.print(".");
tries++;
}
if (WiFi.status() == WL_CONNECTED) {
wifiConnected = true;
digitalWrite(LED_YELLOW, LOW);
lcd.clear();
lcd.print("WiFi Connected!");
lcd.setCursor(0, 1);
lcd.print(WiFi.localIP());
} else {
wifiConnected = false;
digitalWrite(LED_YELLOW, HIGH);
lcd.clear();
lcd.print("WiFi Gagal");
lcd.setCursor(0, 1);
lcd.print("Mode Offline");
}
delay(1500);
inMenu = false;
lcd.clear();
updateDisplay();
}
// ==== DISCONNECT WIFI ====
void disconnectWiFi() {
lcd.clear();
lcd.print("Disconnecting...");
WiFi.disconnect();
wifiConnected = false;
digitalWrite(LED_YELLOW, HIGH);
delay(1000);
lcd.clear();
lcd.print("Mode Offline");
lcd.setCursor(0, 1);
lcd.print("Siap Digunakan");
delay(1500);
inMenu = false;
lcd.clear();
updateDisplay();
}
// ================= THINGSPEAK =================
void sendToThingSpeak(float berat, String jenis) {
if (WiFi.status() != WL_CONNECTED) {
lcd.clear();
lcd.print("WiFi Offline!");
lcd.setCursor(0, 1);
lcd.print("Gagal Mengirim");
delay(1500);
return;
}
lcd.clear();
lcd.print("Mengirim...");
digitalWrite(LED_GREEN, HIGH);
String jenisAman = jenis;
jenisAman.replace(" ", "%20");
jenisAman.replace("/", "%2F");
HTTPClient http;
String url = "http://api.thingspeak.com/update?api_key=";
url += THINGSPEAK_API_KEY;
url += "&field1=" + String(berat, 2);
url += "&field2=" + jenisAman;
http.begin(url);
int httpCode = http.GET();
http.end();
if (httpCode > 0) {
lcd.clear();
lcd.print("Kirim Sukses!");
delay(1500);
digitalWrite(LED_GREEN, LOW);
} else {
lcd.clear();
lcd.print("Kirim Gagal!");
delay(1500);
digitalWrite(LED_GREEN, LOW);
}
}
// ================= BUZZER =================
void beep(int freq = 1200, int durMs = 50) {
ledcAttach(BUZZER, freq, 8);
ledcWrite(BUZZER, 128);
delay(durMs);
ledcWrite(BUZZER, 0);
ledcDetach(BUZZER);
}
// ================= SETUP =================
void setup() {
Serial.begin(115200);
lcd.init();
lcd.backlight();
// Setup PIN LED
pinMode(LED_RED, OUTPUT);
pinMode(LED_YELLOW, OUTPUT);
pinMode(LED_GREEN, OUTPUT);
// Status awal dinyalakan
digitalWrite(LED_RED, HIGH);
digitalWrite(LED_YELLOW, HIGH);
digitalWrite(LED_GREEN, LOW);
int btns[5] = {BTN_ONOFF, BTN_UP, BTN_OK, BTN_DOWN, BTN_BACK};
for (int i = 0; i < 5; i++) pinMode(btns[i], INPUT_PULLUP);
scale.begin(LOADCELL_DOUT, LOADCELL_SCK);
scale.set_scale(420.0);
scale.tare();
lcd.clear();
lcd.print(" Timbangan IoT ");
lcd.setCursor(0, 1);
lcd.print(" Mode Wokwi ");
delay(1200);
connectWiFi();
beep(1000, 200);
}
// ================= LOOP =================
void loop() {
readButtons();
if (isPowerOn) {
if (!inMenu && millis() - lastUpdate > 300) {
if (scale.is_ready()) {
weightKg = scale.get_units(1);
if (abs(weightKg - filteredKg) < 0.02) weightKg = filteredKg;
filteredKg = filteredKg * 0.7 + weightKg * 0.3;
if (filteredKg < 0) filteredKg = 0;
}
updateDisplay();
lastUpdate = millis();
}
}
}
// ================= BUTTON =================
void readButtons() {
int pins[5] = {BTN_ONOFF, BTN_UP, BTN_OK, BTN_DOWN, BTN_BACK};
for (int i = 0; i < 5; i++) {
bool cur = digitalRead(pins[i]);
if (lastBtn[i] == HIGH && cur == LOW) handleButton(i);
lastBtn[i] = cur;
}
}
void handleButton(int i) {
beep();
if (i == 0) {
isPowerOn = !isPowerOn;
if (!isPowerOn) {
digitalWrite(LED_RED, LOW);
digitalWrite(LED_YELLOW, LOW);
digitalWrite(LED_GREEN, LOW);
lcd.clear(); lcd.print("Power Off..."); delay(1000);
lcd.clear(); lcd.noBacklight();
} else {
digitalWrite(LED_RED, HIGH);
if (!wifiConnected) digitalWrite(LED_YELLOW, HIGH);
lcd.backlight(); lcd.clear(); lcd.print("Power On..."); delay(1000);
lcd.clear(); updateDisplay();
}
return;
}
if (!isPowerOn) return;
if (!inMenu && i == 2) {
inMenu = true; menuIndex = 0; showMenu(); return;
}
if (inMenu && !inJenis) {
if (i == 1) menuIndex = (menuIndex + 4) % 5;
if (i == 3) menuIndex = (menuIndex + 1) % 5;
if (i == 2) {
if (menuIndex == 1) { inJenis = true; jenisIndex = 0; showJenis(); return; }
else { menuSelect(); }
}
if (i == 4) { inMenu = false; lcd.clear(); updateDisplay(); return; }
showMenu(); return;
}
if (inJenis) {
if (i == 1) jenisIndex = (jenisIndex + JENIS_COUNT - 1) % JENIS_COUNT;
if (i == 3) jenisIndex = (jenisIndex + 1) % JENIS_COUNT;
if (i == 2) {
jenisDipilih = daftarSampah[jenisIndex].nama;
hargaDipilih = daftarSampah[jenisIndex].harga;
lcd.clear(); lcd.print("Pilih: "); lcd.setCursor(0, 1);
lcd.print(jenisDipilih.substring(0, 16)); delay(1000);
inMenu = false; inJenis = false; lcd.clear(); updateDisplay(); return;
}
if (i == 4) { inJenis = false; showMenu(); return; }
showJenis(); return;
}
}
// ================= MENU DISPLAY =================
void showMenu() {
lcd.clear();
lcd.setCursor(0, 0); lcd.print("> ");
printMenuItem(menuIndex);
lcd.setCursor(0, 1); lcd.print(" ");
printMenuItem((menuIndex + 1) % 5);
}
void printMenuItem(int idx) {
const char* items[] = {"Ukur", "Jenis", "Connect", "Disconnect", "Status"};
lcd.print(items[idx]);
}
void menuSelect() {
switch (menuIndex) {
case 0: selectUkur(); break;
case 1: selectJenis(); break;
case 2: connectWiFi(); break;
case 3: disconnectWiFi(); break;
case 4: selectStatus(); break;
}
}
void showJenis() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(">Pilih Jenis:");
lcd.setCursor(0, 1);
lcd.print(daftarSampah[jenisIndex].nama.substring(0, 16));
}
void updateDisplay() {
lcd.setCursor(0, 0);
lcd.print("Berat: ");
lcd.print(filteredKg, 2);
lcd.print(" kg");
lcd.setCursor(0, 1);
lcd.print("Jenis: ");
String j = jenisDipilih;
if (j.length() > 9) j = j.substring(0, 9);
lcd.print(j);
for (int k = j.length(); k < 9; k++) lcd.print(" ");
}
void selectUkur() {
if (!dataRecorded) {
beratFix = filteredKg; dataRecorded = true;
lcd.clear(); lcd.print("Data Direkam:"); lcd.setCursor(0, 1);
lcd.print(beratFix, 2); lcd.print(" kg"); delay(1500);
} else {
if (WiFi.status() != WL_CONNECTED) {
sendToThingSpeak(beratFix, jenisDipilih);
} else {
sendToThingSpeak(beratFix, jenisDipilih);
}
dataRecorded = false; inMenu = false; lcd.clear(); updateDisplay();
}
}
void selectJenis() { inJenis = true; jenisIndex = 0; showJenis(); }
void selectStatus() {
lcd.clear();
lcd.print("IP:");
if (wifiConnected) {
lcd.print(WiFi.localIP());
} else {
lcd.print("Offline");
}
lcd.setCursor(0, 1);
lcd.print(wifiConnected ? "Status: ONLINE" : "Status: OFFLINE");
delay(2000);
inMenu = false;
lcd.clear();
updateDisplay();
}