commit ad37effcedb476cf2858dd8d87514ee482d45b00 Author: lindadwiwinandha Date: Tue Aug 5 10:53:24 2025 +0700 Upload files to "/" diff --git a/Celengan_Final.ino b/Celengan_Final.ino new file mode 100644 index 0000000..8273359 --- /dev/null +++ b/Celengan_Final.ino @@ -0,0 +1,280 @@ +#include +#include +#include +#include + +// --- THINGER.IO --- +#define USERNAME "lindadwi" +#define DEVICE_ID "Celengan_Pintar" +#define DEVICE_CREDENTIAL "celengan8266" +#define SSID "ozie 3" +#define PASSWORD "followkami" +ThingerESP8266 thing(USERNAME, DEVICE_ID, DEVICE_CREDENTIAL); + +// --- TCS3200 --- +#define S0 D5 +#define S1 D6 +#define S2 D7 +#define S3 D8 +#define sensorOut D3 + +// --- RELAY & SWITCH --- +#define RELAY_PIN D0 +#define SWITCH_PIN D4 + +// --- KEYPAD PCF8574 --- +Adafruit_PCF8574 pcf; +const byte ROWS = 4, COLS = 3; +char keys[ROWS][COLS] = { + {'1','2','3'}, + {'4','5','6'}, + {'7','8','9'}, + {'*','0','#'} +}; +int rowPins[4] = {0, 1, 2, 3}; +int colPins[3] = {4, 5, 6}; + +// --- LCD I2C --- +LiquidCrystal_I2C lcd(0x27, 16, 2); + +// --- GLOBAL --- +String nominal = "Tidak dikenali"; +const int TOLERANSI = 20; +String inputSandi = ""; +bool relayAktif = false; +bool pintuBaruDibuka = false; +bool pintuTerbukaSebelumnya = false; +int totalSaldo = 0; + +void setup() { + Serial.begin(9600); + + // Thinger + thing.add_wifi(SSID, PASSWORD); + + // Resource realtime saldo + thing["total_saldo"] >> [](pson &out){ + out = totalSaldo; + }; + + // TCS3200 + pinMode(S0, OUTPUT); pinMode(S1, OUTPUT); + pinMode(S2, OUTPUT); pinMode(S3, OUTPUT); + pinMode(sensorOut, INPUT); + digitalWrite(S0, HIGH); + digitalWrite(S1, LOW); + + // RELAY & SWITCH + pinMode(RELAY_PIN, OUTPUT); + digitalWrite(RELAY_PIN, HIGH); // Relay OFF + pinMode(SWITCH_PIN, INPUT_PULLUP); + + // KEYPAD + if (!pcf.begin(0x20)) { + Serial.println("PCF8574 tidak terdeteksi!"); + while (1); + } + for (int i = 0; i < 8; i++) pcf.pinMode(i, INPUT_PULLUP); + + // LCD + lcd.begin(16, 2); + lcd.backlight(); + lcd.setCursor(0, 0); + lcd.print("Masukkan uang"); +} + +// === LOOP === +void loop() { + thing.handle(); + + bool pintuTertutup = digitalRead(SWITCH_PIN) == LOW; + + // Deteksi pintu dibuka untuk reset saldo + if (!pintuTertutup && !pintuTerbukaSebelumnya) { + if (totalSaldo > 0) { + Serial.println("Pintu dibuka - reset saldo"); + pson data; + data["status"] = "diambil"; + data["saldo"] = totalSaldo; + thing.write_bucket("data_uang", data); + totalSaldo = 0; + } + pintuTerbukaSebelumnya = true; + } + + if (pintuTertutup && pintuTerbukaSebelumnya) { + pintuTerbukaSebelumnya = false; + } + + // Kontrol relay berdasarkan status + if (relayAktif) { + if (!pintuTertutup) { + pintuBaruDibuka = true; + } else if (pintuBaruDibuka && pintuTertutup) { + relayAktif = false; + digitalWrite(RELAY_PIN, HIGH); // Relay OFF + pintuBaruDibuka = false; + Serial.println("Pintu ditutup kembali - Relay OFF"); + lcd.setCursor(0, 0); + lcd.print("Pintu tertutup "); + lcd.setCursor(0, 1); + lcd.print("Akses selesai "); + delay(2000); + lcd.setCursor(0, 0); + lcd.print("Masukkan uang "); + lcd.setCursor(0, 1); + lcd.print(" "); + } + } + + // === TOMBOL === + char tombol = bacaTombol(); + if (tombol != 0) { + inputSandi += tombol; + if (inputSandi.length() > 4) inputSandi.remove(0, 1); + + lcd.setCursor(0, 0); + lcd.print("Masukkan sandi "); + lcd.setCursor(0, 1); + lcd.print(inputSandi + " "); + + if (tombol == '*') { + if (nominal != "Tidak dikenali") { + int nilai = konversiNominalKeInt(nominal); + if (nilai > 0) { + totalSaldo += nilai; + + lcd.setCursor(0, 0); + lcd.print("Akses diterima "); + lcd.setCursor(0, 1); + lcd.print("Tambah: " + nominal + " "); + + Serial.println("Menambah: " + nominal); + + pson data; + data["status"] = "tambah"; + data["saldo"] = totalSaldo; + data["nominal"] = nominal; + thing.write_bucket("data_uang", data); + + delay(2000); + lcd.setCursor(0, 0); + lcd.print("Masukkan uang "); + lcd.setCursor(0, 1); + lcd.print(" "); + } + } + else if (inputSandi == "123*") { + if (pintuTertutup) { + relayAktif = true; + digitalWrite(RELAY_PIN, LOW); // Relay ON + Serial.println("Akses diterima - Relay ON"); + lcd.setCursor(0, 0); + lcd.print("Akses diterima "); + } else { + Serial.println("Pintu tidak rapat"); + lcd.setCursor(0, 0); + lcd.print("Pintu terbuka "); + } + lcd.setCursor(0, 1); + lcd.print(" "); + delay(2000); + lcd.setCursor(0, 0); + lcd.print("Masukkan uang "); + lcd.setCursor(0, 1); + lcd.print(" "); + } + else { + relayAktif = false; + digitalWrite(RELAY_PIN, HIGH); // Relay OFF + Serial.println("Akses ditolak"); + lcd.setCursor(0, 0); + lcd.print("Akses ditolak "); + lcd.setCursor(0, 1); + lcd.print(" "); + delay(2000); + lcd.setCursor(0, 0); + lcd.print("Masukkan uang "); + lcd.setCursor(0, 1); + lcd.print(" "); + } + inputSandi = ""; + } + } + + // === DETEKSI WARNA === + int red = bacaWarna(LOW, LOW); + int green = bacaWarna(HIGH, HIGH); + int blue = bacaWarna(LOW, HIGH); + + Serial.print("R: "); Serial.print(red); + Serial.print(" G: "); Serial.print(green); + Serial.print(" B: "); Serial.println(blue); + + nominal = detectUang(red, green, blue); + Serial.println("Terdeteksi: " + nominal); + + lcd.setCursor(0, 1); + if (nominal == "Tidak dikenali") { + lcd.print("... "); + } else { + lcd.print("Nominal: " + nominal + " "); + } + + delay(1000); +} + +// === BACA WARNA === +int bacaWarna(bool s2, bool s3) { + digitalWrite(S2, s2); + digitalWrite(S3, s3); + return pulseIn(sensorOut, LOW); +} + +// === KONVERSI NOMINAL === +int konversiNominalKeInt(String nominal) { + if (nominal == "1k") return 1000; + if (nominal == "2k") return 2000; + if (nominal == "5k") return 5000; + if (nominal == "10k") return 10000; + if (nominal == "20k") return 20000; + if (nominal == "50k") return 50000; + if (nominal == "100k") return 100000; + return 0; +} + +// === DETEKSI UANG === +bool isInRange(int val, int ref) { + return val >= (ref - TOLERANSI) && val <= (ref + TOLERANSI); +} + +String detectUang(int r, int g, int b) { + if (isInRange(r,195) && isInRange(g,200) && isInRange(b,196)) return "1k"; + if (isInRange(r,132) && isInRange(g,165) && isInRange(b,132)) return "2k"; + if (isInRange(r,215) && isInRange(g,260) && isInRange(b,215)) return "10k"; + if (isInRange(r,155) && isInRange(g,157) && isInRange(b,155)) return "20k"; + if (isInRange(r,137) && isInRange(g,170) && isInRange(b,137)) return "50k"; + if (isInRange(r,148) && isInRange(g,167) && isInRange(b,148)) return "100k"; + if (isInRange(r,175) && isInRange(g,171) && isInRange(b,175)) return "5k"; + return "Tidak dikenali"; +} + +// === BACA TOMBOL === +char bacaTombol() { + for (int r = 0; r < ROWS; r++) { + pcf.pinMode(rowPins[r], OUTPUT); + pcf.digitalWrite(rowPins[r], LOW); + delayMicroseconds(50); + + for (int c = 0; c < COLS; c++) { + if (!pcf.digitalRead(colPins[c])) { + char key = keys[r][c]; + while (!pcf.digitalRead(colPins[c])); + pcf.pinMode(rowPins[r], INPUT_PULLUP); + return key; + } + } + pcf.pinMode(rowPins[r], INPUT_PULLUP); + } + return 0; +}