CODE (C++) SISTEM MONITORING BOBOT (Rancangan Ulul Azmi TPB20)


Code: 

// ======================================

// IOT KANCIL BETA 5.1 (STANDALONE)

// MASS + SHT31 + CLOUD + SD BACKUP

// WIFI ICON LCD + SINGLE BUTTON (PIN 25)

// ======================================


#include "HX711.h"

#include <Wire.h>

#include <LiquidCrystal_I2C.h>


#include <WiFi.h>

#include "time.h"


#include <ESP_Google_Sheet_Client.h>

#include <GS_SDHelper.h>


#include <SPI.h>

#include <SD.h>


// PUSTAKA SHT31

#include <Adafruit_SHT31.h>


// ======================================

// WIFI

// ======================================


#define WIFI_SSID "BONJOUR"

#define WIFI_PASSWORD "12341234"


// ======================================

// GOOGLE CLOUD

// ======================================


#define PROJECT_ID "masukkan disini"


#define CLIENT_EMAIL "masukkan disini"


const char PRIVATE_KEY[] PROGMEM = R"EOF(

-----BEGIN PRIVATE KEY-----

"masukkan disini"

-----END PRIVATE KEY-----

)EOF";


// ======================================

// SPREADSHEET

// ======================================


const char spreadsheetId[] =

"masukkan disini";


// ======================================

// SD CARD

// ======================================


#define SD_CS 4


File dataFile;


const char* fileName =

"/kancil_log.csv";


bool sdReady = false;


// ======================================

// HX711

// ======================================


#define DT 32

#define SCK 33


HX711 scale;


// ======================================

// SHT31 (Pengganti DHT22)

// ======================================

Adafruit_SHT31 sht31 = Adafruit_SHT31();


float temp;

float hum;


// ======================================

// PUSH BUTTON TUNGGAL (TAMBAHAN BETA 5.1)

// ======================================

#define BUTTON_PIN 25


unsigned long buttonPressTime = 0;

bool lastButtonState = HIGH;

bool buttonHandled = false;


// ======================================

// LCD

// ======================================


LiquidCrystal_I2C lcd(0x27, 16, 2);


// WIFI ICON

byte wifiIcon[8] = {

  B00000,

  B01110,

  B10001,

  B00100,

  B01010,

  B00000,

  B00100,

  B00000

};


// ======================================

// KALIBRASI

// ======================================


float calibration_factor = 818;


// ======================================

// VARIABEL

// ======================================


float lastMass = 0;


unsigned long lastSerial = 0;


unsigned long lastLog = 0;


const unsigned long logInterval =

30000;


bool loggingAktif = true;


// ======================================

// NTP

// ======================================


const char* ntpServer =

"pool.ntp.org";


unsigned long epochTime;


// ======================================

// GET TIME

// ======================================


unsigned long getTime() {


  time_t now;

  struct tm timeinfo;


  if (!getLocalTime(&timeinfo)) {

    return 0;

  }


  time(&now);


  return now;


}


// ======================================

// TOKEN CALLBACK

// ======================================


void tokenStatusCallback(

  TokenInfo info

) {


  if (info.status ==

      token_status_error) {


    GSheet.printf(

      "Token error: %s\n",

      GSheet.getTokenError(info)

      .c_str()

    );


  }

}


// ======================================

// SETUP

// ======================================


void setup() {


  Serial.begin(115200);


  // Inisialisasi Tombol

  pinMode(BUTTON_PIN, INPUT_PULLUP);


  Wire.begin(21, 22);


  // LCD

  lcd.init();

  lcd.backlight();


  lcd.createChar(0, wifiIcon);


  lcd.clear();


  lcd.setCursor(0, 0);


  lcd.print("IOT Kancil");


  lcd.setCursor(0, 1);

  lcd.print("Beta 5.1"); // Update text


  delay(2000);


  // HX711

  scale.begin(DT, SCK);


  scale.set_scale(

    calibration_factor

  );


  // SHT31 INISIALISASI (Alamat default 0x44)

  lcd.clear();

  lcd.setCursor(0, 0);

  if (!sht31.begin(0x44)) {

    Serial.println("SHT31 tidak terdeteksi. Cek koneksi kabel I2C.");

    lcd.print("SHT31: ERROR!");

  } else {

    lcd.print("SHT31: OK!");

  }

  delay(1500);


  // WIFI

  WiFi.setAutoReconnect(true);


  WiFi.begin(

    WIFI_SSID,

    WIFI_PASSWORD

  );


  lcd.clear();


  lcd.setCursor(0, 0);

  lcd.print("Connecting WiFi");


  while (WiFi.status() !=

         WL_CONNECTED) {


    delay(1000);


  }


  lcd.clear();


  lcd.setCursor(0, 0);

  lcd.print("WiFi Connected");


  delay(1000);


  // NTP

  configTime(0, 0, ntpServer);


  // GOOGLE SHEETS

  GSheet.setTokenCallback(

    tokenStatusCallback

  );


  GSheet.setPrerefreshSeconds(

    10 * 60

  );


  GSheet.begin(

    CLIENT_EMAIL,

    PROJECT_ID,

    PRIVATE_KEY

  );


  // SD CARD

  lcd.clear();

  lcd.setCursor(0, 0);

  if (SD.begin(SD_CS)) {


    sdReady = true;


    Serial.println("SD OK");

    lcd.print("SD Card: OK!");


    if (!SD.exists(fileName)) {


      dataFile =

      SD.open(fileName,

              FILE_WRITE);


      if (dataFile) {


        dataFile.println(

          "timestamp,mass_g,temp_c,rh"

        );


        dataFile.close();

      }

    }


  } else {


    sdReady = false;


    Serial.println("SD Failed");

    lcd.print("SD Card: ERROR!");


  }


  delay(2000);

  lcd.clear();

}


// ======================================

// LOOP

// ======================================


void loop() {


  bool ready = GSheet.ready();


  // WIFI RECONNECT

  if (WiFi.status() !=

      WL_CONNECTED) {


    WiFi.reconnect();


  }


  // ======================================

  // LOGIKA PUSH BUTTON (Pengganti Serial Command)

  // ======================================

  bool currentButtonState = digitalRead(BUTTON_PIN);


  // Deteksi tombol baru mulai ditekan

  if (currentButtonState == LOW && lastButtonState == HIGH) {

    buttonPressTime = millis();

    buttonHandled = false;

  }


  // Deteksi jika tombol sedang ditahan (> 3 detik)

  if (currentButtonState == LOW && !buttonHandled) {

    if (millis() - buttonPressTime >= 3000) {

      

      loggingAktif = false;

      buttonHandled = true;


      Serial.println("Logging stopped");

      

      lcd.clear();

      lcd.setCursor(0, 0);

      lcd.print("Logging Stop");

      

      delay(3000);

      lcd.clear();

    }

  }


  // Deteksi jika tombol dilepas cepat (< 3 detik)

  if (currentButtonState == HIGH && lastButtonState == LOW) {

    if (!buttonHandled) {

      

      lcd.clear();

      lcd.setCursor(0, 0);

      lcd.print("Tare...");


      scale.tare(50);

      lastMass = 0;


      delay(1000);

      lcd.clear();

    }

  }

  lastButtonState = currentButtonState;


  // READ MASS

  float mass =

    scale.get_units(5);


  // READ SHT31 (Pengganti DHT22)

  temp = sht31.readTemperature();

  hum = sht31.readHumidity();


  // DEAD ZONE

  if (mass > -0.3 &&

      mass < 0.3 &&

      lastMass > -0.3 &&

      lastMass < 0.3) {


    mass = 0;


  }


  // HOLD FILTER

  if (abs(mass - lastMass)

      < 0.1) {


    mass = lastMass;


  } else {


    lastMass = mass;

  }


  // LOGGING

  if (loggingAktif &&

      millis() - lastLog >=

      logInterval) {


    lastLog = millis();


    epochTime = getTime();


    // SD SAVE

    if (sdReady) {


      dataFile =

      SD.open(fileName,

              FILE_APPEND);


      if (dataFile) {


        dataFile.print(epochTime);

        dataFile.print(",");


        dataFile.print(mass, 1);

        dataFile.print(",");


        dataFile.print(temp, 1);

        dataFile.print(",");


        dataFile.println(hum, 1);


        dataFile.close();


        Serial.println(

          "SD Save OK"

        );


      } else {


        Serial.println(

          "SD Save Failed"

        );


      }

    }


    // CLOUD UPLOAD

    if (ready &&

        WiFi.status() ==

        WL_CONNECTED) {


      FirebaseJson response;


      FirebaseJson valueRange;


      valueRange.add(

        "majorDimension",

        "COLUMNS"

      );


      valueRange.set(

        "values/[0]/[0]",

        epochTime

      );


      valueRange.set(

        "values/[1]/[0]",

        mass

      );


      valueRange.set(

        "values/[2]/[0]",

        temp

      );


      valueRange.set(

        "values/[3]/[0]",

        hum

      );


      bool success =

      GSheet.values.append(

        &response,

        spreadsheetId,

        "Sheet1!A1",

        &valueRange

      );


      if (success) {


        Serial.println(

          "Cloud Upload OK"

        );


      } else {


        Serial.println(

          "Cloud Upload Failed"

        );


        Serial.println(

          GSheet.errorReason()

        );


      }

    }

  }


  // SERIAL MONITOR

  if (millis() - lastSerial

      >= 5000) {


    Serial.print("Mass: ");


    Serial.print(mass, 1);

    Serial.print(" g");


    Serial.print(" | Temp: ");

    Serial.print(temp, 1);

    Serial.print(" C");


    Serial.print(" | RH: ");

    Serial.print(hum, 1);

    Serial.println(" %");


    lastSerial = millis();

  }


  // LCD

  lcd.setCursor(0, 0);


  lcd.print("M:");

  lcd.print(mass, 1);

  lcd.print("g ");


  // WIFI ICON

  if (WiFi.status() == WL_CONNECTED) {


    lcd.setCursor(15, 0);

    lcd.write(byte(0));


  } else {


    lcd.setCursor(15, 0);

    lcd.print(" ");

  }


  lcd.setCursor(0, 1);


  lcd.print("T:");

  lcd.print(temp, 1);


  lcd.print(" H:");


  lcd.print(hum, 0);


  lcd.print(" ");


  delay(300);

}


Comments