/**
AMICA-1 Prototype
DHT22
Soil Moisture Sensor v.1.2
MTTQ client
Water Cycle
Statistics
Copyright 2022, Antonio Soldati
*/
#include <WiFi.h>
#include "DHTesp.h"
#include "PubSubClient.h"
#define NTP_SERVER "pool.ntp.org"
#define UTC_OFFSET 0
#define UTC_OFFSET_DST 0
#define ONBOARD_LED 2
#define LED 4
#define DHT_PIN 15
#define SOIL 35
const char* ssid = "Wokwi-GUEST";
const char* password = "";
String status_string = "";
String timestamp ="";
String temp = "";
String humid = "";
String moist ="";
String rt_string = "";
const int dry_value = 2550;
const int wet_value = 600;
const int threshold_high = 70;
const int threshold_low = 20;
bool standby =false;
bool water_cycle = false;
bool pump_on = false;
//arrays for average calculations
float average_hour;
float average_day;
int day_array [24];
int month_array [30];
int second;
int minute;
int hour;
int day;
char d[97];
String day_string = "";
String month_string ="";
DHTesp dhtSensor;
WiFiClient espClient;
PubSubClient client(espClient);
// MQTT Broker
const char *mqtt_broker = "broker.mqttdashboard.com";
const char *topic_in = "amica/prototype-1/in";
const char *topic_out_status = "amica/prototype-1/out/status";
const char *topic_out_realtime = "amica/prototype-1/out/realtime";
const char *topic_out_day = "amica/prototype-1/out/day";
const char *topic_out_month = "amica/prototype-1/out/month";
const char *mqtt_username = "";
const char *mqtt_password = "";
const int mqtt_port = 1883;
//Local Time printing function
void printLocalTime() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("Connection Err");
return;
}
//Serial.println(&timeinfo, "%H:%M:%S");
// Serial.println(&timeinfo, "%Y%m%dT%H%M%S");
char timeStringBuff[50]; //50 chars should be enough
strftime(timeStringBuff, sizeof(timeStringBuff), "%Y%m%dT%H%M%S", &timeinfo);
//print like "const char*"
Serial.println(timeStringBuff);
//Optional: Construct String object
//String asString(timeStringBuff);
timestamp = timeStringBuff;
}
void setup() {
pinMode(LED, OUTPUT);
pinMode(ONBOARD_LED,OUTPUT);
Serial.begin(9600);
dhtSensor.setup(DHT_PIN, DHTesp::DHT22);
//WiFi connection
Serial.print("Connecting to WiFi");
WiFi.begin(ssid, password, 6);
while (WiFi.status() != WL_CONNECTED) {
delay(100);
digitalWrite(LED,HIGH);
delay(100);
digitalWrite(LED,LOW);
Serial.print(".");
}
Serial.println(" Connected!");
//MQTT Broker connection
client.setServer(mqtt_broker, mqtt_port);
client.setCallback(callback);
while (!client.connected()) {
String client_id = "esp32-client-";
client_id += String(WiFi.macAddress());
Serial.printf("The client %s connects to the public mqtt broker\n", client_id.c_str());
if (client.connect(client_id.c_str(), mqtt_username, mqtt_password)) {
Serial.println("Public " + String(mqtt_broker) + " connected");
} else {
Serial.print("failed with state ");
Serial.print(client.state());
delay(2000);
}
}
// publish and subscribe
client.publish(topic_out_status, "Hello World, I'm ESP32");
client.subscribe(topic_in);
configTime(UTC_OFFSET, UTC_OFFSET_DST, NTP_SERVER);
}
void callback(char *topic_in, byte *payload, unsigned int length) {
Serial.print("Message arrived in topic: ");
Serial.println(topic_in);
Serial.print("Message:");
for (int i = 0; i < length; i++) {
Serial.print((char) payload[i]);
}
Serial.println();
Serial.println("-----------------------");
// Switch on the LED if an 1 was received as first character
if ((char)payload[0] == '1') {
digitalWrite(LED, HIGH);
standby = false;
} else {
digitalWrite(LED, LOW);
standby = true;
}
}
void blink() {
digitalWrite(LED,HIGH);
delay (250);
digitalWrite(LED,LOW);
}
void shiftLeft (int myarray[], int size) {
//shift any element of an array of integers by 1 position to the left
for(int i=0;i<size-1;i++){
myarray [i] = myarray [i+1];
}
}
void loop() {
unsigned long myTime = millis ();
//status_string Check
bool alarm = false;
status_string = "Normal";
if ((WiFi.status() != WL_CONNECTED)) {
status_string = "WiFi malfunction";
alarm = true;
}
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
status_string = status_string + " - " + "Global time malfunction";
alarm = true;
}
if (!client.connected()) {
status_string = status_string + " - " + "MQTT malfunction";
alarm = true;
setup();
}
Serial.println (status_string);
if (alarm) {
digitalWrite (LED, HIGH);
} else {
digitalWrite (LED, LOW);
}
TempAndHumidity data = dhtSensor.getTempAndHumidity();
temp = "Temp: " + String(data.temperature, 1) + "°C";
humid = "Humidity: " + String(data.humidity, 1) + "%";
//reading and mapping percentage soil moisture value
analogReadResolution(12);
int soil_realvalue = analogRead(SOIL);
int soil_value = map (soil_realvalue, dry_value, wet_value, 0, 100);
//Irrigation Cycle
if ( soil_value >= threshold_high ) {
water_cycle = false;
}
if ( soil_value < threshold_low && standby == false ) {
water_cycle = true;
}
if ( water_cycle == true && standby == false ) {
pump_on = true;
Serial.println ("Watering Cycle");
blink ();
}
//calculating hourly and daily average soil moisture
if (second == 3600) {
shiftLeft (day_array,24);
day_array [23] = round (average_hour / 3600);
average_hour=0;
second = 0;
if (hour == 24) {
shiftLeft (month_array,30);
month_array [29] = round (average_day / 86400);
hour = 0;
second = 0;
average_hour = 0;
average_day = 0;
} else {
hour = hour + 1;
}
} else {
average_hour += soil_value;
average_day += soil_value;
second = second + 1;
}
for (int i = 0; i < 24; i++) {
day_string = (day_string + day_array[i] + ",");
}
for (int i = 0; i < 30; i++) {
month_string = (month_string + month_array[i] + ",");
}
//local printing
moist = "Soil Moisture: " + String(soil_value, DEC) + "%";
printLocalTime();
rt_string = timestamp +", " + moist + ", " + temp + ", " + humid;
Serial.println("Message Out: " + rt_string);
Serial.println("---");
//payload preparation and sending
//status_string
int len0 = status_string.length() + 1;
char p0 [len0];
status_string.toCharArray(p0, len0);
client.publish(topic_out_status, p0);
//measurements
int len = rt_string.length() + 1;
char p [len];
rt_string.toCharArray(p, len);
client.publish(topic_out_realtime, p);
//statistics
int len1 = day_string.length();
char p1 [len1];
day_string.toCharArray(p1,len1);
client.publish(topic_out_day, p1);
day_string ="";
int len2 = month_string.length();
char p2 [len2];
month_string.toCharArray(p2,len2);
client.publish(topic_out_month, p2);
month_string ="";
client.loop();
delay(1000);
//delay(1000- ( millis()- myTime));
}