199 lines
4.9 KiB
C++
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;
|
|
}
|