#include <ESP32Servo.h>
#include <LiquidCrystal_I2C.h>
#include <WiFi.h>
#include "RTClib.h"
#include "DHTesp.h"
#include "PubSubClient.h"
#define DHT22_PIN 15
#define SERVO_PIN 14
#define BUZZER_PIN 17
#define ULTRASONIC_TRIG_PIN 5
#define ULTRASONIC_ECHO_PIN 18
#define LED_GREEN_PIN 25
#define LED_YELLOW_PIN 26
#define LED_RED_PIN 27
#define LED_RGB_RED_PIN 12
#define LED_RGB_GREEN_PIN 32
#define LED_RGB_BLUE_PIN 33
#define MAX_TEMPERATURE 60.0
#define MIN_HUMIDITY 25.0
const char* WIFI_NAME = "Wokwi-GUEST"; //WiFi SSID
const char* WIFI_PASSWORD = ""; //WiFI Password
const char* MQTT_SERVER = "test.mosquitto.org"; //MQTT Server
const int MQTT_PORT = 1883; //MQTT Port
int currentAngle = 0;
Servo myServo;
LiquidCrystal_I2C lcd(0x27, 20, 4);
uint8_t degreeSymbol[8] = {0x0E, 0x1F, 0x1F, 0x0E, 0x00, 0x00, 0x00, 0x00};
RTC_DS1307 RTC;
//create an instance of the DHTesp library
DHTesp dhtSensor;
//create a WiFi client object
WiFiClient espClient;
//create a PubSubClient object
PubSubClient client(espClient);
long getDistance(){
digitalWrite(ULTRASONIC_TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(ULTRASONIC_TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(ULTRASONIC_TRIG_PIN, LOW);
long duration = pulseIn(ULTRASONIC_ECHO_PIN, HIGH);
long distanceCm = duration * 0.034 / 2;
return distanceCm;
}
void warningSign(int countSign){
for(int i=0;i<countSign;i++){
//warn by buzzer
tone(BUZZER_PIN, 1000);
delay(500);
noTone(BUZZER_PIN);
delay(1000);
//warn by LED RGB
analogWrite(LED_RGB_RED_PIN, random(0, 256));
analogWrite(LED_RGB_BLUE_PIN, random(0, 256));
analogWrite(LED_RGB_GREEN_PIN, random(0, 256));
}
}
void waterLevelSign(int distanceCm){
if(distanceCm <= 133){
digitalWrite(LED_GREEN_PIN, HIGH);
digitalWrite(LED_YELLOW_PIN, LOW);
digitalWrite(LED_RED_PIN, LOW);
}else if(distanceCm <= 300){
digitalWrite(LED_YELLOW_PIN, HIGH);
digitalWrite(LED_GREEN_PIN, LOW);
digitalWrite(LED_RED_PIN, LOW);
}else{
digitalWrite(LED_RED_PIN, HIGH);
digitalWrite(LED_GREEN_PIN, LOW);
digitalWrite(LED_YELLOW_PIN, LOW);
int countSign = 3;
if(distanceCm >= 400){
countSign = 5;
}
warningSign(countSign);
//turn of LED RGB
analogWrite(LED_RGB_RED_PIN, LOW);
analogWrite(LED_RGB_BLUE_PIN, LOW);
analogWrite(LED_RGB_GREEN_PIN, LOW);
}
}
void showSymbol(uint8_t index, const char* description) {
lcd.write(index); //display the custom symbol
lcd.print(description); //print the symbol description
}
void showTempAndHumidityOnLCD(TempAndHumidity data) {
// TempAndHumidity data = dhtSensor.getTempAndHumidity();
lcd.clear();
lcd.setCursor(0,0);
//display temperature
lcd.print("Temp: " + String(data.temperature, 2));
showSymbol(0, "C");
lcd.setCursor(0,1);
// Display humidity
lcd.print("Humidity: " + String(data.humidity, 1) + "%");
}
void showRealTime() {
DateTime now = RTC.now();
//--Date
lcd.setCursor(0,2); //Defining positon to write from first row,first column.
lcd.print(now.day());
//lcd.setCursor(4,2);
lcd.print("/");
//lcd.setCursor(5,2);
lcd.print(now.month());
//lcd.setCursor(7,2);
lcd.print("/");
//lcd.setCursor(8,2);
lcd.print(now.year());
//lcd.setCursor(11,2);
//lcd.print("water");
//-----------------
//--Time
lcd.setCursor(11,2);
lcd.print(now.hour());
//lcd.setCursor(2,1);
lcd.print(":");
//lcd.setCursor(3,1);
lcd.print(now.minute());
//lcd.setCursor(5,1);
lcd.print(":");
//lcd.setCursor(6,1);
lcd.print(now.second());
}
void wifiConnect(){
delay(10);
Serial.println();
Serial.print("Connecting to SSID: ");
Serial.println(WIFI_NAME);
//connect to the WiFi network
WiFi.begin(WIFI_NAME, WIFI_PASSWORD);
//print a message if WiFi is not connected
while (WiFi.status() != WL_CONNECTED){
delay(500);
Serial.println("Wifi not connected");
}
Serial.println("Wifi connected !"); //print a message if WiFi is connected
Serial.println("Local IP: " + String(WiFi.localIP())); //print the local IP address
// //WiFi.mode(WIFI_STA); //set the WiFi mode to station mode
}
void mqttReconnect(){
while(!client.connected()){
Serial.print("Attempting MQTT connection...");
if(client.connect("22127146")){
Serial.print("Connected to Node-RED by MQTT\n");
client.subscribe("arduino/sensor"); //make sure arduino to subscribe true topic
client.subscribe("arduino/servo"); //make sure arduino to subscribe true topic
}else{
Serial.print("Failed when connecting to Node-RED by MQTT, rc=");
Serial.print(client.state());
Serial.println(" Try again in 5 seconds to connect to Node-RED by MQTT");
delay(5000);
}
}
}
void mqttCallback(char* topic, byte* payload, unsigned int length){
Serial.print("Message (from Node-RED by MQTT) arrived [");
Serial.print(topic);
Serial.print("] ");
String message;
for (unsigned int i = 0; i < length; i++) {
message += (char)payload[i];
}
Serial.println(message + "\n");
if (String(topic) == "arduino/servo") {
int servoAngle = message.substring(message.indexOf(":") + 1, message.indexOf("}")).toInt();
if(servoAngle != currentAngle){
if(servoAngle == 0){
for(int i=0;i<=90;i++){
myServo.write(i);
}
}else{
for(int i=90;i>=0;i--){
myServo.write(i);
}
}
currentAngle = servoAngle;
}
Serial.print("Servo angle set to: ");
Serial.println(servoAngle);
}
}
void setup() {
// set up ultrasonic
Serial.begin(9600);
pinMode(ULTRASONIC_TRIG_PIN, OUTPUT);
pinMode(ULTRASONIC_ECHO_PIN, INPUT);
// set up LED
pinMode(LED_GREEN_PIN, OUTPUT);
pinMode(LED_YELLOW_PIN, OUTPUT);
pinMode(LED_RED_PIN, OUTPUT);
// set up buzzer
pinMode(BUZZER_PIN, OUTPUT);
// set up servo
myServo.attach(SERVO_PIN);
//set up the LCD
lcd.init();
//turn on the LCD backlight
lcd.backlight();
lcd.setCursor(0,0);
lcd.setCursor(0,1);
lcd.createChar(0, degreeSymbol);
//set up RTC
RTC.begin();
//set up DTH22 Sensor
dhtSensor.setup(DHT22_PIN, DHTesp::DHT22);
//setup wifi
wifiConnect();
client.setServer(MQTT_SERVER, MQTT_PORT);
client.setCallback(mqttCallback);
}
void loop() {
if(!client.connected()){
mqttReconnect();
}
client.loop();
//get water level
int waterDistance = getDistance();
int waterLevel = 400 - waterDistance;
//read temperature and humidity from the DHT22 sensor
TempAndHumidity data = dhtSensor.getTempAndHumidity();
showTempAndHumidityOnLCD(data);
showRealTime();
//get notification
waterLevelSign(waterDistance);
if(waterDistance >= 400 and data.temperature > MAX_TEMPERATURE and data.humidity < MIN_HUMIDITY){
warningSign(7);
}
//turn on watering
currentAngle = myServo.read();
if(data.temperature > MAX_TEMPERATURE and data.humidity < MIN_HUMIDITY){
if(currentAngle == 0){
for(int i =0; i<= 90; i++){
myServo.write(i);
}
currentAngle = 90;
}
}
//turn off watering
data = dhtSensor.getTempAndHumidity();
if(data.temperature <= MAX_TEMPERATURE and data.humidity >= MIN_HUMIDITY){
if(currentAngle == 90){
for(int i=90;i>=0;i--){
myServo.write(i);
}
currentAngle = 0;
}
}
Serial.println("Temp: " + String(data.temperature, 2) + "°C"); //print the temperature value with 2 decimal places
Serial.println("Humidity: " + String(data.humidity, 1) + "%"); //print the humidity value with 1 decimal place
Serial.println("Water Level: " + String(waterLevel) + "cm");
//send data to node-RED by MQTT
char buffer[1000];
sprintf(buffer, "{\"temperature\":%d,\"humidity\":%d, \"waterLevel\":%d}", int(data.temperature), int(data.humidity), waterLevel);
client.publish("arduino/sensor", buffer);
Serial.println("--------------------------------------------------------"); //print a separator line
delay(5000);
}