#include <Arduino.h>
#include <DHT.h>
#include "HX711.h"
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
#include <WiFi.h>
#include "PubSubClient.h"
// Function prototypes (declarations before main code)
void displayInfo();
void displayData();
void displayDateTime();
String formatTime(int value, bool leadingZero);
void simulateSunlight();
bool needsWatering(float moisture);
void wifiConnect();
void callback(char* topic, byte* message, unsigned int length);
void publishToMQTT(const char* topic, const char* payload);
void mqttReconnect();
String generateClientID();
void checkWaterLevel();
// Wi-Fi credentials
#define WIFI_SSID "Wokwi-GUEST"
#define WIFI_PASS ""
// MQTT server details
#define MQTT_SERVER "broker.hivemq.com"
#define MQTT_PORT 8883
// #define MQTT_USERNAME "[email protected]"
// #define MQTT_PASSWORD "x6~(K{4U.#;GuI,"
String clientID = generateClientID();
// Topic definitions
#define TEMP_TOPIC "garden/temperature"
#define H_TOPIC "garden/humidity"
#define SM_TOPIC "garden/soil_moisture"
DHT dht(13, DHT22);
HX711 scale;
RTC_DS1307 rtc;
LiquidCrystal_I2C lcd(0x27, 20, 4);
WiFiClient espClient;
PubSubClient client(espClient);
// Pin definitions for RGB LED
#define RGB_LED_PIN_R 9 // RGB LED Red Pin
#define RGB_LED_PIN_G 7 // RGB LED Green Pin
#define RGB_LED_PIN_B 2 // RGB LED Blue Pin
// Function to setup the Program and run for one time
void setup() {
Serial1.begin(115200);
Wire.begin();
rtc.begin();
lcd.init();
lcd.backlight();
dht.begin();
scale.begin(11, 12);
wifiConnect();
client.setServer(MQTT_SERVER, MQTT_PORT);
client.setCallback(callback);
displayInfo();
Serial1.println("Program Starts");
Serial1.println("Generated Client ID: " + clientID);
}
// Function to loop some functions continously
void loop() {
// Display Current Time & Date
displayDateTime();
displayData();
// simulateSunlight(); // Call simulateSunlight function in the loop
client.loop();
delay(650);
}
// Function to display the Program Info
void displayInfo() {
// Display Program Info
lcd.setCursor(4, 0);
lcd.print("Terra-Firma");
lcd.setCursor(4, 1);
lcd.print("Home Garden");
lcd.setCursor(4, 2);
lcd.print("Developed By");
lcd.setCursor(2, 3);
lcd.print("Tawfeeq Zaghlool");
delay(2000);
lcd.clear();
}
// Function to display the Data from the sensors
void displayData() {
// Read temperature and humidity
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
// Read soil moisture
float soilMoisture = scale.get_units();
// Second row: Humidity & Temp
lcd.setCursor(2, 1);
lcd.print("H:");
lcd.print(humidity);
lcd.print("% T:");
lcd.print(temperature);
lcd.print("C");
// Third row: Soil Moisture (shortened to "Soil M")
lcd.setCursor(3, 2);
lcd.print("Soil M:");
lcd.print(soilMoisture);
// Fourth row: Watering Status (using icon)
lcd.setCursor(3, 3);
if (needsWatering(soilMoisture)) {
lcd.print("Need Water (u_u)"); // Exclamation mark for watering needed
} else {
lcd.print("Good Water (^-^)"); // Smiley face for moist soil
}
// Convert temperature, humidity, and soil moisture to strings
String tempStr = String(temperature);
String humStr = String(humidity);
String soilMoistureStr = String(soilMoisture);
// Publish temperature to MQTT
publishToMQTT(TEMP_TOPIC, tempStr.c_str());
// Publish humidity to MQTT
publishToMQTT(H_TOPIC, humStr.c_str());
// Publish soil moisture to MQTT
publishToMQTT(SM_TOPIC, soilMoistureStr.c_str());
}
void displayDateTime() {
// Get current time
DateTime now = rtc.now();
// Display Current Time
lcd.setCursor(0, 0);
lcd.print(formatTime(now.hour(), false)); // Display in 12-hour format with AM/PM
lcd.print(':');
lcd.print(formatTime(now.minute(), DEC)); // Use formatTime for minutes with leading zero
lcd.print(':');
lcd.print(formatTime(now.second(), DEC)); // Use formatTime for seconds with leading zero
// Display Current Date
lcd.setCursor(10, 0);
lcd.print(now.day(), DEC);
lcd.print('/');
lcd.print(now.month(), DEC);
lcd.print('/');
lcd.print(now.year(), DEC);
}
String formatTime(int value, bool leadingZero) {
String formatted = String(value, DEC); // Convert value to string
if (leadingZero && value < 10) {
formatted = "0" + formatted; // Add leading zero if needed
}
return formatted;
}
void simulateSunlight() {
pinMode(RGB_LED_PIN_R, OUTPUT);
pinMode(RGB_LED_PIN_G, OUTPUT);
pinMode(RGB_LED_PIN_B, OUTPUT);
DateTime now = rtc.now();
int hour = now.hour();
if (hour >= 6 && hour < 18) {
analogWrite(RGB_LED_PIN_R, 255);
analogWrite(RGB_LED_PIN_G, 255);
analogWrite(RGB_LED_PIN_B, 255);
} else {
analogWrite(RGB_LED_PIN_R, 0);
analogWrite(RGB_LED_PIN_G, 0);
analogWrite(RGB_LED_PIN_B, 0);
}
}
bool needsWatering(float moisture) {
return moisture < 200; // Example threshold, adjust as needed
}
void wifiConnect() {
delay(10);
// We start by connecting to a WiFi network
Serial1.println();
Serial1.print("Connecting to ");
Serial1.println(WIFI_SSID);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial1.print(".");
}
randomSeed(micros());
Serial1.println("");
Serial1.println("WiFi connected");
Serial1.println("IP address: ");
Serial1.println(WiFi.localIP());
}
void callback(char* topic, byte* message, unsigned int length) {
Serial1.print("Message arrived on topic: ");
Serial1.print(topic);
Serial1.print(". Message: ");
String stMessage;
for (int i = 0; i < length; i++) {
Serial1.print((char)message[i]);
stMessage += (char)message[i];
}
Serial1.println();
}
void publishToMQTT(const char* topic, const char* payload) {
if (!client.connected()) {
mqttReconnect();
}
if (client.publish(topic, payload)) {
Serial1.println("Published to MQTT");
} else {
Serial1.println("Failed to publish to MQTT");
}
}
void mqttReconnect() {
while (!client.connected()) {
Serial1.print("Attempting MQTT connection...");
Serial1.print("MQTT Client State: ");
Serial1.println(client.state());
if (client.connect(clientID.c_str())) {
Serial1.println("MQTT connected");
client.subscribe(TEMP_TOPIC);
client.subscribe(H_TOPIC); // Subscribe to servo topic
client.subscribe(SM_TOPIC); // Subscribe to neopixel topic
Serial1.println("Topic Subscribed");
}
else {
Serial1.print("failed, rc=");
Serial1.print(client.state());
Serial1.println(" try again in 5 seconds");
delay(5000); // wait 5sec and retry
}
}
}
String generateClientID() {
String id = "";
char c;
for (int i = 0; i < 16; i++) {
c = (char)random(0, 127); // Generate a random character
id += c;
}
return "Wokwi_" + id; // Prepend a prefix for easier identification
}