-
-
Save Andymulb/3b6a4b1f43533e16c88c08682613697f to your computer and use it in GitHub Desktop.
ESP32 Soil Moisture Sensor with Tingg MQTT and Telegram integration
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Plant Wartering Alert & Monitor | |
Components: ESP32, Capacitive Soil Moisture Sensor, Micro-USB Cable, Power Supply, Jumper Wires | |
By Andreas Blum Media (https://blummedia.de) | |
*/ | |
#include <WiFi.h> | |
#include <PubSubClient.h> | |
#include <WiFiClientSecure.h> | |
#include <UniversalTelegramBot.h> | |
#include <ArduinoJson.h> | |
//------------Customize-------------- | |
#define CHAT_ID "123456789" //Define unique Chat ID of User | |
#define BOTtoken "1234567890:ABC_1A2B3C4D5E6F7G8H9I" //Define unique ID Token of Telegram Bot | |
const String plant = "PFLANZENNAME"; //Define unique name of plant | |
const int trigger = 20; //Trigger Telegram message for moisture level below trigger value in percent | |
const char* ssid = "SSID_OF_WIFI_ROUTER"; | |
const char* password = "WIFI_PASSWORD"; | |
const char* mqttDeviceId = "UNIQUE_TINGG_DEVICE_ID"; | |
const char* mqttPassword = "DEVICE_PASSWORD"; | |
//----------Check Config Settings---------- | |
// Topics Config | |
const char* soilMoistureTopic = "Soil_Moisture"; | |
const char* levelTopic = "Level"; | |
const char* subTopic = "Soil_Moisture"; | |
// Tingg Config | |
const char* mqttServer = "mqtt.tingg.io"; | |
const char* mqttUsername = "thing"; | |
const int port = 1883; | |
// Pins Config | |
//const int LightPin = 0; | |
const int sensorPin = 32; | |
const int DefaultPin = 2; | |
WiFiClient espClient; | |
PubSubClient client(espClient); | |
//Telegram Wifi Setup | |
WiFiClientSecure telegramClient; | |
UniversalTelegramBot bot(BOTtoken, telegramClient); | |
//Checks for new messages every 1 second. | |
int botRequestDelay = 1000; | |
unsigned long lastTimeBotRan; | |
// Vars | |
char buf[12]; | |
const int wet = 1500; | |
const int dry = 0; | |
int tinggPostDelay = 5000; | |
unsigned long lastTinggPost; | |
const int iTemp = 3600 / 5; //Water shortage trigger delay | |
const int iRestartDelay = 120; //Restart delay if trying to reconnect to MQTT | |
int iRestart = iRestartDelay; //Restart Counter | |
int iStep = 0; | |
int iCounter = iTemp; | |
int iToggle = 0; | |
// Function to validate connection with the board | |
void blinking_loop(){ | |
while (ssid == "SSID") { | |
digitalWrite(DefaultPin,HIGH); | |
delay(500); | |
digitalWrite(DefaultPin,LOW); | |
delay(500); | |
Serial.println("Default light should be blinking. Please set up your Wifi configuration."); | |
} | |
} | |
void setup_wifi() { | |
delay(10); | |
Serial.print("Connecting to "); | |
Serial.println(ssid); | |
WiFi.mode(WIFI_STA); | |
iRestart = iRestartDelay * 5; | |
WiFi.begin(ssid, password); | |
while (WiFi.status() != WL_CONNECTED) { | |
delay(500); | |
Serial.print("."); | |
if (iRestart <= 0) { | |
Serial.print("Restarting..."); | |
ESP.restart(); | |
} | |
iRestart--; | |
} | |
randomSeed(micros()); | |
Serial.println(""); | |
Serial.print("Congratulations!! WiFi connected on IP address: "); | |
Serial.println(WiFi.localIP()); | |
Serial.println(""); | |
Serial.println("Now, follow up on the steps for the MQTT configuration. "); | |
} | |
void reconnect() { | |
while (!client.connected()) { | |
Serial.println("Attempting to connect MQTT..."); | |
if (client.connect(mqttDeviceId, mqttUsername, mqttPassword)) { | |
Serial.println("connected"); | |
client.subscribe(subTopic); | |
iRestart = iRestartDelay; | |
} else { | |
if (iRestart <= 0) { | |
Serial.print("Restarting..."); | |
ESP.restart(); | |
} | |
iRestart--; | |
Serial.print("iRestart = "); | |
Serial.println(iRestart); | |
Serial.print(" Still not connected..."); // Serial.print(client.state()); | |
Serial.println(" trying again in 5 seconds"); // Wait 5 seconds before retrying | |
delay(5000); | |
} | |
} | |
} | |
//Telegram Functions | |
// Get sensor readings and return them as a String variable | |
String getReadings(){ | |
int sensorVal = 4095 - analogRead(sensorPin); | |
int moisturePercentage = map(sensorVal, dry, wet, 0, 100); | |
if (moisturePercentage > 100) { | |
moisturePercentage = 100; | |
} else if (moisturePercentage < 0) { | |
moisturePercentage = 0; | |
} | |
String message = plant + "\n"; | |
message += "Moisture: " + String(sensorVal) + "\n"; | |
message += "Level: " + String(moisturePercentage) + " % \n"; | |
return message; | |
} | |
//Handle what happens when you receive new messages | |
void handleNewMessages(int numNewMessages) { | |
Serial.println("handleNewMessages"); | |
Serial.println(String(numNewMessages)); | |
for (int i=0; i<numNewMessages; i++) { | |
// Chat id of the requester | |
String chat_id = String(bot.messages[i].chat_id); | |
if (chat_id != CHAT_ID){ | |
bot.sendMessage(chat_id, "Unauthorized user", ""); | |
continue; | |
} | |
// Print the received message | |
String text = bot.messages[i].text; | |
Serial.println(text); | |
String from_name = bot.messages[i].from_name; | |
if (text == "/start") { | |
String welcome = "Welcome, " + from_name + ".\n"; | |
welcome += "Use the following command to get current readings.\n\n"; | |
welcome += "/state \n"; | |
bot.sendMessage(chat_id, welcome, ""); | |
} | |
if (text == "/state") { | |
String readings = getReadings(); | |
bot.sendMessage(chat_id, readings, ""); | |
} | |
} | |
} | |
//Main Functions | |
void setup() { | |
//pinMode(LightPin,OUTPUT); | |
pinMode(sensorPin,INPUT); | |
pinMode(DefaultPin,OUTPUT); | |
Serial.begin(9600); | |
blinking_loop(); | |
setup_wifi(); | |
client.setServer(mqttServer, port); | |
bot.sendMessage(CHAT_ID, plant + " restarted!", ""); //Send message if controller restarted | |
} | |
void loop() { | |
if (!client.connected()) { | |
reconnect(); | |
} | |
client.loop(); | |
int sensorVal = analogRead(sensorPin); | |
sensorVal = 4095 - sensorVal; | |
int moisturePercentage = map(sensorVal, dry, wet, 0, 100); | |
if (moisturePercentage > 100) { | |
moisturePercentage = 100; | |
} else if (moisturePercentage < 0) { | |
moisturePercentage = 0; | |
} | |
if (millis() > lastTinggPost + tinggPostDelay) { | |
Serial.print("Value: "); | |
Serial.println(sensorVal); | |
Serial.print("Level: "); | |
Serial.print(moisturePercentage); | |
Serial.println("%"); | |
client.publish(soilMoistureTopic,itoa(sensorVal, buf, 10)); | |
client.publish(levelTopic,itoa(moisturePercentage, buf, 10)); | |
//Send Telegram Message if Moisture Level | |
switch (iStep) { | |
case 0: | |
iCounter = iTemp; | |
iToggle = 1; | |
iStep = 1; | |
break; | |
case 1: | |
if (iCounter <= 0) { | |
iStep = 2; | |
iToggle = 1; | |
} else if (moisturePercentage < trigger) { | |
iCounter--; | |
Serial.print("Counter: "); | |
Serial.println(iCounter); | |
} else if (moisturePercentage >= trigger) { | |
iStep = 0; | |
} | |
break; | |
case 2: | |
if (moisturePercentage < trigger && iToggle == 1) { | |
String alert = plant + " gießen!"; | |
bot.sendMessage(CHAT_ID, alert, ""); | |
Serial.println("Message sent!"); | |
iToggle = 0; | |
} else if (moisturePercentage > trigger) { | |
iCounter = iTemp; | |
iStep = 3; | |
} | |
break; | |
case 3: | |
if (iCounter <= 0 && moisturePercentage > trigger) { | |
iStep = 0; | |
} else if (moisturePercentage > trigger) { | |
iCounter--; | |
Serial.print("Counter: "); | |
Serial.println(iCounter); | |
} else if (moisturePercentage <= trigger) { | |
iStep = 2; | |
} | |
break; | |
} | |
lastTinggPost = millis(); | |
} | |
//Telegram Message Request | |
if (millis() > lastTimeBotRan + botRequestDelay) { | |
int numNewMessages = bot.getUpdates(bot.last_message_received + 1); | |
while(numNewMessages) { | |
Serial.println("got response"); | |
handleNewMessages(numNewMessages); | |
numNewMessages = bot.getUpdates(bot.last_message_received + 1); | |
} | |
lastTimeBotRan = millis(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment