#include <Arduino.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include "time.h"
#include <EEPROM.h>
#define ssid "Wokwi-GUEST"
#define password ""
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 7 * 3600; // Offset GMT+7 dalam detik
const int daylightOffset_sec = 0; // Tidak ada waktu musim panas di Jakarta
String BOTtoken = "7388822701:AAHkkPG00chP1nxCR5fkzZ-HL-bEM5smcAg"; // Ganti dengan token bot Anda
//String CHAT_ID = "987880117"; // Ganti dengan chat ID Anda
WiFiClientSecure clientTCP;
UniversalTelegramBot bot(BOTtoken, clientTCP);
int botRequestDelay = 1000;
unsigned long lastTimeBotRan;
LiquidCrystal_I2C lcd(0x27, 20, 4);
#define ONE_WIRE_BUS 14
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
#define TdsSensorPin 35
#define TdsFactor 0.5 // tds = ec / 2
#define SampleCount 10
float aref = 3.3; // reference voltage
float adcRange = 4096.0; // 12-bit ADC
int kValueAddress = 16;
float kValue = 1.00;
float analogValue, voltage, ecValue, tdsValue;
float calibration_value = 21.34 - 0.5;
int phval = 0;
unsigned long int avgval;
int buffer_arr[10], temp;
#define RELAY1_PIN 25
#define RELAY2_PIN 26
#define WATER_SENSOR_PIN 34
float waterSensorValue;
float ph_act = 0; // Global declaration of ph_act
float averageTdsValue = 0; // Global declaration of averageTdsValue
float temperatureC = 0; // Global declaration of temperatureC
void setup() {
Serial.begin(115200);
lcd.init();
lcd.backlight();
sensors.begin();
Wire.begin();
pinMode(TdsSensorPin, INPUT);
pinMode(RELAY1_PIN, OUTPUT);
pinMode(RELAY2_PIN, OUTPUT);
pinMode(WATER_SENSOR_PIN, INPUT); // Set water sensor pin as input
// Pastikan relay mati pada awal
digitalWrite(RELAY1_PIN, LOW);
digitalWrite(RELAY2_PIN, LOW);
// Read kValue from EEPROM
EEPROM.get(kValueAddress, kValue);
if (isnan(kValue) || kValue == 0xFF) {
kValue = 1.0; // default K value
EEPROM.put(kValueAddress, kValue);
}
// Splash Screen
lcd.clear();
lcd.setCursor(0, 1);
lcd.print(" Smart Farming ");
lcd.setCursor(0, 2);
lcd.print(" Hydroponics IoT ");
delay(1000);
lcd.clear();
// Display initializing with loading dots
lcd.setCursor(0, 1);
lcd.print(" Initializing");
for (int i = 0; i < 3; i++) {
delay(750);
lcd.print(" .");
}
// Koneksi ke Wi-Fi
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.println("WiFi connected.");
// Inisialisasi waktu dan ambil waktu lokal
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
lcd.clear();
printLocalTime();
clientTCP.setInsecure();
}
void loop() {
sensors.requestTemperatures();
temperatureC = sensors.getTempCByIndex(0);
Serial.print(temperatureC);
Serial.println("ºC");
float totalTdsValue = 0;
for (int i = 0; i < SampleCount; i++) {
analogValue = analogRead(TdsSensorPin);
voltage = analogValue / adcRange * aref;
ecValue = (133.42 * voltage * voltage * voltage - 255.86 * voltage * voltage + 857.39 * voltage) * kValue;
tdsValue = ecValue * TdsFactor;
totalTdsValue += tdsValue;
delay(100); // Delay antara pembacaan sampel
}
averageTdsValue = totalTdsValue / SampleCount;
Serial.print(averageTdsValue, 0);
Serial.println(" ppm");
for (int i = 0; i < 10; i++) {
buffer_arr[i] = analogRead(34);
delay(30);
}
for (int i = 0; i < 9; i++) {
for (int j = i + 1; j < 10; j++) {
if (buffer_arr[i] > buffer_arr[j]) {
temp = buffer_arr[i];
buffer_arr[i] = buffer_arr[j];
buffer_arr[j] = temp;
}
}
}
avgval = 0;
for (int i = 2; i < 8; i++)
avgval += buffer_arr[i];
float volt = (float)avgval * 3.3 / 4096 / 6;
ph_act = -5.70 * volt + calibration_value; // Update ph_act
Serial.print("pH: ");
Serial.println(ph_act);
// Check water sensor
int waterSensorValue = analogRead(WATER_SENSOR_PIN);
if (waterSensorValue <= 200) {
digitalWrite(RELAY2_PIN, HIGH);
} else {
digitalWrite(RELAY2_PIN, LOW);
}
// Check temperature and control relay1
if (temperatureC > 30) {
digitalWrite(RELAY1_PIN, HIGH);
} else {
digitalWrite(RELAY1_PIN, LOW);
}
bool relay1State = (waterSensorValue <= 200);
bool relay2State = (temperatureC > 25.0);
lcd.setCursor(0, 1);
lcd.print("TW=");
lcd.print(temperatureC);
lcd.print("*C PPM=");
lcd.print(averageTdsValue);
lcd.setCursor(0, 2);
lcd.print("PH=");
lcd.print(ph_act);
lcd.print(" R1:");
lcd.print(relay1State ? "ON" : "OF");
lcd.print(" R2:");
lcd.print(relay2State ? "ON" : "OF");
if (millis() > lastTimeBotRan + botRequestDelay) {
int numNewMessages = bot.getUpdates(bot.last_message_received + 1);
while (numNewMessages) {
Serial.println("got response");
handleNewMessages(numNewMessages);
numNewMessages = bot.getUpdates(bot.last_message_received + 1);
}
lastTimeBotRan = millis();
}
}
void handleNewMessages(int numNewMessages) {
Serial.print("Handle New Messages: ");
Serial.println(numNewMessages);
for (int i = 0; i < numNewMessages; i++) {
String chat_id = String(bot.messages[i].chat_id);
String text = bot.messages[i].text;
Serial.println(text);
String from_name = bot.messages[i].from_name;
if (from_name == "")
from_name = "Guest";
if (text == "/start") {
String welcome = "Selamat Datang, " + from_name + "\n";
welcome += "/status : Lihat kondisi sensor\n";
welcome += "/manual : Lihat manualbook\n";
bot.sendMessage(chat_id, welcome, "");
String keyboardJson = "[[\"/status\", \"/manual\"]]";
bot.sendMessageWithReplyKeyboard(chat_id, "Klik salah satu \n", "", keyboardJson, true);
}
if (text == "/status") {
String statusMessage = "Status Sensor:\n";
statusMessage += "TDS: " + String(averageTdsValue, 2) + " ppm\n";
statusMessage += "pH: " + String(ph_act, 2) + "\n";
statusMessage += "Suhu: " + String(temperatureC, 1) + "ºC\n";
statusMessage += "Relay1: " + String(digitalRead(RELAY1_PIN) == HIGH ? "ON" : "OFF") + "\n";
statusMessage += "Relay2: " + String(digitalRead(RELAY2_PIN) == HIGH ? "ON" : "OFF") + "\n";
statusMessage += "Water Sensor: " + String(analogRead(waterSensorValue) <= 200 ? "Detected" : "Not Detected") + "\n";
statusMessage += "Tanggal dan Waktu: " + getDateTime() + "\n";
bot.sendMessage(chat_id, statusMessage, "");
}
if (text == "/manual") {
String keyboardJson = "[[{ \"text\" : \"Go to Manual\", \"url\" : \"https://www.google.com\" }]]";
bot.sendMessageWithInlineKeyboard(chat_id, "Klik tombol dibawah", "", keyboardJson);
}
}
}
String getDateTime() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("Failed to obtain time");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Failed to get time");
return "";
}
char dateBuffer[11];
strftime(dateBuffer, sizeof(dateBuffer), "%d/%m/%Y", &timeinfo);
char timeBuffer[6];
strftime(timeBuffer, sizeof(timeBuffer), "%H:%M", &timeinfo);
return String(dateBuffer) + " " + String(timeBuffer);
}
void printLocalTime() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("Failed to obtain time");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Failed to get time");
return;
}
// Baris 1: Tanggal dan Jam
char dateBuffer[11];
strftime(dateBuffer, sizeof(dateBuffer), "%d/%m/%Y", &timeinfo);
lcd.setCursor(0, 0);
lcd.print(dateBuffer);
char timeBuffer[6];
strftime(timeBuffer, sizeof(timeBuffer), "%H:%M", &timeinfo);
lcd.setCursor(15, 0); // Tempatkan waktu pada posisi kanan
lcd.print(timeBuffer);
}