Wednesday, 28 October 2026

AI-Powered IoT Smart Agriculture Monitoring System Using Arduino Uno, ESP32, n8n Automation & AI Voice Alerts

AI-Powered Smart Agriculture Monitoring System Using IoT, Arduino UNO, ESP32-S3 and n8n

ESP32-S3 智能农业监测与自动灌溉系统_智慧农场 esp32 传感器 设计 源程序-CSDN博客
 
 
 
AgriSense IoT Dashboard & Smart Alerts · Built with Blink
 
 
 
ESP32 DHT22: Automate Greenhouse Fan and Pump | ShillehTek
 
 
 

Complete project documentation, circuit connections, flowcharts, and software

This project combines IoT sensors, an Arduino UNO, an ESP32-S3, cloud data logging, AI-assisted decision-making, and workflow automation to monitor agricultural conditions in real time. When a sensor reading crosses a configured threshold, the system can send a Telegram text notification, generate a voice alert, record the event in Google Sheets, and send an email through Gmail.

The documentation below is organized as a practical engineering project that you can build, test, demonstrate, and adapt for a college project, final-year project, or smart-farming prototype.

Project overview

ARDUINO® Uno Rev3

        – Robot Pi Shop
 
 
 

Arduino UNO — sensor interface

Reads analog soil-moisture measurements and can act as a dedicated sensor controller.

 
Waveshare ESP32-S3 - WiFi Development Board
 
 
 

ESP32-S3 — IoT gateway

Connects to Wi-Fi, collects sensor data, and transmits readings to the automation server.

 
Automatisation & Workflows IA | Automatiser vos processus métier intelligemment
 
 
 

n8n — automation and AI orchestration

Processes incoming readings, applies rules, calls AI services when appropriate, and coordinates notifications.

 
Logging Data to Google Sheets with the Tessel 2 - SparkFun Learn
 
 
 

Cloud dashboard and notifications

Google Sheets, an IoT webpage, optional ThingSpeak charts, Gmail messages, and Telegram text or voice alerts.

Main project title

AI-Powered Smart Agriculture Monitoring System Using IoT, Arduino UNO, ESP32-S3 and n8n Automation

Subtitle: Real-Time Temperature, Humidity and Soil-Moisture Monitoring with AI Voice Alerts, Google Sheets Cloud Logging, Gmail Notifications, Telegram Automation and an IoT Web Dashboard.

Project features

  • 🌡️ Real-time temperature monitoring.

  • 💧 Air humidity and soil-moisture monitoring.

  • 📊 Live webpage dashboard and Google Sheets logging.

  • ☁️ Optional ThingSpeak cloud visualization.

  • 📧 Automatic Gmail notifications for critical conditions.

  • 📱 Telegram text notifications.

  • 🔊 AI-generated spoken alerts delivered through Telegram as audio or voice messages.

  • 🤖 AI-assisted alert explanations and agricultural recommendations.

  • ⚠️ Threshold-based warnings for dry soil, excessive heat, and other configured conditions.

  • 🔄 Automated n8n workflows with event logging and recovery handling.

  • 🌱 Optional future expansion to automatic irrigation.

 

1. Abstract

Agriculture depends heavily on temperature, atmospheric humidity, and soil-water availability. Manual inspection of fields is time-consuming and may not identify unfavorable conditions quickly enough. This project proposes an IoT-based smart agriculture monitoring system that continuously collects environmental measurements and makes them available through a web dashboard and cloud storage.

The system uses sensors such as the DHT22 or a suitable temperature/humidity sensor and a capacitive soil-moisture sensor. An Arduino UNO can acquire sensor readings, while an ESP32-S3 provides Wi-Fi connectivity and forwards measurements to an n8n automation workflow.

The n8n workflow validates the incoming readings, evaluates configurable agricultural thresholds, records measurements in Google Sheets, and sends notifications through Gmail and Telegram. An AI service can transform critical readings into understandable spoken alerts, which are delivered through Telegram using a supported audio or voice-message method.

The proposed system provides a modular, expandable, and relatively low-cost approach to environmental monitoring. It can help users observe changing field conditions and respond more quickly to possible water stress or heat-related risks.

Important design principle: AI generates explanations and optional recommendations; deterministic sensor thresholds trigger critical warnings. This makes the system more predictable than allowing an AI agent to decide whether a potentially urgent alert should be sent.

2. Objectives

  1. Measure temperature, atmospheric humidity, and soil moisture.

  2. Acquire readings at regular intervals.

  3. Transmit sensor readings from the ESP32-S3 to a server over Wi-Fi.

  4. Display current measurements on an IoT webpage.

  5. Maintain a timestamped cloud record in Google Sheets.

  6. Configure thresholds for abnormal environmental conditions.

  7. Send automatic Gmail and Telegram notifications.

  8. Generate natural-language and voice alerts using an AI or text-to-speech service.

  9. Maintain a modular design that supports ThingSpeak integration and future irrigation automation.

  10. Reduce dependence on continuous manual inspection.

3. System architecture

Agricultural environment

Temperature · Air humidity · Soil moisture

Sensors

DHT22 + capacitive soil-moisture sensor

Arduino UNO (optional sensor controller)

Reads analog soil moisture; sends data over serial

ESP32-S3 IoT gateway

Wi-Fi · JSON payload · HTTP/HTTPS transmission

n8n automation server

Validation → rules → storage → notification → AI voice

Google Sheets

Historical records

Gmail

Email warnings

Telegram

Text and voice alerts

Web / ThingSpeak

Live and historical charts

How the two microcontrollers work together

There are two practical ways to build the hardware.

  • Recommended for a simple prototype: Connect the sensors directly to the ESP32-S3. The ESP32-S3 reads the sensors, connects to Wi-Fi, and sends the readings to n8n. The Arduino UNO is not required in this arrangement.

  • Dual-controller version: Connect the soil-moisture sensor to the Arduino UNO, read the DHT sensor on either the UNO or ESP32-S3, and transmit the readings from the UNO to the ESP32-S3 over UART serial. The ESP32-S3 handles the network connection.

The remainder of this guide uses the dual-controller design, while explaining the direct-to-ESP32 alternative where it is useful.

4. Hardware components required

The following list is for one prototype with the Arduino UNO reading soil moisture and the ESP32-S3 forwarding measurements to n8n.

Buy Official Arduino Uno R3 Development Board
 – REES52
 
 
 

1. Arduino UNO R3

Quantity: 1

Reads the analog soil-moisture sensor and sends a serial data packet to the ESP32-S3.

 
Waveshare ESP32-S3 Development Board (with Headers) - The Pi Hut
 
 
 

2. ESP32-S3 development board

Quantity: 1

Provides Wi-Fi, JSON encoding, and HTTP communication with the n8n webhook.

 
Buy DHT 22 Module Online In India. Hyderabad
 
 
 

3. DHT22 / AM2302

Quantity: 1

Measures ambient temperature and relative humidity. The example code connects it to the ESP32-S3.

 
Capteur d'humidité du sol capacitif analogique V1.2
– tuni-smart-innovation
 
 
 

4. Capacitive soil-moisture sensor

Quantity: 1

Measures a soil-dependent analog signal. It needs calibration against the actual soil and watering conditions.

 
Arduino Starter Package for arduino Uno R3 - Bundle of 5 Items: Uno R3 Breadboard Jumper Wires USB Cable and 9V Battery Connecto | Daraz.com.bd
 
 
 

5. Supporting components

Breadboard, jumper wires, suitable USB cables, a stable power supply, and a voltage divider or logic-level interface for UART signals.

Software and cloud services

Software/service

Purpose

Arduino IDE

Compile and upload firmware

ESP32 board support package

Program the ESP32-S3

n8n

Receive data and orchestrate workflows

Google Sheets

Store sensor history

Gmail

Send email notifications

Telegram Bot API

Deliver text and voice alerts

AI or text-to-speech API

Create alert text and spoken audio

HTML, CSS and JavaScript

Build the IoT webpage

ThingSpeak (optional)

Display cloud-based sensor charts

 

Useful references: n8n documentation  and n8n Webhook node . n8n's webhook supports incoming HTTP requests and separates test and production URLs.

n8n Docs
+1

5. Circuit diagram and wiring

Plant temperature and soil moisture status bluetooth - Hackster.io
 
 
 

The image above is a visual reference. Use the following explicit pin connections as the wiring specification for the example firmware.

5.1 Soil-moisture sensor to Arduino UNO

Soil sensor pin

Arduino UNO connection

VCC

5 V only if supported by the sensor module

GND

GND

AO

A0

DO

Not connected

 

The capacitive sensor's analog output varies with the moisture of the soil. The reading is not a universal percentage until it has been calibrated.

5.2 DHT22 to ESP32-S3

DHT22 pin

ESP32-S3 connection

VCC

3.3 V, if supported by the module

GND

GND

DATA

GPIO 4

Pull-up resistor

Approximately 4.7–10 kΩ between DATA and 3.3 V, if the module does not already include one

 

Confirm the actual pin order printed on your DHT22 module. Bare sensors and preassembled modules may have different connection requirements.

5.3 Arduino UNO to ESP32-S3 using UART

The UNO sends the soil-moisture reading to the ESP32-S3 over a serial connection.

Arduino UNO

ESP32-S3

Purpose

D3 (software TX)

GPIO 18 (RX) through a suitable level shifter or divider

Soil reading data

GND

GND

Common reference

TX/RX USB connection

Computer

Firmware upload and debugging

 

Critical voltage warning: The UNO R3 uses 5 V logic, while ESP32-S3 GPIOs are 3.3 V devices. Never connect a 5 V UNO TX signal directly to an ESP32-S3 input. Use a level shifter or correctly designed resistor divider. The ESP32-S3 TX-to-UNO RX direction also needs to be checked against the UNO input specifications. For the sample below, the ESP32-S3 transmits no serial data back to the UNO.

5.4 Complete schematic overview

Capacitive soil sensor

AO → UNO A0 · VCC · GND

Arduino UNO

Analog input → moisture percentage

Level-shifted UART

UNO D3 TX → ESP32-S3 GPIO18 RX

ESP32-S3

DHT22 on GPIO4 + Wi-Fi + HTTPS/HTTP POST

n8n webhook

Validation and automation

The sensor grounds and microcontroller grounds must share a reference where required by the UART circuit. Keep the sensor and controller wiring away from high-current pump wiring. If the project later adds a pump, use an appropriately rated driver, a protected power supply, and isolation where appropriate.

 

6. Operating principle: step-by-step

  1. Acquire sensor readings. The UNO samples the soil sensor. The ESP32-S3 reads temperature and relative humidity from the DHT22.

  2. Calibrate the moisture measurement. Convert the raw ADC value into an estimated percentage using dry and wet reference measurements.

  3. Transfer the reading. The UNO sends a line of serial data, such as MOISTURE,42.5, to the ESP32-S3.

  4. Prepare the payload. The ESP32-S3 creates a JSON object containing temperature, humidity, soil moisture, device identity, and a timestamp or uptime value.

  5. Send to n8n. The ESP32-S3 posts the JSON payload to the configured webhook.

  6. Validate and evaluate. n8n checks that values are present and plausible, then compares them against configured limits.

  7. Store the measurements. Google Sheets receives a row for each accepted reading. A webpage can display the same data through a separate endpoint or database.

  8. Generate alerts. If a threshold is crossed, n8n sends the appropriate Telegram message and/or Gmail notification.

  9. Generate a voice message. For a significant event, an AI model may write a short explanation, a text-to-speech service converts it to audio, and n8n sends the resulting audio file to Telegram.

  10. Repeat. The device collects and transmits the next measurement at the configured interval.

7. Flowcharts

7.1 Hardware and data acquisition flow

mermaid

flowchart TD
    A([System starts]) --> B[Initialize Arduino UNO]
    B --> C[Read soil moisture ADC]
    C --> D[Calibrate ADC to percentage]
    D --> E[Transmit serial packet]
    E --> F[ESP32-S3 receives packet]
    F --> G[Read temperature and humidity]
    G --> H{Sensor data valid?}
    H -- No --> I[Record sensor error]
    I --> C
    H -- Yes --> J[Build JSON payload]
    J --> K[Send HTTP POST to n8n]
    K --> L{Request successful?}
    L -- No --> M[Retry with backoff]
    M --> K
    L -- Yes --> N[Wait for next interval]
    N --> C

7.2 n8n automation flow

mermaid

flowchart TD
    A[Webhook receives JSON] --> B[Validate and normalize data]
    B --> C{Payload valid?}
    C -- No --> D[Reject and log error]
    C -- Yes --> E[Append row to Google Sheets]
    E --> F[Update dashboard data source]
    F --> G{Any threshold exceeded?}
    G -- No --> H[Finish normal cycle]
    G -- Yes --> I[Determine severity and alert text]
    I --> J[Send Telegram text alert]
    I --> K[Send Gmail notification]
    I --> L{Voice alert enabled?}
    L -- No --> M[Finish alert workflow]
    L -- Yes --> N[AI generates concise message]
    N --> O[Text-to-speech creates audio]
    O --> P[Send audio or voice message to Telegram]
    P --> M

7.3 Alert decision flow

mermaid

flowchart TD
    A[Receive sensor readings] --> B{Temperature too high?}
    B -- Yes --> C[Heat warning]
    B -- No --> D{Soil too dry?}
    C --> E[Classify alert severity]
    D -- Yes --> F[Soil moisture warning]
    D -- No --> G{Humidity outside configured range?}
    F --> E
    G -- Yes --> H[Humidity warning]
    G -- No --> I[Normal status]
    H --> E
    E --> J[Log event]
    J --> K[Notify user]
    I --> L[Continue monitoring]
    K --> L

Thresholds should be selected for the crop, growth stage, soil type, sensor placement, and local conditions. The values used in the example software are demonstration settings, not universal agricultural recommendations.

8. Arduino UNO firmware

This program reads the analog soil-moisture sensor, converts the raw ADC reading to an approximate percentage, and transmits it over UART.

Arduino IDE setup

  1. Open Arduino IDE.

  2. Select the Arduino UNO R3 board.

  3. Connect the capacitive sensor's analog output to A0.

  4. Connect the sensor ground and power.

  5. Upload the following code.

  6. Open Serial Monitor at 9600 baud to inspect the output.

cpp

/*
  Project: Smart Agriculture Monitoring
  Board: Arduino UNO R3
  Sensor: Capacitive soil moisture sensor
  Output: UART on D3 at 9600 baud

  Calibrate DRY_RAW and WET_RAW for your sensor.
*/

#include <SoftwareSerial.h>

const byte SOIL_PIN = A0;
const byte TX_PIN = 3;
const byte RX_PIN = 2;  // Not used in this one-way link

SoftwareSerial espSerial(RX_PIN, TX_PIN);

// EXAMPLE VALUES ONLY. Replace after calibration.
const int DRY_RAW = 800;
const int WET_RAW = 350;

unsigned long lastSample = 0;
const unsigned long SAMPLE_INTERVAL_MS = 5000;

void setup() {
  Serial.begin(9600);
  espSerial.begin(9600);

  Serial.println("Smart Agriculture: UNO started");
}

void loop() {
  if (millis() - lastSample < SAMPLE_INTERVAL_MS) {
    return;
  }

  lastSample = millis();

  long total = 0;

  // Average several readings to reduce noise.
  for (int i = 0; i < 10; i++) {
    total += analogRead(SOIL_PIN);
    delay(10);
  }

  int raw = total / 10;

  // Works when dry readings are higher than wet readings.
  float moisture = 100.0f *
      (DRY_RAW - raw) / (DRY_RAW - WET_RAW);

  moisture = constrain(moisture, 0.0f, 100.0f);

  // Serial output for debugging.
  Serial.print("Raw ADC: ");
  Serial.print(raw);
  Serial.print(" | Soil moisture: ");
  Serial.print(moisture, 1);
  Serial.println("%");

  // Machine-readable packet for ESP32-S3.
  espSerial.print("MOISTURE,");
  espSerial.println(moisture, 1);
}

Explanation of the code

  • analogRead(A0) returns a value from 0 to 1023 on a standard UNO R3.

  • Averaging ten measurements reduces some random noise.

  • DRY_RAW and WET_RAW are calibration constants, not guaranteed values for your sensor.

  • constrain() limits the displayed estimate to 0–100%.

  • MOISTURE,42.5 is the serial packet format expected by the ESP32-S3 program.

The moisture percentage here is a calibrated sensor index, not a laboratory measurement of volumetric water content.

Calibrate the soil sensor

  1. Record the stable ADC value with the probe in the relevant dry reference condition.

  2. Record a second stable value in a well-watered soil condition.

  3. Enter the measured values in DRY_RAW and WET_RAW.

  4. Test at intermediate moisture levels and compare the estimate with actual soil conditions.

  5. Recalibrate if the sensor, soil composition, or installation depth changes.

For many capacitive sensors, raw values decrease as moisture increases, but verify this experimentally.

 

9. ESP32-S3 firmware

This firmware reads the UNO's serial data, reads temperature and humidity from the DHT22, and posts the result to the n8n webhook.

Required Arduino libraries

Install the following from Arduino IDE's Library Manager:

  • DHT sensor library by Adafruit

  • Adafruit Unified Sensor

Also install the ESP32 board package and select the correct ESP32-S3 development board.

Configure these settings before uploading

  • Wi-Fi SSID and password.

  • n8n webhook URL.

  • A webhook authentication secret, if enabled.

  • The actual ESP32-S3 UART and DHT pins used in your wiring.

For production deployments, use HTTPS and header authentication. The HTTP option below is intended for local testing only.

cpp

/*
  Project: AI-Powered Smart Agriculture
  Board: ESP32-S3
  DHT22 DATA: GPIO 4
  UNO serial TX -> level shifter -> GPIO 18
  Serial packet: MOISTURE,42.5
*/

#include <WiFi.h>
#include <HTTPClient.h>
#include <WiFiClientSecure.h>
#include <DHT.h>

const char* WIFI_SSID = "YOUR_WIFI_NAME";
const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";

// Use the Production URL after activating your n8n workflow.
const char* WEBHOOK_URL =
  "https://YOUR_N8N_HOST/webhook/agriculture";

const char* WEBHOOK_SECRET = "CHANGE_THIS_SECRET";

#define DHT_PIN 4
#define DHT_TYPE DHT22

#define UNO_RX_PIN 18
#define UNO_TX_UNUSED 17

DHT dht(DHT_PIN, DHT_TYPE);
HardwareSerial UnoSerial(1);

float soilMoisture = -1.0f;
unsigned long lastPost = 0;

const unsigned long POST_INTERVAL_MS = 15000;

String readUnoPacket() {
  static String line;

  while (UnoSerial.available()) {
    char c = UnoSerial.read();

    if (c == '\n') {
      String result = line;
      line = "";
      result.trim();
      return result;
    }

    if (c != '\r' && line.length() < 80) {
      line += c;
    }
  }

  return "";
}

bool parseMoisture(String packet, float &value) {
  if (!packet.startsWith("MOISTURE,")) {
    return false;
  }

  String number = packet.substring(9);
  char* endPtr = nullptr;
  float parsed = strtof(number.c_str(), &endPtr);

  if (endPtr == number.c_str() || *endPtr != '\0') {
    return false;
  }

  if (!isfinite(parsed) || parsed < 0 || parsed > 100) {
    return false;
  }

  value = parsed;
  return true;
}

void connectWiFi() {
  if (WiFi.status() == WL_CONNECTED) return;

  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);

  unsigned long started = millis();

  while (WiFi.status() != WL_CONNECTED &&
         millis() - started < 20000) {
    delay(250);
  }
}

void setup() {
  Serial.begin(115200);

  // RX = GPIO18. TX is unused in this one-way connection.
  UnoSerial.begin(9600, SERIAL_8N1,
                  UNO_RX_PIN, UNO_TX_UNUSED);

  dht.begin();
  connectWiFi();

  Serial.println("ESP32-S3 agriculture gateway started");
}

void loop() {
  String packet = readUnoPacket();

  if (packet.length() > 0) {
    float parsed;

    if (parseMoisture(packet, parsed)) {
      soilMoisture = parsed;
    }
  }

  if (millis() - lastPost < POST_INTERVAL_MS) {
    delay(10);
    return;
  }

  lastPost = millis();

  float temperature = dht.readTemperature();
  float humidity = dht.readHumidity();

  bool dhtValid = isfinite(temperature) &&
                  isfinite(humidity) &&
                  temperature >= -40 &&
                  temperature <= 80 &&
                  humidity >= 0 &&
                  humidity <= 100;

  if (!dhtValid || soilMoisture < 0) {
    Serial.println(
      "Invalid or missing sensor data; not posting");
    return;
  }

  connectWiFi();

  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("Wi-Fi unavailable");
    return;
  }

  // Use TLS certificate validation in production.
  WiFiClientSecure client;
  client.setCACert(nullptr);

  /*
    Replace the placeholder TLS configuration with the
    appropriate CA certificate for your n8n endpoint.
    Do not disable certificate verification in production.
  */

  HTTPClient http;

  if (!http.begin(client, WEBHOOK_URL)) {
    Serial.println("Failed to initialize HTTPS client");
    return;
  }

  http.addHeader("Content-Type", "application/json");
  http.addHeader("X-Webhook-Secret", WEBHOOK_SECRET);

  String payload = "{";
  payload += "\"device_id\":\"farm-node-01\",";
  payload += "\"temperature_c\":" + String(temperature, 1) + ",";
  payload += "\"humidity_pct\":" + String(humidity, 1) + ",";
  payload += "\"soil_moisture_pct\":" +
             String(soilMoisture, 1) + ",";
  payload += "\"uptime_ms\":" + String(millis());
  payload += "}";

  int status = http.POST(payload);

  Serial.print("HTTP status: ");
  Serial.println(status);

  if (status > 0) {
    Serial.println(http.getString());
  } else {
    Serial.println("POST failed; retry on a later cycle");
  }

  http.end();
}

Important correction before deployment: The example's client.setCACert(nullptr) does not configure a trusted certificate and must be replaced with a valid CA certificate before HTTPS requests are expected to work. Do not use setInsecure() for a production system. Install the appropriate certificate for the endpoint or use a correctly configured secure network client.

Example JSON payload

json

{
  "device_id": "farm-node-01",
  "temperature_c": 34.2,
  "humidity_pct": 41.5,
  "soil_moisture_pct": 28.7,
  "uptime_ms": 125000
}

The ESP32-S3 forwards a measurement every 15 seconds. This is a configurable demonstration interval. The UNO samples soil moisture every five seconds, so the gateway uses the latest valid moisture reading it has received.

Alternative: ESP32-S3-only version

If you do not need the UNO, connect a suitable analog-output soil sensor to an ADC-capable ESP32-S3 pin and perform the moisture calibration on the ESP32-S3. This reduces wiring and eliminates the UART link. Check the particular board's pinout and sensor output voltage before connecting it. Espressif's GPIO documentation describes ADC-capable pins and pin restrictions.

— ESP-IDF Programming Guide latest documentation
+1

10. Build the n8n automation workflow

n8n is the central automation layer. It receives the sensor data and connects the monitoring hardware to cloud storage, messaging, email, and AI services.

10.1 Create the workflow

Open your n8n instance and create a workflow named:

AI Smart Agriculture Monitoring and Voice Alerts

Add these nodes in order.

01

Webhook

Receive JSON from ESP32-S3 using POST.

02

Code

Validate values, calculate status, and prepare alert text.

03

Google Sheets

Append a row to the sensor history spreadsheet.

04

IF

Separate normal readings from warning or critical readings.

05

Telegram

Send the text alert.

06

Gmail

Send an email for the configured severity.

07

AI / Text-to-Speech

Generate alert wording and create audio for critical events.

08

Telegram

Deliver the generated audio file.

The node names above describe the intended design. Depending on your n8n version and provider, some integrations may need different node operations or an HTTP Request node. The official documentation covers webhook configuration and supported app actions.

GitHub
+2

10.2 Configure the Webhook node

Set these values:

Setting

Value

HTTP Method

POST

Path

agriculture

Authentication

Header Auth or another supported authentication method

Response

Respond immediately, or use a Respond to Webhook node

Expected content

JSON

 

Use the test URL while developing, and the production URL after activating or publishing the workflow, as required by your n8n deployment.

The webhook URL should look like this:

text
https://YOUR_N8N_HOST/webhook/agriculture

For a local development test, n8n provides a test URL, usually containing /webhook-test/. Use the exact URL displayed in your own Webhook node.

Security: Store credentials in n8n credentials or environment variables. Avoid exposing the webhook publicly without authentication, rate limiting, and appropriate network protections.

10.3 Add the Code node

Configure the Code node to run once for each incoming item. The following JavaScript validates the incoming data, calculates the condition, and produces fields for the downstream nodes.

javascript

const input = $json.body ?? $json;

const temperature = Number(input.temperature_c);
const humidity = Number(input.humidity_pct);
const soil = Number(input.soil_moisture_pct);

const valid =
  input.device_id &&
  Number.isFinite(temperature) &&
  Number.isFinite(humidity) &&
  Number.isFinite(soil) &&
  temperature >= -40 && temperature <= 80 &&
  humidity >= 0 && humidity <= 100 &&
  soil >= 0 && soil <= 100;

if (!valid) {
  throw new Error("Invalid agriculture sensor payload");
}

// Demonstration thresholds: adjust for your crop and soil.
const TEMP_HIGH = 35;
const SOIL_DRY = 30;
const HUMIDITY_LOW = 30;
const HUMIDITY_HIGH = 85;

const alerts = [];

if (temperature >= TEMP_HIGH) {
  alerts.push("High temperature");
}

if (soil <= SOIL_DRY) {
  alerts.push("Low soil moisture");
}

if (humidity < HUMIDITY_LOW) {
  alerts.push("Low relative humidity");
}

if (humidity > HUMIDITY_HIGH) {
  alerts.push("High relative humidity");
}

const status = alerts.length ? "WARNING" : "NORMAL";

const summary = alerts.length
  ? alerts.join(", ")
  : "All monitored values are within the configured limits.";

const timestamp = new Date().toISOString();

const message =
  `🌱 Smart Agriculture Alert\n` +
  `Device: ${input.device_id}\n` +
  `Temperature: ${temperature.toFixed(1)} °C\n` +
  `Air humidity: ${humidity.toFixed(1)} %\n` +
  `Soil moisture: ${soil.toFixed(1)} %\n` +
  `Status: ${status}\n` +
  `Condition: ${summary}\n` +
  `Time: ${timestamp}`;

return [{
  json: {
    timestamp,
    device_id: String(input.device_id),
    temperature_c: temperature,
    humidity_pct: humidity,
    soil_moisture_pct: soil,
    status,
    alert_summary: summary,
    alert_message: message,
    should_alert: alerts.length > 0
  }
}];

This node deliberately separates the measured data from the alert text. The same normalized output can be sent to Google Sheets, Telegram, Gmail, or a dashboard.

10.4 Configure Google Sheets

Create a spreadsheet called Smart Agriculture Monitoring.

Add a worksheet named SensorData and use these column headings in the first row:

text

Timestamp
Device_ID
Temperature_C
Humidity_Percent
Soil_Moisture_Percent
Status
Alert_Summary

In n8n:

  1. Add a Google Sheets node.

  2. Connect your Google account using the supported OAuth2 credential method.

  3. Select the spreadsheet and SensorData worksheet.

  4. Choose the Append Row operation.

  5. Map the fields from the Code node to the corresponding columns.

  6. Test with a sample payload and confirm that one new row appears.

Google Sheets is suitable for a prototype and moderate-frequency logging. For larger deployments, a database is often more appropriate for high-volume data.

n8n
+1

10.5 Configure the IF node

Set the condition to check the Boolean field:

text
should_alert is true
  • False output: End the alert branch; the measurement is still stored.

  • True output: Send Telegram and Gmail alerts.

For production, consider adding separate severity levels:

  • NORMAL: no warning.

  • WARNING: soil is approaching the dry limit or a configured environmental limit is crossed.

  • CRITICAL: a more severe, crop-specific threshold has been exceeded.

A temperature threshold of 35 °C and soil moisture of 30% in the sample code are examples only. They should not be interpreted as suitable limits for every crop.

10.6 Configure Telegram text alerts

  1. Open Telegram and start a conversation with @BotFather.

  2. Send /newbot and follow its instructions.

  3. Copy the bot token.

  4. In n8n, create a Telegram API credential and save the token securely.

  5. Start a conversation with your new bot.

  6. Obtain the target chat ID, for example through a Telegram Trigger update or a getUpdates API request after sending the bot a message.

  7. Add a Telegram node and select Send Message.

  8. Set the chat ID and map alert_message from the Code node.

The Telegram bot needs an initiated conversation with the user for a normal private-chat notification. Use the official Telegram Bot API  for supported request parameters and media requirements.

GitHub
+1

10.7 Configure Gmail notifications

  1. Add a Gmail node.

  2. Create a Gmail OAuth2 credential in n8n and authorize the account.

  3. Select the Send operation.

  4. Set the recipient to your monitoring email address.

  5. Set the subject to Smart Agriculture: {{$json.status}}.

  6. Set the body to {{$json.alert_message}}.

  7. Connect it to the warning branch.

For a prototype, sending an email for each alert is acceptable. In a real deployment, use cooldowns and event-state tracking so that one persistent dry-soil condition does not generate hundreds of duplicate emails.

10.8 Optional ThingSpeak integration

ThingSpeak can display environmental time series in addition to Google Sheets.

The general integration is:

  1. Create a ThingSpeak channel.

  2. Add fields for temperature, humidity, and soil moisture.

  3. Obtain the channel's write API key.

  4. Add an HTTP Request node to the n8n workflow.

  5. Send the field values to the channel using its documented write API.

  6. Open the ThingSpeak channel dashboard to view the charts.

Keep the write API key secret. For an actual deployment, consult ThingSpeak documentation .

 

11. AI agent and Telegram voice alerts

A key feature of this project is turning a sensor warning into a short spoken message. This normally involves two distinct services:

  • AI text generation: Writes a concise explanation based on the actual measurements.

  • Text-to-speech (TTS): Converts the approved text into an audio file.

An AI Agent node alone does not automatically create playable audio. You must connect a model or service that produces audio and then send that audio to Telegram.

11.1 AI prompt for agricultural alerts

Use a prompt like the following in your AI or language-model node:

text

You are an agricultural monitoring assistant.

Explain the current sensor readings in clear, concise language.

Use only the supplied sensor measurements and configured thresholds.
Do not invent weather conditions, plant diseases, or crop-specific facts.
Do not claim that irrigation is definitely required unless the configured
rule explicitly supports that conclusion.

Device: {{ $json.device_id }}
Temperature Celsius: {{ $json.temperature_c }}
Air humidity percent: {{ $json.humidity_pct }}
Soil moisture percent: {{ $json.soil_moisture_pct }}
Current status: {{ $json.status }}
Detected condition: {{ $json.alert_summary }}

Produce a short spoken alert, preferably one or two sentences.
Give a practical next step, such as checking the soil manually.

An example of the resulting spoken message might be:

Attention. The soil moisture reading is below the configured threshold. Please inspect the root-zone soil and verify whether irrigation is needed.

The AI output is illustrative. Your actual message should be generated from the incoming data, and the deterministic threshold check should remain responsible for triggering the alert.

11.2 Configure text-to-speech

Connect a TTS provider to the AI output. The provider may return an audio file, binary data, or a downloadable file URL.

In n8n, the usual sequence is:

AI Agent / Language Model

Creates the alert sentence

Text-to-Speech API

Produces audio bytes or a file

Binary file handling

Fetch or convert the audio into the required format

Telegram Send Audio / Send Voice

Deliver the spoken alert to the user's chat

11.3 Send audio to Telegram

There are two supported delivery patterns:

  • Audio file: Use Telegram's sendAudio method for a supported MP3 or M4A file.

  • Voice message: Use sendVoice with a supported OGG/Opus voice-note file. Verify the current Telegram API requirements for file format and size.

See the official Telegram Bot API media documentation .

Telegram Core

For a provider that returns a URL, ensure the URL is accessible to n8n and that the resulting file has the expected format. If it returns raw binary data, pass the binary output to the appropriate Telegram node operation.

Do not send a plain text URL as if it were an audio attachment. The Telegram node must receive a valid audio file or a supported file URL.

11.4 Recommended alert policy

Event

Telegram text

Gmail

Voice

Normal reading

Optional

No

No

Soil moisture low

Yes

Optional

Optional

High temperature

Yes

Yes

Yes, if critical

Multiple critical conditions

Yes

Yes

Yes

Sensor failure

Yes

Optional

Usually no

 

Add a cooldown—for example, one notification per device per alert type every 15 minutes—while keeping the raw sensor logging frequency unchanged. Also send a recovery notification when a condition returns to normal, if that behavior is useful for the application.

12. Create the IoT webpage dashboard

The webpage displays the latest temperature, humidity, and soil-moisture readings with a status indicator and a history chart.

A reliable design separates the dashboard from the sensor hardware:

  • The ESP32-S3 sends data to n8n.

  • n8n stores readings in Google Sheets and, optionally, a database.

  • The webpage reads data from a dashboard API.

  • The browser does not receive Telegram bot tokens, Google credentials, or other private API keys.

For a quick prototype, the following standalone webpage can be used to test the dashboard layout. It includes simulated readings until you connect a real dashboard endpoint.

Smart Greenhouse
 
 
 

12.1 Dashboard features

  • Temperature card in °C.

  • Relative humidity card in %.

  • Soil-moisture card in %.

  • Normal/warning status indicator.

  • Automatic refresh.

  • Timestamp of the most recent reading.

  • A trend chart for recent measurements.

12.2 Complete HTML, CSS, and JavaScript

Save the following code as index.html. It runs as a standalone demonstration, and can later be connected to an authenticated dashboard API.

AI-Powered Smart Agriculture Monitoring System

This project continuously measures temperature, humidity, and soil moisture, displays them on a local IoT webpage, logs them to Google Sheets and ThingSpeak, and uses n8n to trigger Gmail, Telegram text, and AI-generated Telegram voice alerts when field conditions cross safe agricultural thresholds. ThingSpeak accepts sensor data through its REST API, supports up to eight fields per channel, and requires a channel-specific Write API Key.[mathworks][docs.sparkfun]

Project Overview

Layer Hardware / Software Purpose
Sensing DHT11/DHT22, capacitive soil-moisture sensor Measures environment and soil condition
Local controller Arduino UNO Reads sensors and forwards stable sensor data over Serial
IoT controller ESP32-S3 Connects to Wi-Fi, hosts dashboard, sends data to cloud
Automation n8n Receives webhook data, evaluates thresholds, sends alerts
Cloud logging Google Sheets, ThingSpeak Stores historical and live agricultural data
Alerts Gmail, Telegram text, Telegram voice Notifies farmer instantly
AI OpenAI/Groq TTS or ElevenLabs Converts alert text into natural voice audio

The ESP32-S3 reads the analog soil-moisture sensor through its ADC; capacitive sensors typically output a voltage that decreases as soil moisture increases. ThingSpeak supports HTTP GET/POST updates using api_key and field1–field8 parameters.[mathworks][newbiely]

System Architecture

                 ┌────────────────────────────┐
                 │        FIELD SENSORS       │
                 │ DHT22 + Soil Moisture      │
                 └─────────────┬──────────────┘
                               │ Analog / Digital
                 ┌─────────────▼──────────────┐
                 │        ARDUINO UNO         │
                 │ Sensor conditioning +      │
                 │ Serial data forwarding     │
                 └─────────────┬──────────────┘
                               │ UART / Serial
                 ┌─────────────▼──────────────┐
                 │         ESP32-S3           │
                 │ Wi-Fi + Web Dashboard +    │
                 │ Cloud Upload + Webhook     │
                 └───┬───────────┬────────────┘
                     │           │
        ┌────────────▼──┐   ┌────▼──────────────┐
        │  ThingSpeak   │   │   n8n Webhook     │
        │ Live charts   │   │ Threshold logic   │
        └───────────────┘   └───┬───────────────┘
                                │
       ┌────────────────────────┼────────────────────────┐
       ▼                        ▼                        ▼
┌──────────────┐       ┌────────────────┐       ┌──────────────────┐
│ Google Sheets│       │ Gmail Alert    │       │ Telegram Text +  │
│ Cloud log    │       │ Email alert    │       │ AI Voice Alert   │
└──────────────┘       └────────────────┘       └──────────────────┘

Hardware Required

  • Arduino UNO
  • ESP32-S3 development board
  • DHT11 or DHT22 temperature/humidity sensor
  • Capacitive soil-moisture sensor
  • 16x2 I2C LCD, optional
  • Buzzer, optional
  • LEDs, optional
  • Breadboard and jumper wires
  • 5V USB power supply
  • Micro-USB/USB-C cable for programming
  • Wi-Fi 2.4 GHz network

Pin Connections

DHT22 to Arduino UNO

DHT22 Pin Arduino UNO
VCC 5V
GND GND
DATA D2
10kΩ resistor Between VCC and DATA

Soil Moisture Sensor to Arduino UNO

Sensor Pin Arduino UNO
VCC 5V
GND GND
AOUT A0

Arduino UNO to ESP32-S3

Use a voltage divider because Arduino UNO TX outputs 5 V, while ESP32 GPIO pins are 3.3 V tolerant only in limited cases.

Arduino UNO Connection ESP32-S3
GND Direct GND
TX, Pin 1 Through 1kΩ + 2kΩ divider RX pin, e.g., GPIO18
RX, Pin 0 Direct or 1kΩ series resistor TX pin, e.g., GPIO17

Recommended voltage divider:

Arduino TX ── 1kΩ ──┬── ESP32 RX
                    │
                   2kΩ
                    │
                   GND

Optional Status Indicators

Component ESP32-S3 Pin
Green LED GPIO4
Yellow LED GPIO5
Red LED GPIO6
Buzzer GPIO7

Circuit Schematic

                      ┌───────────────────┐
                      │    ARDUINO UNO    │
                      │                   │
 DHT22 DATA ──────────┤ D2                │
 DHT22 VCC ───────────┤ 5V                │
 DHT22 GND ───────────┤ GND               │
                      │                   │
 Soil AOUT ───────────┤ A0                │
 Soil VCC ────────────┤ 5V                │
 Soil GND ────────────┤ GND               │
                      │                   │
 Arduino TX ──1kΩ──┬──┤ TX Pin 1          │
                   │  │                   │
                  2kΩ │                   │
                   │  │                   │
                  GND └───────┬───────────┘
                              │
                      ┌───────▼───────────┐
                      │      ESP32-S3     │
                      │                   │
 Arduino TX divider ──┤ GPIO18 / RX       │
 Arduino RX ──────────┤ GPIO17 / TX       │
 GND ─────────────────┤ GND               │
                      │                   │
 Green LED ───────────┤ GPIO4             │
 Yellow LED ──────────┤ GPIO5             │
 Red LED ─────────────┤ GPIO6             │
 Buzzer ──────────────┤ GPIO7             │
                      └───────────────────┘

Each LED should use a 220Ω series resistor. The buzzer can be driven through a transistor if it requires more current than the ESP32 GPIO can safely supply.

Software Flow

START
  │
  ▼
Initialize Arduino UNO, DHT sensor, soil sensor
  │
  ▼
Initialize ESP32-S3 Wi-Fi, web server, ThingSpeak
  │
  ▼
Read temperature, humidity, soil moisture
  │
  ▼
Calculate moisture percentage
  │
  ▼
Display data on local webpage
  │
  ▼
Send data to ThingSpeak every 20 seconds
  │
  ▼
Send JSON data to n8n webhook
  │
  ▼
n8n checks thresholds
  │
  ├── Normal ──► Log to Google Sheets ──► Continue
  │
  └── Abnormal ──► Log to Google Sheets
                    │
                    ├── Send Gmail alert
                    ├── Send Telegram text
                    └── Generate AI voice and send Telegram voice
  │
  ▼
Repeat

ThingSpeak’s public examples use a 20-second interval, and the platform does not accept new updates more frequently than every 15 seconds.[github][docs.particle]

Threshold Example

Parameter Normal Range Alert Condition
Temperature 18–32°C Below 18°C or above 32°C
Humidity 40–80% Below 40% or above 80%
Soil moisture 40–80% Below 40% or above 80%

You can adjust these values based on the crop. For example, leafy vegetables often need consistently moist soil, while drought-tolerant crops can tolerate lower moisture levels.

Arduino UNO Code

Install the DHT sensor library by Adafruit in Arduino IDE.

#include <DHT.h>

#define DHTPIN 2
#define DHTTYPE DHT22   // Use DHT11 if you have DHT11
#define SOIL_PIN A0

DHT dht(DHTPIN, DHTTYPE);

// Calibration values: measure these for your own sensor
const int DRY_VALUE = 3200;   // Sensor value in dry air/soil
const int WET_VALUE = 1400;   // Sensor value in water/wet soil

void setup() {
  Serial.begin(9600);
  dht.begin();
}

void loop() {
  float temperature = dht.readTemperature();
  float humidity = dht.readHumidity();
  int soilRaw = analogRead(SOIL_PIN);

  int moisturePercent = map(soilRaw, DRY_VALUE, WET_VALUE, 0, 100);
  moisturePercent = constrain(moisturePercent, 0, 100);

  if (isnan(temperature) || isnan(humidity)) {
    Serial.println("{\"error\":\"DHT sensor read failed\"}");
  } else {
    Serial.print("{\"temperature\":");
    Serial.print(temperature, 1);
    Serial.print(",\"humidity\":");
    Serial.print(humidity, 1);
    Serial.print(",\"soilMoisture\":");
    Serial.print(moisturePercent);
    Serial.println("}");
  }

  delay(5000);
}

The Arduino sends a compact JSON line such as:

{"temperature":28.4,"humidity":62.0,"soilMoisture":55}

ESP32-S3 Code

Install these Arduino libraries:

  • WiFi
  • WebServer
  • HTTPClient
  • ArduinoJson
  • ThingSpeak

In Arduino IDE, select the correct ESP32-S3 board and enable USB CDC On Boot if required.

#include <WiFi.h>
#include <WebServer.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <ThingSpeak.h>

// ---------- Wi-Fi ----------
const char* WIFI_SSID = "YOUR_WIFI_NAME";
const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";

// ---------- ThingSpeak ----------
unsigned long THINGSPEAK_CHANNEL_ID = 1234567;
const char* THINGSPEAK_WRITE_API = "YOUR_THINGSPEAK_WRITE_KEY";

// ---------- n8n ----------
const char* N8N_WEBHOOK_URL = "https://YOUR_N8N_DOMAIN/webhook/agriculture";

// ---------- UART ----------
#define ARDUINO_RX 18
#define ARDUINO_TX 17

// ---------- LEDs / Buzzer ----------
#define GREEN_LED 4
#define YELLOW_LED 5
#define RED_LED 6
#define BUZZER 7

HardwareSerial ArduinoSerial(1);
WebServer server(80);
WiFiClient client;

float temperature = 0;
float humidity = 0;
int soilMoisture = 0;
bool dataValid = false;

unsigned long lastThingSpeak = 0;
unsigned long lastN8N = 0;

const unsigned long THINGSPEAK_INTERVAL = 20000; // 20 seconds
const unsigned long N8N_INTERVAL = 60000;        // 1 minute

void handleRoot() {
  String html = R"=====(
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Smart Agriculture Dashboard</title>
<style>
body{font-family:Arial;background:#0f172a;color:#fff;text-align:center;padding:20px;}
.card{background:#1e293b;border-radius:16px;padding:20px;margin:12px auto;max-width:350px;}
h1{color:#4ade80;}
.value{font-size:34px;font-weight:bold;}
.normal{color:#4ade80;}
.warning{color:#facc15;}
.danger{color:#f87171;}
</style>
<meta http-equiv="refresh" content="5">
</head>
<body>
<h1>🌱 Smart Agriculture Monitor</h1>

<div class="card">
<h2>Temperature</h2>
<div class="value">%TEMP% °C</div>
</div>

<div class="card">
<h2>Humidity</h2>
<div class="value">%HUM% %</div>
</div>

<div class="card">
<h2>Soil Moisture</h2>
<div class="value">%SOIL% %</div>
</div>

<div class="card">
<h2>Status</h2>
<div class="value">%STATUS%</div>
</div>

</body>
</html>
)=====";

  String status = "NORMAL";
  String statusClass = "normal";

  if (temperature < 18 || temperature > 32 ||
      humidity < 40 || humidity > 80 ||
      soilMoisture < 40 || soilMoisture > 80) {
    status = "ALERT";
    statusClass = "danger";
  }

  html.replace("%TEMP%", String(temperature, 1));
  html.replace("%HUM%", String(humidity, 0));
  html.replace("%SOIL%", String(soilMoisture));
  html.replace("%STATUS%", status);

  server.send(200, "text/html", html);
}

void connectWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);

  Serial.print("Connecting to Wi-Fi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println();
  Serial.print("Connected. IP: ");
  Serial.println(WiFi.localIP());
}

void readArduinoData() {
  static String buffer = "";

  while (ArduinoSerial.available()) {
    char c = ArduinoSerial.read();

    if (c == '\n') {
      buffer.trim();

      if (buffer.length() > 0) {
        JsonDocument doc;

        DeserializationError error = deserializeJson(doc, buffer);

        if (!error) {
          temperature = doc["temperature"] | 0.0;
          humidity = doc["humidity"] | 0.0;
          soilMoisture = doc["soilMoisture"] | 0;
          dataValid = true;

          Serial.printf("Temp: %.1f C, Humidity: %.1f %%, Soil: %d %%\n",
                        temperature, humidity, soilMoisture);
        }
      }

      buffer = "";
    } else {
      buffer += c;
    }
  }
}

void updateStatusIndicators() {
  bool tempAlert = temperature < 18 || temperature > 32;
  bool humidityAlert = humidity < 40 || humidity > 80;
  bool soilAlert = soilMoisture < 40 || soilMoisture > 80;

  digitalWrite(GREEN_LED, !tempAlert && !humidityAlert && !soilAlert);
  digitalWrite(YELLOW_LED, tempAlert || humidityAlert);
  digitalWrite(RED_LED, soilAlert);

  digitalWrite(BUZZER, soilAlert ? HIGH : LOW);
}

void sendToThingSpeak() {
  if (!dataValid) return;

  ThingSpeak.setField(1, temperature);
  ThingSpeak.setField(2, humidity);
  ThingSpeak.setField(3, soilMoisture);

  int status = ThingSpeak.writeFields(THINGSPEAK_CHANNEL_ID, THINGSPEAK_WRITE_API);

  if (status == 200) {
    Serial.println("ThingSpeak update successful.");
  } else {
    Serial.println("ThingSpeak update failed: " + String(status));
  }
}

void sendToN8N() {
  if (!dataValid) return;

  HTTPClient http;
  http.begin(N8N_WEBHOOK_URL);
  http.addHeader("Content-Type", "application/json");

  JsonDocument doc;
  doc["device"] = "ESP32-S3-AgriNode";
  doc["temperature"] = temperature;
  doc["humidity"] = humidity;
  doc["soilMoisture"] = soilMoisture;
  doc["timestamp"] = millis();

  String payload;
  serializeJson(doc, payload);

  int code = http.POST(payload);
  Serial.println("n8n response: " + String(code));

  http.end();
}

void setup() {
  Serial.begin(115200);
  ArduinoSerial.begin(9600, SERIAL_8N1, ARDUINO_RX, ARDUINO_TX);

  pinMode(GREEN_LED, OUTPUT);
  pinMode(YELLOW_LED, OUTPUT);
  pinMode(RED_LED, OUTPUT);
  pinMode(BUZZER, OUTPUT);

  connectWiFi();

  ThingSpeak.begin(client);

  server.on("/", handleRoot);
  server.begin();

  Serial.println("Smart Agriculture System Started");
}

void loop() {
  server.handleClient();
  readArduinoData();
  updateStatusIndicators();

  unsigned long now = millis();

  if (now - lastThingSpeak >= THINGSPEAK_INTERVAL) {
    lastThingSpeak = now;
    sendToThingSpeak();
  }

  if (now - lastN8N >= N8N_INTERVAL) {
    lastN8N = now;
    sendToN8N();
  }
}

ThingSpeak channels support up to eight fields, so this project uses Field 1 for temperature, Field 2 for humidity, and Field 3 for soil moisture.[docs.sparkfun][raw.githubusercontent]

n8n Workflow

n8n can connect Google Sheets and Telegram through native nodes, while HTTP Request nodes can call external AI or TTS APIs.[n8n]

Workflow Diagram

ESP32-S3
   │
   ▼
Webhook Trigger
   │
   ▼
Set / Edit Fields
   │
   ▼
IF Node: Check Thresholds
   │
   ├── False ──► Google Sheets: Append Normal Reading
   │
   └── True ──► Google Sheets: Append Alert Reading
                  │
                  ├── Gmail: Send Alert Email
                  │
                  ├── Telegram: Send Text Message
                  │
                  └── OpenAI / TTS API
                         │
                         ▼
                    Telegram: Send Voice Alert

Google Sheet Columns

Create a Google Sheet named Smart Agriculture Log with these headers:

Timestamp Device Temperature C Humidity % Soil Moisture % Status Alert Message

n8n’s Google Sheets integration supports appending rows and upserting existing rows.[n8n]

n8n Webhook Configuration

Create a workflow with a Webhook node:

  • HTTP Method: POST
  • Path: agriculture
  • Response Mode: Immediately
  • Webhook URL: https://YOUR_N8N_DOMAIN/webhook/agriculture

Use this URL in the ESP32 code as N8N_WEBHOOK_URL.

IF Node Condition

Add an IF node with the following logic:

Temperature < 18
OR Temperature > 32
OR Humidity < 40
OR Humidity > 80
OR Soil Moisture < 40
OR Soil Moisture > 80

In n8n, use the expression editor:

{{ $json.temperature < 18 ||
   $json.temperature > 32 ||
   $json.humidity < 40 ||
   $json.humidity > 80 ||
   $json.soilMoisture < 40 ||
   $json.soilMoisture > 80 }}

Gmail Alert Message

Use a Gmail node with:

  • To: farmer@example.com
  • Subject: ⚠️ Smart Agriculture Alert
  • Message:
Smart Agriculture Alert

Device: {{ $json.device }}
Temperature: {{ $json.temperature }} °C
Humidity: {{ $json.humidity }} %
Soil Moisture: {{ $json.soilMoisture }} %

Immediate attention may be required.

Telegram Text Alert

Use a Telegram node:

  • Credential: Your Telegram Bot API credential
  • Chat ID: Your farmer/group chat ID
  • Text:
🚨 Smart Agriculture Alert

🌡️ Temperature: {{ $json.temperature }} °C
💧 Humidity: {{ $json.humidity }} %
🌱 Soil Moisture: {{ $json.soilMoisture }} %

Please inspect the field immediately.

AI Voice Alert

Use an HTTP Request node to call a text-to-speech API such as OpenAI TTS, ElevenLabs, or Google Cloud Text-to-Speech. Then send the resulting audio file to Telegram using Telegram’s sendVoice or sendAudio operation.

Example alert text for TTS:

Agricultural alert. Temperature is {{ $json.temperature }} degrees Celsius.
Humidity is {{ $json.humidity }} percent.
Soil moisture is {{ $json.soilMoisture }} percent.
Please check the field immediately.

A practical n8n pattern is: receive Telegram voice/text, transcribe if needed, use an AI model to create structured output, then send a confirmation or voice response through Telegram. Similar workflows use Telegram triggers, transcription, AI parsing, Google Sheets logging, and Telegram replies.[n8n][n8n]

ThingSpeak Dashboard Setup

  1. Create a free ThingSpeak account.
  2. Create a new channel.
  3. Enable fields:

    • Field 1: Temperature
    • Field 2: Humidity
    • Field 3: Soil Moisture
  4. Copy the Channel ID and Write API Key.
  5. Paste them into the ESP32 code.
  6. Use the channel’s Private View or Public View for charts.

ThingSpeak’s update endpoint is https://api.thingspeak.com/update.json, and the write API key is available from the channel’s API Keys tab.[mathworks]

Testing Procedure

  1. Upload the Arduino UNO code.
  2. Open Serial Monitor at 9600 baud and confirm JSON output.
  3. Upload the ESP32-S3 code.
  4. Open Serial Monitor at 115200 baud.
  5. Confirm Wi-Fi connection and note the ESP32 IP address.
  6. Open http://ESP32_IP_ADDRESS/ in a browser.
  7. Verify temperature, humidity, and soil-moisture readings.
  8. Confirm ThingSpeak charts update every 20 seconds.
  9. Activate the n8n workflow and confirm webhook reception.
  10. Test alerts by heating the DHT sensor, breathing near it, or placing the soil sensor in dry and wet conditions.
  11. Verify Gmail, Telegram text, and Telegram voice alerts.

Safety and Reliability Tips

  • Keep the ESP32 and Arduino grounds connected.
  • Never connect a 5V Arduino TX directly to an ESP32 GPIO input.
  • Use a capacitive soil sensor rather than a resistive one for longer life.
  • Protect the electronics from rain using an IP65 enclosure.
  • Keep sensor cables short and use waterproof connectors outdoors.
  • Add a rechargeable battery or solar power system for remote deployment.
  • Do not expose API keys, Wi-Fi passwords, or Telegram tokens in public code.
  • Add a capacitor across the soil sensor power lines to reduce ADC noise.
  • Send alerts only when a threshold remains violated for several readings to avoid false alarms.

Possible Viva Questions

Why use both Arduino UNO and ESP32-S3?
Arduino UNO handles reliable sensor interfacing, while ESP32-S3 provides Wi-Fi, cloud communication, web dashboard hosting, and automation integration.

Why use n8n instead of coding alerts directly in ESP32?
n8n separates automation logic from embedded hardware, making it easier to change thresholds, add services, manage credentials, and scale without reflashing the ESP32.

What makes the system AI-powered?
The system uses AI text-to-speech to generate a natural voice alert and can optionally use an AI agent to analyze sensor trends, classify risk, and generate crop-specific recommendations.

What is the role of ThingSpeak?
ThingSpeak provides live cloud charts and historical IoT data storage through its REST API.[mathworks][docs.espressif]

How does soil moisture percentage work?
The raw ADC value is mapped between a calibrated dry value and wet value, then constrained to 0–100%.

Final Project Description

The AI-Powered Smart Agriculture Monitoring System is an IoT-based solution that helps farmers monitor field conditions in real time. Arduino UNO reads temperature, humidity, and soil-moisture sensors and sends the data to an ESP32-S3. The ESP32-S3 hosts a mobile-friendly IoT webpage, uploads readings to ThingSpeak, and forwards data to an n8n automation workflow.

n8n evaluates the readings against crop-friendly thresholds. When abnormal conditions are detected, it records the event in Google Sheets, sends a Gmail warning, sends a Telegram text alert, and generates an AI voice notification delivered through Telegram. This gives the farmer immediate awareness of overheating, excessive humidity, dry soil, or waterlogged soil, enabling faster irrigation and crop-protection decisions.