IoT-Plants-Monitor/project.ino

199 lines
4.9 KiB
C++

/* https://randomnerdtutorials.com */
#include "DHT.h"
#include <PubSubClient.h>
#include <WiFiMulti.h>
#include <Wire.h> //Import the required libraries
#define DEVICE "ESP32"
#define WIFI_SSID "SSID_HERE" // Network Name
#define WIFI_PASSWORD "PASSWORD_HERE" // Network Password
#define MQTT_SERVER "mqtt.plant.ammar.engineer"
#define MQTT_PORT 1883
#define MQTT_SUBSCRIBE_PUMP "plant/1/pump"
// if water level is lower than
#define LOWEST_ACCEPTABLE_WATER_LEVEL 20
// for more than 25 seconds
#define LOWEST_TIME_BETWEEN_PUMP_STARTS 25000
// Then the water pump starts
#define WATER_PUMP_PIN 25 // actually relay
// however, the timer restarts if the water level raised above 25000ms!
// unfortunate variable naming :)
#define DHT11_PIN 32
#define WATER_SOIL_PIN 34
#define LDR_PIN 33
WiFiMulti wifiMulti;
WiFiClient espClient;
PubSubClient client(espClient);
DHT dht(DHT11_PIN, DHT11);
int temp = 0;
int humid = 0;
int water_soil = 0;
int light = 0;
// This is to stop the pump from working too much
unsigned long last_time_pump_started = millis();
void setup() {
Serial.begin(115200);
pinMode(WATER_PUMP_PIN, OUTPUT);
setup_wifi();
setup_mqtt();
dht.begin();
}
void loop() {
Serial.println("one cycle");
temp = dht.readTemperature();
humid = dht.readHumidity();
water_soil = water_sensor(WATER_SOIL_PIN);
light = light_sensor();
// Check WiFi connection and reconnect if needed
if (wifiMulti.run() != WL_CONNECTED) {
Serial.println("Wifi connection lost");
}
if (!client.connected()) {
reconnect_mqtt();
}
if (needs_water()) {
start_bump_seconds(1);
last_time_pump_started = millis();
}
client.loop(); // check incoming messags
// uploads data.
publish_mqtt("plant/1/temp", "temp", temp);
publish_mqtt("plant/1/humid", "humid", humid);
publish_mqtt("plant/1/water_soil", "water_soil", water_soil);
publish_mqtt("plant/1/light", "light", light);
delay(1000); // Wait 1 seconds
}
void setup_wifi() {
WiFi.mode(WIFI_STA); // Setup wifi connection
wifiMulti.addAP(WIFI_SSID, WIFI_PASSWORD);
Serial.print("Connecting to wifi"); // Connect to WiFi
while (wifiMulti.run() != WL_CONNECTED) {
Serial.print(".");
delay(100);
}
Serial.print("Connected to ");
Serial.print(WIFI_SSID);
Serial.println(" Successfully");
Serial.print(WiFi.localIP());
Serial.println(" isn the local IP");
}
void setup_mqtt() {
client.setServer(MQTT_SERVER, MQTT_PORT);
client.setCallback(callback);
}
void callback(char *topic, byte *message, unsigned int length) {
Serial.print("Message arrived on topic: ");
Serial.print(topic);
Serial.print(". Message: ");
String messageTemp;
for (int i = 0; i < length; i++) {
Serial.print((char)message[i]);
messageTemp += (char)message[i];
}
Serial.println();
if (String(topic) == MQTT_SUBSCRIBE_PUMP) {
char buffer[40];
int seconds = messageTemp.toInt();
Serial.print("Starting Pump for: ");
Serial.println(seconds);
start_bump_seconds(seconds);
}
}
void reconnect_mqtt() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect("ESP32-1")) {
Serial.println("connected");
// Subscribe
client.subscribe(MQTT_SUBSCRIBE_PUMP);
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void publish_mqtt(const char *topic, const char *sensor, float value) {
char buffer[40];
sprintf(buffer, "plant1 %s=%.0f", sensor, value);
Serial.print("Publishing ");
Serial.println(buffer);
client.publish(topic, buffer);
}
int water_sensor(int pin) {
int raw = analogRead(pin);
// max is ~4000
// min is ~800
// this is the percentage, after normalizing min to 0
// then invert by subtracting, 100
return 102 - (int)((((float)raw - 800.0) / 3200.0) * 100.0);
}
int light_sensor() {
int raw = analogRead(LDR_PIN);
// max is ~4095
// min is ~779
// see comments for water_sensor
return (int)((((float)raw - 700.0) / (4095.0 - 779.0)) * 100.0);
}
void set_bump(int state) {
digitalWrite(WATER_PUMP_PIN, state); // turn on pump 5 seconds
}
void start_bump_seconds(int seconds) {
set_bump(HIGH); // turn on pump 5 seconds
delay(seconds * 1000);
set_bump(LOW); // turn on pump 5 seconds
}
bool needs_water() {
unsigned long now = millis();
unsigned long time_diff = now - last_time_pump_started;
Serial.print("Needs water?: ");
Serial.print(now);
Serial.print(" - ");
Serial.print(last_time_pump_started);
Serial.print("=");
Serial.println(time_diff);
if (water_soil > LOWEST_ACCEPTABLE_WATER_LEVEL) {
last_time_pump_started = millis();
} else if (water_soil < LOWEST_ACCEPTABLE_WATER_LEVEL &&
time_diff > LOWEST_TIME_BETWEEN_PUMP_STARTS) {
Serial.println("Pump needs to be started");
return true;
}
return false;
}