first commit
This commit is contained in:
commit
2f78d8867c
|
@ -0,0 +1,137 @@
|
||||||
|
#include <LiquidCrystal_I2C.h>
|
||||||
|
|
||||||
|
// Konfigurasi LCD
|
||||||
|
LiquidCrystal_I2C lcd(0x27, 20, 4); // LCD 20x4
|
||||||
|
|
||||||
|
// Pin sensor
|
||||||
|
const int pHpin = A0;
|
||||||
|
|
||||||
|
// Kalibrasi berdasarkan data aktual (pH = -6.90 * V + 28.15)
|
||||||
|
const float FIXED_SLOPE = -6.90;
|
||||||
|
const float FIXED_INTERCEPT = 28.15;
|
||||||
|
|
||||||
|
#define UKURAN_FILTER 10
|
||||||
|
float pembacaanpH[UKURAN_FILTER];
|
||||||
|
int indeksPembacaan = 0;
|
||||||
|
|
||||||
|
unsigned long waktuBacaTerakhir = 0;
|
||||||
|
const int intervalBaca = 1000;
|
||||||
|
unsigned long waktuKirimTerakhir = 0;
|
||||||
|
const int intervalKirim = 2000;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
lcd.init();
|
||||||
|
lcd.backlight();
|
||||||
|
lcd.clear();
|
||||||
|
lcd.setCursor(0, 0);
|
||||||
|
lcd.print("Monitoring pH Meter");
|
||||||
|
lcd.setCursor(0, 1);
|
||||||
|
lcd.print(" Feeder Automatic ");
|
||||||
|
delay(2000);
|
||||||
|
lcd.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
float tegangan = dapatkanTeganganRataRata();
|
||||||
|
float nilaipH = dapatkanpHStabil(tegangan);
|
||||||
|
|
||||||
|
if (millis() - waktuBacaTerakhir >= intervalBaca) {
|
||||||
|
waktuBacaTerakhir = millis();
|
||||||
|
tampilkanHasil(nilaipH);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (millis() - waktuKirimTerakhir >= intervalKirim) {
|
||||||
|
waktuKirimTerakhir = millis();
|
||||||
|
kirimKeESP(nilaipH, tegangan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float dapatkanTeganganRataRata() {
|
||||||
|
float total = 0;
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
total += analogRead(pHpin);
|
||||||
|
delay(10);
|
||||||
|
}
|
||||||
|
float tegangan = (total / 10.0) * (5.0 / 1023.0); // Sesuaikan dengan Vref 5V
|
||||||
|
return constrain(tegangan, 0, 5.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
float dapatkanpHStabil(float tegangan) {
|
||||||
|
float pH = (FIXED_SLOPE * tegangan) + FIXED_INTERCEPT;
|
||||||
|
pembacaanpH[indeksPembacaan] = pH;
|
||||||
|
indeksPembacaan = (indeksPembacaan + 1) % UKURAN_FILTER;
|
||||||
|
|
||||||
|
float total = 0;
|
||||||
|
int jumlahValid = 0;
|
||||||
|
for (int i = 0; i < UKURAN_FILTER; i++) {
|
||||||
|
if (!isnan(pembacaanpH[i])) {
|
||||||
|
total += pembacaanpH[i];
|
||||||
|
jumlahValid++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jumlahValid == 0) return pH;
|
||||||
|
float rataRatapH = total / jumlahValid;
|
||||||
|
if (isnan(rataRatapH) || rataRatapH < 0 || rataRatapH > 14) return pH;
|
||||||
|
return rataRatapH;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tampilkanHasil(float pH) {
|
||||||
|
// Baris 1: Nilai pH
|
||||||
|
lcd.setCursor(0, 0);
|
||||||
|
lcd.print("pH: ");
|
||||||
|
if (pH <= 0 || pH >= 14) {
|
||||||
|
lcd.print("Error ");
|
||||||
|
} else {
|
||||||
|
lcd.print(pH, 2); lcd.print(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Baris 2: Status Pompa
|
||||||
|
lcd.setCursor(0, 1);
|
||||||
|
if (pH < 6.5) {
|
||||||
|
lcd.print("Pump1:ON Pump2:OFF");
|
||||||
|
} else if (pH > 7.5) {
|
||||||
|
lcd.print("Pump1:OFF Pump2:ON ");
|
||||||
|
} else {
|
||||||
|
lcd.print("Pump1:OFF Pump2:OFF");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Baris 3: Rentang pH
|
||||||
|
lcd.setCursor(0, 2);
|
||||||
|
if (pH <= 0 || pH >= 14) {
|
||||||
|
lcd.print("Rentang: -- ");
|
||||||
|
} else if (pH < 3.0) {
|
||||||
|
lcd.print("Rentang: 0.0 - 2.9");
|
||||||
|
} else if (pH < 6.5) {
|
||||||
|
lcd.print("Rentang: 3.0 - 6.4");
|
||||||
|
} else if (pH < 7.5) {
|
||||||
|
lcd.print("Rentang: 6.5 - 7.4");
|
||||||
|
} else if (pH < 9.0) {
|
||||||
|
lcd.print("Rentang: 7.5 - 8.9");
|
||||||
|
} else {
|
||||||
|
lcd.print("Rentang: 9.0 - 14.0");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Baris 4: Kategori pH
|
||||||
|
lcd.setCursor(0, 3);
|
||||||
|
if (pH <= 0 || pH >= 14) {
|
||||||
|
lcd.print("Kategori:Tidak Valid ");
|
||||||
|
} else if (pH < 3.0) {
|
||||||
|
lcd.print("Kategori:Sangat Asam ");
|
||||||
|
} else if (pH < 6.5) {
|
||||||
|
lcd.print("Kategori:Asam ");
|
||||||
|
} else if (pH < 7.5) {
|
||||||
|
lcd.print("Kategori:Netral ");
|
||||||
|
} else if (pH < 9.0) {
|
||||||
|
lcd.print("Kategori:Basa ");
|
||||||
|
} else {
|
||||||
|
lcd.print("Kategori:Sangat Basa ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void kirimKeESP(float pH, float volt) {
|
||||||
|
Serial.print(pH, 2);
|
||||||
|
Serial.print(",");
|
||||||
|
Serial.println(volt, 3);
|
||||||
|
}
|
|
@ -0,0 +1,137 @@
|
||||||
|
#include <LiquidCrystal_I2C.h>
|
||||||
|
|
||||||
|
// Konfigurasi LCD
|
||||||
|
LiquidCrystal_I2C lcd(0x27, 20, 4); // LCD 20x4
|
||||||
|
|
||||||
|
// Pin sensor
|
||||||
|
const int pHpin = A1;
|
||||||
|
|
||||||
|
// Kalibrasi sensor pH
|
||||||
|
const float FIXED_SLOPE = 1.80;
|
||||||
|
const float FIXED_INTERCEPT = 1.00;
|
||||||
|
|
||||||
|
#define UKURAN_FILTER 10
|
||||||
|
float pembacaanpH[UKURAN_FILTER];
|
||||||
|
int indeksPembacaan = 0;
|
||||||
|
|
||||||
|
unsigned long waktuBacaTerakhir = 0;
|
||||||
|
const int intervalBaca = 1000;
|
||||||
|
unsigned long waktuKirimTerakhir = 0;
|
||||||
|
const int intervalKirim = 2000;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
lcd.init();
|
||||||
|
lcd.backlight();
|
||||||
|
lcd.clear();
|
||||||
|
lcd.setCursor(0, 0);
|
||||||
|
lcd.print("Monitoring pH Meter");
|
||||||
|
lcd.setCursor(0, 1);
|
||||||
|
lcd.print(" Feeder Automatic ");
|
||||||
|
delay(2000);
|
||||||
|
lcd.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
float tegangan = dapatkanTeganganRataRata();
|
||||||
|
float nilaipH = dapatkanpHStabil(tegangan);
|
||||||
|
|
||||||
|
if (millis() - waktuBacaTerakhir >= intervalBaca) {
|
||||||
|
waktuBacaTerakhir = millis();
|
||||||
|
tampilkanHasil(nilaipH);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (millis() - waktuKirimTerakhir >= intervalKirim) {
|
||||||
|
waktuKirimTerakhir = millis();
|
||||||
|
kirimKeESP(nilaipH, tegangan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float dapatkanTeganganRataRata() {
|
||||||
|
float total = 0;
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
total += analogRead(pHpin);
|
||||||
|
delay(10);
|
||||||
|
}
|
||||||
|
float tegangan = (total / 10.0) * (5.0 / 1023.0);
|
||||||
|
return constrain(tegangan, 0, 5.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
float dapatkanpHStabil(float tegangan) {
|
||||||
|
float pH = (FIXED_SLOPE * tegangan) + FIXED_INTERCEPT;
|
||||||
|
pembacaanpH[indeksPembacaan] = pH;
|
||||||
|
indeksPembacaan = (indeksPembacaan + 1) % UKURAN_FILTER;
|
||||||
|
|
||||||
|
float total = 0;
|
||||||
|
int jumlahValid = 0;
|
||||||
|
for (int i = 0; i < UKURAN_FILTER; i++) {
|
||||||
|
if (!isnan(pembacaanpH[i])) {
|
||||||
|
total += pembacaanpH[i];
|
||||||
|
jumlahValid++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jumlahValid == 0) return pH;
|
||||||
|
float rataRatapH = total / jumlahValid;
|
||||||
|
if (isnan(rataRatapH) || rataRatapH < 0 || rataRatapH > 14) return pH;
|
||||||
|
return rataRatapH;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tampilkanHasil(float pH) {
|
||||||
|
// Baris 1: Nilai pH
|
||||||
|
lcd.setCursor(0, 0);
|
||||||
|
lcd.print("pH: ");
|
||||||
|
if (pH <= 0 || pH >= 14) {
|
||||||
|
lcd.print("Error ");
|
||||||
|
} else {
|
||||||
|
lcd.print(pH, 2); lcd.print(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Baris 2: Status Pompa
|
||||||
|
lcd.setCursor(0, 1);
|
||||||
|
if (pH < 6.5) {
|
||||||
|
lcd.print("Pump1:ON Pump2:OFF ");
|
||||||
|
} else if (pH > 7.5) {
|
||||||
|
lcd.print("Pump1:OFF Pump2:ON ");
|
||||||
|
} else {
|
||||||
|
lcd.print("Pump1:OFF Pump2:OFF ");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Baris 3: Rentang pH
|
||||||
|
lcd.setCursor(0, 2);
|
||||||
|
if (pH <= 0 || pH >= 14) {
|
||||||
|
lcd.print("Rentang: -- ");
|
||||||
|
} else if (pH < 3.0) {
|
||||||
|
lcd.print("Rentang: 0.0 - 2.9");
|
||||||
|
} else if (pH < 6.5) {
|
||||||
|
lcd.print("Rentang: 3.0 - 6.4");
|
||||||
|
} else if (pH < 7.5) {
|
||||||
|
lcd.print("Rentang: 6.5 - 7.4");
|
||||||
|
} else if (pH < 9.0) {
|
||||||
|
lcd.print("Rentang: 7.5 - 8.9");
|
||||||
|
} else {
|
||||||
|
lcd.print("Rentang: 9.0 - 14.0");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Baris 4: Kategori pH
|
||||||
|
lcd.setCursor(0, 3);
|
||||||
|
if (pH <= 0 || pH >= 14) {
|
||||||
|
lcd.print("Kategori:Tidak Valid");
|
||||||
|
} else if (pH < 3.0) {
|
||||||
|
lcd.print("Kategori:Sangat Asam");
|
||||||
|
} else if (pH < 6.5) {
|
||||||
|
lcd.print("Kategori:Asam ");
|
||||||
|
} else if (pH < 7.5) {
|
||||||
|
lcd.print("Kategori:Netral ");
|
||||||
|
} else if (pH < 9.0) {
|
||||||
|
lcd.print("Kategori:Basa ");
|
||||||
|
} else {
|
||||||
|
lcd.print("Kategori:Sangat Basa");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void kirimKeESP(float pH, float volt) {
|
||||||
|
Serial.print(pH, 2);
|
||||||
|
Serial.print(",");
|
||||||
|
Serial.println(volt, 3);
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
const int pHpin = A0;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
int adcValue = analogRead(pHpin);
|
||||||
|
float voltage = adcValue * 5.0 / 1023.0;
|
||||||
|
|
||||||
|
Serial.print("ADC: ");
|
||||||
|
Serial.print(adcValue);
|
||||||
|
Serial.print(" | Tegangan: ");
|
||||||
|
Serial.print(voltage, 3);
|
||||||
|
Serial.println(" V");
|
||||||
|
|
||||||
|
delay(1000);
|
||||||
|
}
|
|
@ -0,0 +1,255 @@
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <PubSubClient.h>
|
||||||
|
#include <Servo.h>
|
||||||
|
#include <NTPClient.h>
|
||||||
|
#include <WiFiUdp.h>
|
||||||
|
|
||||||
|
// === WiFi & MQTT ===
|
||||||
|
const char* ssid = "Fansyah";
|
||||||
|
const char* password = "12345678";
|
||||||
|
const char* mqtt_server = "203.194.113.47";
|
||||||
|
|
||||||
|
WiFiClient espClient;
|
||||||
|
PubSubClient client(espClient);
|
||||||
|
|
||||||
|
// === NTP (UTC+7) ===
|
||||||
|
WiFiUDP ntpUDP;
|
||||||
|
NTPClient timeClient(ntpUDP, "pool.ntp.org", 25200);
|
||||||
|
|
||||||
|
// === Pin ===
|
||||||
|
#define RELAY1 D0
|
||||||
|
#define RELAY2 D4
|
||||||
|
#define SERVO_PIN D5
|
||||||
|
Servo myServo;
|
||||||
|
|
||||||
|
// === Jadwal Pakan ===
|
||||||
|
int morningHour = 6, morningMinute = 0;
|
||||||
|
int eveningHour = 17, eveningMinute = 30;
|
||||||
|
bool morningFed = false, eveningFed = false, modeOtomatis = true;
|
||||||
|
|
||||||
|
// === Servo Timer ===
|
||||||
|
bool servoActive = false;
|
||||||
|
unsigned long servoStartTime = 0;
|
||||||
|
const unsigned long SERVO_DURATION = 60000;
|
||||||
|
|
||||||
|
// === Data pH & Tegangan ===
|
||||||
|
float pHValue = 0.0;
|
||||||
|
float voltageValue = 0.0;
|
||||||
|
unsigned long lastDataReceivedTime = 0;
|
||||||
|
|
||||||
|
// === Threshold Relay ===
|
||||||
|
const float pH_THRESHOLD_LOW = 6.5;
|
||||||
|
const float pH_THRESHOLD_HIGH = 7.5;
|
||||||
|
|
||||||
|
// === Mode Pompa ===
|
||||||
|
bool modePompaOtomatis = true; // default otomatis
|
||||||
|
String perintahManual = "netral"; // default netral
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
pinMode(RELAY1, OUTPUT);
|
||||||
|
pinMode(RELAY2, OUTPUT);
|
||||||
|
digitalWrite(RELAY1, HIGH);
|
||||||
|
digitalWrite(RELAY2, HIGH);
|
||||||
|
|
||||||
|
myServo.attach(SERVO_PIN);
|
||||||
|
myServo.write(0); // Posisi awal servo
|
||||||
|
|
||||||
|
WiFi.begin(ssid, password);
|
||||||
|
while (WiFi.status() != WL_CONNECTED) {
|
||||||
|
delay(500); Serial.print(".");
|
||||||
|
}
|
||||||
|
Serial.println("\nWiFi Terhubung: " + WiFi.localIP().toString());
|
||||||
|
|
||||||
|
client.setServer(mqtt_server, 1883);
|
||||||
|
client.setCallback(callback);
|
||||||
|
timeClient.begin();
|
||||||
|
|
||||||
|
Serial.println("Menunggu data pH dari Arduino...");
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
if (!client.connected()) reconnectMQTT();
|
||||||
|
client.loop();
|
||||||
|
timeClient.update();
|
||||||
|
|
||||||
|
checkSchedule();
|
||||||
|
readSerialData();
|
||||||
|
checkServo();
|
||||||
|
sendCurrentTimeToMQTT();
|
||||||
|
checkpHLevel(); // Periksa dan kontrol relay
|
||||||
|
}
|
||||||
|
|
||||||
|
void reconnectMQTT() {
|
||||||
|
while (!client.connected()) {
|
||||||
|
Serial.print("Menghubungkan ke MQTT...");
|
||||||
|
if (client.connect("ESPFeederClient")) {
|
||||||
|
Serial.println(" Terhubung!");
|
||||||
|
client.subscribe("feeder/jadwal/siang");
|
||||||
|
client.subscribe("feeder/jadwal/sore");
|
||||||
|
client.subscribe("feeder/mode");
|
||||||
|
client.subscribe("feeder/modepompa");
|
||||||
|
client.subscribe("feeder/manual/kontrol");
|
||||||
|
client.publish("feeder/status", "ESP Terhubung");
|
||||||
|
} else {
|
||||||
|
Serial.print(" Gagal ("); Serial.print(client.state());
|
||||||
|
Serial.println("). Coba lagi 5 detik...");
|
||||||
|
delay(5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void callback(char* topic, byte* payload, unsigned int length) {
|
||||||
|
String msg;
|
||||||
|
for (int i = 0; i < length; i++) msg += (char)payload[i];
|
||||||
|
msg.trim();
|
||||||
|
|
||||||
|
if (String(topic) == "feeder/jadwal/siang") {
|
||||||
|
int sep = msg.indexOf(':');
|
||||||
|
morningHour = msg.substring(0, sep).toInt();
|
||||||
|
morningMinute = msg.substring(sep + 1).toInt();
|
||||||
|
Serial.println("[MQTT] Jadwal Siang: " + msg);
|
||||||
|
} else if (String(topic) == "feeder/jadwal/sore") {
|
||||||
|
int sep = msg.indexOf(':');
|
||||||
|
eveningHour = msg.substring(0, sep).toInt();
|
||||||
|
eveningMinute = msg.substring(sep + 1).toInt();
|
||||||
|
Serial.println("[MQTT] Jadwal Sore: " + msg);
|
||||||
|
} else if (String(topic) == "feeder/mode") {
|
||||||
|
modeOtomatis = (msg == "otomatis");
|
||||||
|
Serial.println("[MQTT] Mode: " + msg);
|
||||||
|
} else if (String(topic) == "feeder/modepompa") {
|
||||||
|
modePompaOtomatis = (msg == "otomatis");
|
||||||
|
Serial.println("[MQTT] Mode Pompa: " + msg);
|
||||||
|
} else if (String(topic) == "feeder/manual/kontrol") {
|
||||||
|
perintahManual = msg;
|
||||||
|
Serial.println("[MQTT] Perintah Manual Pompa: " + msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkSchedule() {
|
||||||
|
int h = timeClient.getHours();
|
||||||
|
int m = timeClient.getMinutes();
|
||||||
|
|
||||||
|
if (modeOtomatis) {
|
||||||
|
if (h == morningHour && m == morningMinute && !morningFed) {
|
||||||
|
triggerFeeding("Pagi");
|
||||||
|
morningFed = true;
|
||||||
|
eveningFed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h == eveningHour && m == eveningMinute && !eveningFed) {
|
||||||
|
triggerFeeding("Sore");
|
||||||
|
eveningFed = true;
|
||||||
|
morningFed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h != morningHour || m != morningMinute) morningFed = false;
|
||||||
|
if (h != eveningHour || m != eveningMinute) eveningFed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void triggerFeeding(String waktu) {
|
||||||
|
Serial.println(">> MEMBERI PAKAN " + waktu + " (" + timeClient.getFormattedTime() + ")");
|
||||||
|
myServo.write(90); // Aktifkan servo
|
||||||
|
servoStartTime = millis();
|
||||||
|
servoActive = true;
|
||||||
|
|
||||||
|
String notif = "Pakan diberikan - " + waktu + " | " + timeClient.getFormattedTime();
|
||||||
|
client.publish("feeder/notifikasi", notif.c_str());
|
||||||
|
Serial.println("[MQTT] " + notif);
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkServo() {
|
||||||
|
if (servoActive && millis() - servoStartTime >= SERVO_DURATION) {
|
||||||
|
myServo.write(0); // Kembalikan ke posisi awal
|
||||||
|
servoActive = false;
|
||||||
|
Serial.println("[INFO] Servo dimatikan");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void readSerialData() {
|
||||||
|
if (Serial.available()) {
|
||||||
|
String in = Serial.readStringUntil('\n');
|
||||||
|
in.trim();
|
||||||
|
int sep = in.indexOf(',');
|
||||||
|
|
||||||
|
if (sep > 0) {
|
||||||
|
float pH = in.substring(0, sep).toFloat();
|
||||||
|
float volt = in.substring(sep + 1).toFloat();
|
||||||
|
String t = timeClient.getFormattedTime();
|
||||||
|
|
||||||
|
String ph_payload = String(pH, 2) + " | " + t;
|
||||||
|
String volt_payload = String(volt, 3) + " V | " + t;
|
||||||
|
client.publish("feeder/pH", ph_payload.c_str());
|
||||||
|
client.publish("feeder/tegangan", volt_payload.c_str());
|
||||||
|
|
||||||
|
Serial.printf("[DATA] pH: %.2f | V: %.3f | %s\n", pH, volt, t.c_str());
|
||||||
|
lastDataReceivedTime = millis();
|
||||||
|
pHValue = pH;
|
||||||
|
voltageValue = volt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (millis() - lastDataReceivedTime > 10000 && lastDataReceivedTime != 0) {
|
||||||
|
String t = timeClient.getFormattedTime();
|
||||||
|
client.publish("feeder/pH", ("0 | " + t).c_str());
|
||||||
|
client.publish("feeder/tegangan", ("0 V | " + t).c_str());
|
||||||
|
Serial.println("[WARNING] Timeout data pH");
|
||||||
|
lastDataReceivedTime = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void kirimStatusPompa(String status) {
|
||||||
|
client.publish("feeder/statuspompa", status.c_str());
|
||||||
|
Serial.println("[MQTT] Status Pompa: " + status);
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkpHLevel() {
|
||||||
|
String status = "Pompa OFF";
|
||||||
|
|
||||||
|
if (modePompaOtomatis) {
|
||||||
|
Serial.print(">> [Otomatis] Pemeriksaan pH: "); Serial.println(pHValue, 2);
|
||||||
|
|
||||||
|
if (pHValue < pH_THRESHOLD_LOW) {
|
||||||
|
digitalWrite(RELAY1, LOW);
|
||||||
|
digitalWrite(RELAY2, HIGH);
|
||||||
|
status = "Pompa 1 Aktif (Otomatis - pH rendah)";
|
||||||
|
} else if (pHValue > pH_THRESHOLD_HIGH) {
|
||||||
|
digitalWrite(RELAY1, HIGH);
|
||||||
|
digitalWrite(RELAY2, LOW);
|
||||||
|
status = "Pompa 2 Aktif (Otomatis - pH tinggi)";
|
||||||
|
} else {
|
||||||
|
digitalWrite(RELAY1, HIGH);
|
||||||
|
digitalWrite(RELAY2, HIGH);
|
||||||
|
status = "Tidak ada Pompa Aktif (Otomatis - pH normal)";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Serial.print(">> [Manual] Perintah: "); Serial.println(perintahManual);
|
||||||
|
|
||||||
|
if (perintahManual == "ph_rendah") {
|
||||||
|
digitalWrite(RELAY1, LOW);
|
||||||
|
digitalWrite(RELAY2, HIGH);
|
||||||
|
status = "Pompa 1 Aktif (Manual - pH rendah)";
|
||||||
|
} else if (perintahManual == "ph_tinggi") {
|
||||||
|
digitalWrite(RELAY1, HIGH);
|
||||||
|
digitalWrite(RELAY2, LOW);
|
||||||
|
status = "Pompa 2 Aktif (Manual - pH tinggi)";
|
||||||
|
} else {
|
||||||
|
digitalWrite(RELAY1, HIGH);
|
||||||
|
digitalWrite(RELAY2, HIGH);
|
||||||
|
status = "Tidak ada Pompa Aktif (Manual - Netral)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kirimStatusPompa(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendCurrentTimeToMQTT() {
|
||||||
|
static unsigned long last = 0;
|
||||||
|
if (millis() - last >= 1000) {
|
||||||
|
last = millis();
|
||||||
|
String t = timeClient.getFormattedTime();
|
||||||
|
client.publish("feeder/waktu", t.c_str());
|
||||||
|
Serial.println("[MQTT] Waktu dikirim: " + t);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "2e92a845f1f50f3f",
|
||||||
|
"type": "ui_gauge",
|
||||||
|
"z": "29be4b82ed975b38",
|
||||||
|
"name": "Volt Sensor",
|
||||||
|
"group": "6052452935d9b5f7",
|
||||||
|
"order": 2,
|
||||||
|
"width": 3,
|
||||||
|
"height": 3,
|
||||||
|
"gtype": "donut",
|
||||||
|
"title": "Tegangan",
|
||||||
|
"label": "",
|
||||||
|
"format": "{{value}} V",
|
||||||
|
"min": "0",
|
||||||
|
"max": "5",
|
||||||
|
"colors": [
|
||||||
|
"#1d91c0",
|
||||||
|
"#ffe600",
|
||||||
|
"#ca3838"
|
||||||
|
],
|
||||||
|
"seg1": "",
|
||||||
|
"seg2": "",
|
||||||
|
"diff": false,
|
||||||
|
"className": "",
|
||||||
|
"x": 340,
|
||||||
|
"y": 120,
|
||||||
|
"wires": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "6052452935d9b5f7",
|
||||||
|
"type": "ui_group",
|
||||||
|
"name": "Monitoring PH Meter",
|
||||||
|
"tab": "03a33f3b692afcd8",
|
||||||
|
"order": 1,
|
||||||
|
"disp": true,
|
||||||
|
"width": 6,
|
||||||
|
"collapse": false,
|
||||||
|
"className": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "03a33f3b692afcd8",
|
||||||
|
"type": "ui_tab",
|
||||||
|
"name": "Fedder Dashboard",
|
||||||
|
"icon": "dashboard",
|
||||||
|
"order": 1,
|
||||||
|
"disabled": false,
|
||||||
|
"hidden": false
|
||||||
|
}
|
||||||
|
]
|
Loading…
Reference in New Issue