#include <WiFi.h>
#include <esp_crt_bundle.h>
#include <ssl_client.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
// This is the root CA certificate
const char root_ca[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
-----END CERTIFICATE-----
)EOF";
// Configure the serial console for debug and the modem
#define SerialMon Serial // Set serial for debug console (to the Serial Monitor)
// Configure the MQTT broker
#define MQTT_BROKER "f888816e.ala.asia-southeast1.emqxsl.com" // e.g. a2l1dde17xdr1y-ats.iot.eu-west-1.amazonaws.com
#define MQTT_PORT 8883
#define MQTT_USERNAME "admin"
#define MQTT_PASSWORD "Admin123"
#define MQTT_CLIENT_ID "ESP_IOT_GROKUL"
#define MQTT_TIMEOUT 15000 // Set timeout for SSL connection (in ms)
#define TOPIC_TETES "grokul/tetes"
#define TOPIC_SOIL "grokul/soil"
#define TOPIC_TOP "grokul/threshold/top"
#define TOPIC_BOT "grokul/threshold/bottom"
#define TOPIC_STATE "grokul/state"
// dev mode topics
#define TOPIC_DEV "grokul/dev"
#define TOPIC_DEVDRY "grokul/threshold/devdry"
#define TOPIC_DEVWET "grokul/threshold/devwet"
// Setup wifi
#define WIFI_AP "Wokwi-GUEST"
#define WIFI_PASS ""
// Create the mqtt stack
WiFiClientSecure wifiClient;
PubSubClient mqttClient(wifiClient);
// Pin setup
#define RELAY_PIN 15
#define SOIL_SENSOR 34
#define BUTTON 4
#define DEBOUNCE_TIME 1000
#define SEND_INTERVAL 15000
#define WINDOW_SIZE 10
// Updating soil concurrently
TaskHandle_t soilTask;
int soilValue[5];
uint32_t lastReconnectAttempt = 0;
long now, lastSent = 0, lastPressed = 0;
int lowerThreshold = 10, upperThreshold = 80;
// dev mode settings
int valueWet = 1200, valueDry = 1550;
int indexValue = 0;
int readingValue = 0;
int totalValue = 0;
int readingsValue[WINDOW_SIZE];
int sensorValue = 0;
boolean relayState = HIGH;
void IRAM_ATTR handleButtonPress();
int getSoilMoisture();
void movingAverage(void *pvParameters);
void callback(char *topic, byte *payload, unsigned int length);
void reconnect();
void setupWifi();
void setMQTTClientParams();
void setup()
{
SerialMon.begin(115200);
SerialMon.println("Starting....");
pinMode(BUTTON, INPUT_PULLUP);
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, relayState);
attachInterrupt(digitalPinToInterrupt(BUTTON), handleButtonPress, FALLING);
xTaskCreatePinnedToCore(
movingAverage, /* Task function. */
"GPS Task", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&soilTask, /* Task handle to keep track of created task */
0);
delay(5000);
setupWifi();
// Set the MQTT client parameters
setMQTTClientParams();
mqttClient.setServer(MQTT_BROKER, MQTT_PORT);
mqttClient.setCallback(callback);
}
void loop()
{
// We maintain connectivity with the broker
if (!mqttClient.connected())
{
reconnect();
}
int dev = analogRead(SOIL_SENSOR);
int soil = getSoilMoisture();
now = millis();
if (now - lastSent > SEND_INTERVAL)
{
if (soil < lowerThreshold && relayState == HIGH)
{
SerialMon.println("nyala");
relayState = !relayState;
digitalWrite(RELAY_PIN, relayState);
mqttClient.publish(TOPIC_STATE, "1", true);
}
else if (soil > upperThreshold && relayState == LOW)
{
SerialMon.println("mati");
relayState = !relayState;
digitalWrite(RELAY_PIN, relayState);
mqttClient.publish(TOPIC_STATE, "0", true);
}
SerialMon.print("Soil level: ");
SerialMon.println(soil);
SerialMon.print("Analog value: ");
SerialMon.println(dev);
mqttClient.publish(TOPIC_SOIL, String(soil).c_str(), true);
mqttClient.publish(TOPIC_DEV, String(dev).c_str(), true);
lastSent = now;
}
SerialMon.print("Soil level: ");
SerialMon.println(soil);
SerialMon.print("Analog value: ");
SerialMon.println(dev);
// We are listening to the events
mqttClient.loop();
delay(10);
}
void IRAM_ATTR handleButtonPress()
{
if (now - lastPressed > DEBOUNCE_TIME)
{
digitalWrite(RELAY_PIN, HIGH);
lastPressed = now;
}
}
int getSoilMoisture()
{
float moisture = (float)(valueDry - sensorValue) / (valueDry - valueWet);
if (moisture < 0)
return 0;
else if (moisture > 1)
return 100;
else
return moisture * 100;
}
void movingAverage(void *pvParameters)
{
long currentTime, lastTime;
for (;;)
{
currentTime = millis();
if (currentTime - lastTime > 500)
{
totalValue = totalValue - readingsValue[indexValue];
readingValue = analogRead(SOIL_SENSOR);
readingsValue[indexValue] = readingValue;
totalValue += readingValue;
indexValue = (indexValue + 1) % WINDOW_SIZE;
sensorValue = totalValue / WINDOW_SIZE;
lastTime = currentTime;
}
}
}
void setMQTTClientParams(void)
{
wifiClient.setCACert(root_ca);
wifiClient.setTimeout(MQTT_TIMEOUT);
}
void callback(char *topic, byte *payload, unsigned int length)
{
SerialMon.print("Message arrived [");
SerialMon.print(topic);
SerialMon.print("] ");
SerialMon.write(payload, length);
SerialMon.println();
if (String(topic) == TOPIC_TETES && (char)payload[0] == '1')
{
digitalWrite(RELAY_PIN, HIGH);
}
else
{
char msg[length];
for (int i = 0; i < length; i++)
{
msg[i] = (char)payload[i];
}
// SerialMon.println(msg);
if (atoi(msg) < 100)
if (String(topic) == TOPIC_TOP)
{
upperThreshold = atoi(msg);
}
else if (String(topic) == TOPIC_BOT)
{
lowerThreshold = atoi(msg);
}
}
}
void reconnect()
{
setMQTTClientParams();
// Loop until we're reconnected
while (!mqttClient.connected())
{
SerialMon.println("Attempting MQTT connection...");
// Attempt to connect
if (mqttClient.connect(MQTT_CLIENT_ID, MQTT_USERNAME, MQTT_PASSWORD))
{
SerialMon.println("-----------------------------------connected-----------------------");
mqttClient.subscribe(TOPIC_TETES);
mqttClient.subscribe(TOPIC_TOP);
mqttClient.subscribe(TOPIC_BOT);
}
else
{
SerialMon.print("failed, rc=");
SerialMon.print(mqttClient.state());
SerialMon.println("...try again in 5 seconds");
delay(5000);
}
}
}
void setupWifi()
{
SerialMon.println("Connecting to WiFi...");
int attempts = 0;
WiFi.begin(WIFI_AP, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED && attempts < 20)
{
delay(500);
// spinner();
Serial.print(".");
attempts++;
}
if (WiFi.status() != WL_CONNECTED)
{
SerialMon.println("\nFailed to connect to WiFi");
delay(3000);
}
else
{
SerialMon.println("\nConnected to WiFi");
delay(3000);
}
}