diff --git a/Kode_arduino.ino b/Kode_arduino.ino new file mode 100644 index 0000000..9f0b182 --- /dev/null +++ b/Kode_arduino.ino @@ -0,0 +1,233 @@ +#include +#include +#include +#include +#include +#if defined(ESP8266)|| defined(ESP32) || defined(AVR) +#include +#endif + +// === WIFI & FIREBASE === +#define WIFI_SSID "..." +#define WIFI_PASSWORD "12345678" +#define API_KEY "AIzaSyDQ0zYJrQqCMrAU0-iO0qtCmXCR3wnG0wc" +#define DATABASE_URL "https://timbangan-ae018-default-rtdb.firebaseio.com/" +#define LEGACY_TOKEN "svzBUSZ6M8ANPs1uGuI4sxNeU2MLq3pEaDiYalgB" + +FirebaseData fbdo; +FirebaseAuth auth; +FirebaseConfig config; + +// === SENSOR BERAT === +const int HX711_dout = 23; +const int HX711_sck = 4; +HX711_ADC LoadCell(HX711_dout, HX711_sck); + +// === SENSOR ULTRASONIK === +#define TRIG_PIN 5 +#define ECHO_PIN 18 + +LiquidCrystal_I2C lcd(0x27, 16, 2); + +const int calVal_eepromAdress = 0; +unsigned long t = 0; +float calibrationFactor = 21.69; +long customOffset = 0; + +#define NUM_SAMPLES 5 +float beratBuffer[NUM_SAMPLES]; +int bufferIndex = 0; +bool isWeightLocked = false; + +float getSmoothedWeight(float newReading) { + beratBuffer[bufferIndex] = newReading; + bufferIndex = (bufferIndex + 1) % NUM_SAMPLES; + float total = 0; + for (int i = 0; i < NUM_SAMPLES; i++) { + total += beratBuffer[i]; + } + return total / NUM_SAMPLES; +} + +long readDistanceCM() { + digitalWrite(TRIG_PIN, LOW); + delayMicroseconds(2); + digitalWrite(TRIG_PIN, HIGH); + delayMicroseconds(10); + digitalWrite(TRIG_PIN, LOW); + long duration = pulseIn(ECHO_PIN, HIGH, 30000); // timeout 30ms + long distance = duration * 0.034 / 2; + return distance; +} + +double hitungBMI(double berat, double tinggi) { + if (tinggi == 0) return 0; + double tinggiMeter = tinggi / 100.0; // Konversi tinggi ke meter + return berat / (tinggiMeter * tinggiMeter); // Rumus BMI +} + +String kategoriBMI(double bmi) { + if (bmi < 18.5) return "Kurus"; + if (bmi <= 24.9) return "Normal"; + if (bmi <= 29.9) return "Berlebih"; + return "Obesitas"; +} + +void setup() { + Serial.begin(115200); + Serial.println("Memulai..."); + + // Inisialisasi pin ultrasonik + pinMode(TRIG_PIN, OUTPUT); + pinMode(ECHO_PIN, INPUT); + + // LCD + lcd.init(); + lcd.backlight(); + lcd.clear(); + lcd.setCursor(0, 0); + lcd.print("Menghubungkan..."); + + // WiFi + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + unsigned long start = millis(); + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + if (millis() - start > 20000) { + Serial.println("Gagal Koneksi WiFi!"); + lcd.clear(); + lcd.setCursor(0, 0); + lcd.print("Gagal WiFi"); + return; + } + } + Serial.println("WiFi Terhubung!"); + lcd.clear(); + lcd.setCursor(0, 0); + lcd.print("WiFi Terhubung"); + + // Firebase + config.api_key = API_KEY; + config.database_url = DATABASE_URL; + config.signer.tokens.legacy_token = LEGACY_TOKEN; + Firebase.begin(&config, &auth); + Firebase.reconnectWiFi(true); + + // LoadCell + LoadCell.begin(); + unsigned long stabilizingtime = 2000; + boolean _tare = true; + LoadCell.start(stabilizingtime, _tare); + if (LoadCell.getTareTimeoutFlag() || LoadCell.getSignalTimeoutFlag()) { + Serial.println("Timeout HX711"); + lcd.clear(); + lcd.setCursor(0, 0); + lcd.print("HX711 Error"); + while (1); + } + LoadCell.setCalFactor(calibrationFactor); + while (!LoadCell.update()); +} +void loop() { + static boolean newDataReady = 0; + const int serialPrintInterval = 3000; + + if (LoadCell.update()) newDataReady = true; + + if (newDataReady && millis() > t + serialPrintInterval && Firebase.ready()) { + // ====== BACA BERAT ====== + float berat = LoadCell.getData(); + if (berat < 0) berat = 0; + float beratKg = berat / 1000.0; + float rataRataBerat = getSmoothedWeight(beratKg); + if (!isWeightLocked && abs(rataRataBerat - beratKg) < 0.1) { + isWeightLocked = true; + } + + // ====== BACA TINGGI DARI ULTRASONIK ====== + long jarak = readDistanceCM(); // cm + float tinggi = 201.0 - jarak; + if (jarak > 201 || tinggi < 0) { + tinggi = 0; + } + + // ====== HITUNG BMI ====== + double bmi = hitungBMI(rataRataBerat, tinggi); + + // ====== TAMPILKAN DI LCD ====== + lcd.clear(); + lcd.setCursor(0, 0); + lcd.print("B: "); + lcd.print(rataRataBerat, 1); + lcd.print("kg T: "); + lcd.print(tinggi, 0); + lcd.print("cm"); + + lcd.setCursor(0, 1); + char output[10]; + dtostrf(bmi, 4, 1, output); // Convert to string with 1 decimal point + lcd.print("BMI: "); + lcd.print(output); // Display BMI on LCD + + Serial.printf("Berat: %.2f kg | Tinggi: %.0f cm (Jarak: %ld cm) | BMI: %.1f\n", rataRataBerat, tinggi, jarak, bmi); + + // ====== KIRIM KE FIREBASE ====== + Firebase.RTDB.setFloat(&fbdo, "/sensor/berat", rataRataBerat); + Firebase.RTDB.setFloat(&fbdo, "/sensor/tinggi", tinggi); + Firebase.RTDB.setFloat(&fbdo, "/sensor/bmi", bmi); // Kirim BMI ke Firebase + + newDataReady = 0; + t = millis(); + } + + if (Serial.available() > 0) { + char inByte = Serial.read(); + if (inByte == 't') LoadCell.tareNoDelay(); + else if (inByte == 'r') calibrate(); + else if (inByte == 'c') changeSavedCalFactor(); + } + + if (LoadCell.getTareStatus() == true) { + Serial.println("Tare complete"); + } +} + +void calibrate() { + Serial.println("* Start calibration... Kirim 't' untuk tare"); +} + +void changeSavedCalFactor() { + float oldVal = LoadCell.getCalFactor(); + boolean _resume = false; + Serial.print("Current: "); Serial.println(oldVal); + Serial.println("Kirim nilai baru:"); + float newVal; + while (!_resume) { + if (Serial.available() > 0) { + newVal = Serial.parseFloat(); + if (newVal != 0) { + LoadCell.setCalFactor(newVal); + _resume = true; + } + } + } + + _resume = false; + Serial.println("Simpan ke EEPROM? y/n"); + while (!_resume) { + if (Serial.available() > 0) { + char inByte = Serial.read(); + if (inByte == 'y') { + EEPROM.begin(512); + EEPROM.put(calVal_eepromAdress, newVal); + EEPROM.commit(); + Serial.println("Disimpan."); + _resume = true; + } else if (inByte == 'n') { + Serial.println("Tidak disimpan."); + _resume = true; + } + } + } +}