#include "HX711.h"
#include <ESP32Servo.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include "time.h"
// WiFi
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// HiveMQ Cloud settings (replace with your cluster info)
const char* mqttServer = "bf82ef604f6b4a4fb45679d1f7df39b6.s1.eu.hivemq.cloud"; // Example: 8a1234567890.s1.eu.hivemq.cloud
const int mqttPort = 8883; // TLS port
const char* mqttUser = "hivemq.webclient.1756334189635"; // from HiveMQ Cloud access management
const char* mqttPassword = "AWuDhkRNE14w,!g>?0n8";
WiFiClientSecure espClient; // Secure client
PubSubClient client(espClient);
// NTP setup
const char *ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 10800; // Egypt GMT+2
const int daylightOffset_sec = 0;
#define LDR_PIN 34 // LDR analog pin
#define BUZZER_PIN 27
#define DOUT 32
#define CLK 33
#define SERVO_PIN 25
#define PUMP_PIN 26 // Pump control pin (MOSFET Gate)
#define SENSOR_PIN 14 // Analog pin for water sensor (ADC pin)
HX711 scale;
Servo gateServo;
const int MAX_SENSOR_VALUE = 4095;
const float LEVEL_THRESHOLD = 15.0; // % Threshold
unsigned long buzzerStart = 0;
bool buzzerActive = false;
bool gateClosed = false;
int ldrThreshold = 2000; // adjust this for your light level
// Target time
int targetHour = 0;
int targetMinute = 0;
int targetSecond = 0;
bool targetActive = false;
unsigned long activeStart = 0;
int currentSlot = 0;
int lastRunDay = -1;
int slotHour[3] = {0, 8, 16};
int slotMinute[3] = {0, 0, 0};
int slotSecond[3] = {0, 0, 0};
void callback(char* topic, byte* payload, unsigned int length) {
String msg;
for (int i = 0; i < length; i++) {
msg += (char)payload[i];
}
Serial.printf("š© Received on [%s]: %s\n", topic, msg.c_str());
int h, m, s;
if (sscanf(msg.c_str(), "%d:%d:%d", &h, &m, &s) == 3) {
slotHour[0] = h;
slotMinute[0] = m;
slotSecond[0] = s;
// Auto compute next slots (8h later and 16h later)
slotHour[1] = (h + 8) % 24;
slotMinute[1] = m;
slotSecond[1] = s;
slotHour[2] = (h + 16) % 24;
slotMinute[2] = m;
slotSecond[2] = s;
Serial.printf("ā
Slots set: [%02d:%02d:%02d], [%02d:%02d:%02d], [%02d:%02d:%02d]\n",
slotHour[0], slotMinute[0], slotSecond[0],
slotHour[1], slotMinute[1], slotSecond[1],
slotHour[2], slotMinute[2], slotSecond[2]);
}
}
void connectMQTT() {
while (!client.connected()) {
Serial.print("Connecting to HiveMQ Cloud...");
String clientId = "ESP32Client-" + String(random(0xffff), HEX);
if (client.connect(clientId.c_str(), mqttUser, mqttPassword)) {
Serial.println("connected!");
client.subscribe("/target/time");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" retrying in 5s...");
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
// Connect WiFi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nā
WiFi connected");
// TLS requires time for cert validation
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
// ā ļø For testing only, skip certificate verification
espClient.setInsecure();
// Init MQTT
client.setServer(mqttServer, mqttPort);
client.setCallback(callback);
pinMode(BUZZER_PIN, OUTPUT);
// Servo init
gateServo.attach(SERVO_PIN);
gateServo.write(0); // start as open
// HX711 setup
scale.begin(DOUT, CLK);
scale.set_scale(420.0f); // calibration factor (adjust!)
scale.tare(); // reset scale to 0
Serial.println("System Ready...");
pinMode(PUMP_PIN, OUTPUT);
digitalWrite(PUMP_PIN, LOW); // Pump OFF
analogReadResolution(12); // 0..4095
analogSetAttenuation(ADC_11db); // Max ~3.3V
}
void loop() {
if (!client.connected()) connectMQTT();
client.loop();
struct tm timeinfo;
if (getLocalTime(&timeinfo)) {
int hour = timeinfo.tm_hour;
int minute = timeinfo.tm_min;
int second = timeinfo.tm_sec;
// Reset slots at midnight (new day)
if (hour == 0 && minute == 0 && second == 0 && timeinfo.tm_mday != lastRunDay) {
currentSlot = 0;
lastRunDay = timeinfo.tm_mday;
Serial.println("š New day, resetting slot counter...");
}
// --- Slot trigger ---
if (!targetActive &&
hour == slotHour[currentSlot] &&
minute == slotMinute[currentSlot] &&
second == slotSecond[currentSlot]) {
Serial.printf("šÆ Slot %d started at %02d:%02d:%02d\n", currentSlot, hour, minute, second);
targetActive = true;
activeStart = millis();
}
// --- Run logic for 5 minutes ---
if (targetActive) {
unsigned long elapsed = millis() - activeStart;
if (elapsed <= 5UL * 60UL * 1000UL) {
// š¹ Weight + Servo + Buzzer logic
if (scale.is_ready()) {
float weight = scale.get_units(5);
if (weight < 0) weight = 0;
Serial.print("Weight: ");
Serial.print(weight, 2);
Serial.println(" kg");
if (weight >= 0.28) {
gateServo.write(90);
gateClosed = true;
Serial.println("Gate CLOSED (weight >= 280g)");
if (!buzzerActive) {
buzzerActive = true;
buzzerStart = millis();
digitalWrite(BUZZER_PIN, HIGH);
Serial.println("Buzzer ON (Gate Closed)");
}
} else if (weight <= 0.1) {
gateServo.write(0);
gateClosed = false;
Serial.println("Gate OPENED (weight <= 100g)");
}
}
if (buzzerActive) {
int ldrValue = analogRead(LDR_PIN);
if ((millis() - buzzerStart >= 120000) || (ldrValue < ldrThreshold)) {
buzzerActive = false;
digitalWrite(BUZZER_PIN, LOW);
Serial.println("Buzzer OFF");
}
}
} else {
// End of this slot
targetActive = false;
Serial.printf("ā¹ Slot %d finished\n", currentSlot);
currentSlot++;
if (currentSlot >= 3) {
Serial.println("ā
All 3 slots done for today");
}
}
}
}
// --- Water Sensor (always active) ---
long sum = 0;
for (int i = 0; i < 10; i++) {
sum += analogRead(SENSOR_PIN);
delay(5);
}
int sensorValue = sum / 10;
float levelPercent = (sensorValue * 100.0) / MAX_SENSOR_VALUE;
if (levelPercent < LEVEL_THRESHOLD) {
digitalWrite(PUMP_PIN, HIGH);
} else {
digitalWrite(PUMP_PIN, LOW);
}
delay(1000);
}
Loading
esp32-devkit-c-v4
esp32-devkit-c-v4