Sunday, 11 October 2026

AI Sleep Detection & Driver Alert System

 

AI Sleep Detection & Driver Alert System

ESP32 + AI + IoT Web Dashboard + n8n Automation + Telegram Voice Alerts + Google Sheets + ThingSpeak

This project is designed to detect signs of driver drowsiness, immediately alert the driver, and send monitoring data to an IoT dashboard. It combines an ESP32-based embedded system with AI-assisted event analysis, n8n automation, Telegram notifications, Google Sheets data logging, and ThingSpeak cloud visualization.

AI-Assisted Driver Drowsiness Detection System Using RPI4 - Hackster.io
 
 
 
Driver Safety Monitoring System | AI Alerts to Prevent Accidents – LogisFleet
 
 
 
ESP32 IOT Dashboard. | ESP32
 
9
 

Proposed project title

AI-Powered IoT-Based Driver Sleep Detection and Alert System Using ESP32, AI Agent, n8n Automation, Telegram Voice Notifications, Google Sheets and ThingSpeak Cloud Dashboard.

The key safety principle is that drowsiness detection and the immediate local warning must work even if Wi-Fi, the cloud, or n8n is unavailable. Cloud AI and automation are supplementary features, not the only way to alert a sleepy driver.

1. Project abstract

Driver fatigue and drowsiness can reduce attention, slow reaction time, and increase road-safety risks. This project proposes an embedded driver-monitoring prototype that identifies possible drowsiness from eye-closure signals, activates a local alarm, and transmits event information to a cloud-connected monitoring platform.

The ESP32 collects sensor data and evaluates a configurable drowsiness rule. When a possible drowsiness event occurs, a buzzer and warning LED activate. The ESP32 then sends an event through Wi-Fi to an n8n webhook. The n8n workflow can log the event in Google Sheets, send Telegram notifications, and update the IoT monitoring dashboard. An AI agent can summarize repeated events and produce human-readable reports.

For a camera-based version, an ESP32-S3 camera board can be used to develop an eye-state detection model. Espressif provides the ESP32-S3-EYE platform and ESP-WHO computer-vision framework as a starting point for embedded vision development. Eye-closure detection for driving requires a suitable model and validation beyond basic face detection.

documentation.espressif.com
+1

 

Project objectives

  • Detect prolonged eye closure or other signs of possible drowsiness.

  • Trigger an immediate local buzzer and LED warning.

  • Display system status on an IoT webpage.

  • Automate alerts through n8n and Telegram.

  • Record event time, duration, and alert level in Google Sheets.

  • Visualize numerical monitoring data using ThingSpeak.

  • Use an AI agent to analyze event history and summarize risk patterns.

  • Continue local warning operation if cloud connectivity fails.

2. System architecture

Driver monitoring sensors

IR eye-blink sensor for the starter prototype, or camera-based eye-state AI

 

ESP32 / ESP32-S3 controller

Evaluate eye state, track closure duration, trigger buzzer and LED

Wi-Fi event transmission

n8n automation and AI agent

Webhook → event validation → logging → alerting → optional AI summary

Telegram

Text and optional voice alerts

Google Sheets

Event history and reports

ThingSpeak

Time-series charts

IoT webpage

Live status and event history

Important design distinction: the local alarm is controlled by the ESP32. The cloud system handles remote notifications, recordkeeping, visualization, and optional AI analysis. The AI agent must not be the sole mechanism responsible for an urgent driver warning.

3. Hardware components required

For the first working prototype, use a digital eye-blink sensor. It is simpler to test than a camera-based AI model and helps you build the complete IoT automation pipeline first.

GitHub - TronixLab/DOIT_ESP32_DevKit-v1_30P · GitHub
 
 
 

1. ESP32 DevKit V1

Main microcontroller

Handles sensor readings, drowsiness timing, the local alarm, and Wi-Fi communication.

 
Eye Blink Sensor (High Quality) With Goggle
 – Harish Projects
 
 
 

2. IR eye-blink sensor module

Driver eye-state input

Supplies a digital signal representing detected eye/blink states. Verify its output polarity and whether it can reliably distinguish open eyes from closed eyes before setting thresholds.

 
Active Buzzer Module - 3.3-5V | Fastbit Embedded
 
 
 

3. Active buzzer

Generates the immediate audible warning. Use a suitable transistor driver if the buzzer current exceeds the GPIO's safe output capability.

 
Chanzon Breadboard Kit - Solderless Prototype with Morocco | Ubuy
 
 
 

4. Red LED, 220–330 Ω resistor, breadboard and jumper wires

Visual warning and circuit prototyping.

 
Espressif ESP32-S3-EYE - ESP32-S3 Camera Board - The Pi Hut
 
 
 

5. Optional camera AI upgrade

Use an ESP32-S3-EYE or another supported camera platform for face/eye tracking. The camera version requires camera-specific firmware and a validated eye-state model; the starter code below does not perform image-based AI.

You will also need a USB data cable, a computer, Wi-Fi, an n8n instance, a Telegram bot, a Google account, and a ThingSpeak account.

4. Circuit / schematic diagram

This is the proposed wiring for the digital IR-sensor starter version.

IR eye-blink sensor

VCC → suitable supply voltage for the module

GND → GND

OUT → GPIO 27

 

ESP32 DevKit V1

GPIO 27: sensor input

GPIO 26: buzzer driver output

GPIO 25: LED output

GND: common ground

GPIO 26

Buzzer driver

Then buzzer and suitable supply

GPIO 25

220–330 Ω resistor

Then LED → GND

Connect all grounds together. Confirm sensor voltage compatibility and output polarity before connecting it to the ESP32. Never feed 5 V directly into an ESP32 GPIO.

Pin connection table

Component

ESP32 connection

IR sensor OUT

GPIO 27

Active buzzer driver input

GPIO 26

LED anode through resistor

GPIO 25

Sensor GND

GND

Buzzer-driver GND

GND

Sensor VCC

Per module specification

For a camera-based version, follow the camera board's own pin mapping. Do not reuse these GPIO assignments blindly on an ESP32-S3 camera board, because camera and peripheral pins may already be allocated.

5. Flowchart of the complete system

#chatgpt-mermaid-_r_c9_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,"Segoe UI",Helvetica,"Apple Color Emoji",Arial,sans-serif,"Segoe UI Emoji","Segoe UI Symbol";font-size:16px;fill:rgb(13, 13, 13);}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#chatgpt-mermaid-_r_c9_ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_c9_ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_c9_ .error-icon{fill:rgb(243, 243, 243);}#chatgpt-mermaid-_r_c9_ .error-text{fill:rgb(13, 13, 13);stroke:rgb(13, 13, 13);}#chatgpt-mermaid-_r_c9_ .edge-thickness-normal{stroke-width:1px;}#chatgpt-mermaid-_r_c9_ .edge-thickness-thick{stroke-width:3.5px;}#chatgpt-mermaid-_r_c9_ .edge-pattern-solid{stroke-dasharray:0;}#chatgpt-mermaid-_r_c9_ .edge-thickness-invisible{stroke-width:0;fill:none;}#chatgpt-mermaid-_r_c9_ .edge-pattern-dashed{stroke-dasharray:3;}#chatgpt-mermaid-_r_c9_ .edge-pattern-dotted{stroke-dasharray:2;}#chatgpt-mermaid-_r_c9_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_c9_ .marker.cross{stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_c9_ svg{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,"Segoe UI",Helvetica,"Apple Color Emoji",Arial,sans-serif,"Segoe UI Emoji","Segoe UI Symbol";font-size:16px;}#chatgpt-mermaid-_r_c9_ p{margin:0;}#chatgpt-mermaid-_r_c9_ .label{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,"Segoe UI",Helvetica,"Apple Color Emoji",Arial,sans-serif,"Segoe UI Emoji","Segoe UI Symbol";color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_c9_ .cluster-label text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_c9_ .cluster-label span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_c9_ .cluster-label span p{background-color:transparent;}#chatgpt-mermaid-_r_c9_ .label text,#chatgpt-mermaid-_r_c9_ span{fill:rgb(13, 13, 13);color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_c9_ .node rect,#chatgpt-mermaid-_r_c9_ .node circle,#chatgpt-mermaid-_r_c9_ .node ellipse,#chatgpt-mermaid-_r_c9_ .node polygon,#chatgpt-mermaid-_r_c9_ .node path{fill:rgb(222, 234, 251);stroke:rgb(83, 154, 248);stroke-width:1px;}#chatgpt-mermaid-_r_c9_ .rough-node .label text,#chatgpt-mermaid-_r_c9_ .node .label text,#chatgpt-mermaid-_r_c9_ .image-shape .label,#chatgpt-mermaid-_r_c9_ .icon-shape .label{text-anchor:middle;}#chatgpt-mermaid-_r_c9_ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#chatgpt-mermaid-_r_c9_ .rough-node .label,#chatgpt-mermaid-_r_c9_ .node .label,#chatgpt-mermaid-_r_c9_ .image-shape .label,#chatgpt-mermaid-_r_c9_ .icon-shape .label{text-align:center;}#chatgpt-mermaid-_r_c9_ .node.clickable{cursor:pointer;}#chatgpt-mermaid-_r_c9_ .root .anchor path{fill:rgb(143, 143, 143)!important;stroke-width:0;stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_c9_ .arrowheadPath{fill:rgb(143, 143, 143);}#chatgpt-mermaid-_r_c9_ .edgePath .path{stroke:rgb(143, 143, 143);stroke-width:1px;}#chatgpt-mermaid-_r_c9_ .flowchart-link{stroke:rgb(143, 143, 143);fill:none;}#chatgpt-mermaid-_r_c9_ .edgeLabel{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_c9_ .edgeLabel p{background-color:rgb(252, 252, 252);}#chatgpt-mermaid-_r_c9_ .edgeLabel rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_c9_ .labelBkg{background-color:rgba(252, 252, 252, 0.5);}#chatgpt-mermaid-_r_c9_ .cluster rect{fill:rgb(243, 243, 243);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_c9_ .cluster text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_c9_ .cluster span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_c9_ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,"Segoe UI",Helvetica,"Apple Color Emoji",Arial,sans-serif,"Segoe UI Emoji","Segoe UI Symbol";font-size:12px;background:rgb(243, 243, 243);border:1px solid rgba(0, 0, 0, 0.1);border-radius:2px;pointer-events:none;z-index:100;}#chatgpt-mermaid-_r_c9_ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_c9_ rect.text{fill:none;stroke-width:0;}#chatgpt-mermaid-_r_c9_ .icon-shape,#chatgpt-mermaid-_r_c9_ .image-shape{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_c9_ .icon-shape p,#chatgpt-mermaid-_r_c9_ .image-shape p{background-color:rgb(252, 252, 252);padding:2px;}#chatgpt-mermaid-_r_c9_ .icon-shape .label rect,#chatgpt-mermaid-_r_c9_ .image-shape .label rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_c9_ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#chatgpt-mermaid-_r_c9_ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#chatgpt-mermaid-_r_c9_ .node .neo-node{stroke:rgb(83, 154, 248);}#chatgpt-mermaid-_r_c9_ [data-look="neo"].node rect,#chatgpt-mermaid-_r_c9_ [data-look="neo"].cluster rect,#chatgpt-mermaid-_r_c9_ [data-look="neo"].node polygon{stroke:url(#chatgpt-mermaid-_r_c9_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_c9_ [data-look="neo"].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_c9_ [data-look="neo"].node path{stroke:url(#chatgpt-mermaid-_r_c9_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_c9_ [data-look="neo"].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_c9_ [data-look="neo"].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_c9_ [data-look="neo"].node circle{stroke:url(#chatgpt-mermaid-_r_c9_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_c9_ [data-look="neo"].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_c9_ [data-look="neo"].icon-shape .icon{fill:url(#chatgpt-mermaid-_r_c9_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_c9_ [data-look="neo"].icon-shape .icon-neo path{stroke:url(#chatgpt-mermaid-_r_c9_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_c9_ .node text{font-size:14px;font-weight:600;letter-spacing:normal;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_c9_ .edgeLabels text{font-size:13px;font-weight:600;letter-spacing:-0.08px;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_c9_ .node tspan[font-weight="normal"],#chatgpt-mermaid-_r_c9_ .edgeLabels tspan[font-weight="normal"]{font-weight:600;}#chatgpt-mermaid-_r_c9_ .edgeLabel .label rect{opacity:1;rx:13px;ry:13px;fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-width:1px;}#chatgpt-mermaid-_r_c9_ .node rect,#chatgpt-mermaid-_r_c9_ .node circle,#chatgpt-mermaid-_r_c9_ .node ellipse,#chatgpt-mermaid-_r_c9_ .node polygon,#chatgpt-mermaid-_r_c9_ .node path{fill:rgb(229, 243, 255);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_c9_ .node rect{rx:16px;ry:16px;}#chatgpt-mermaid-_r_c9_ .node.mermaid-decision .label-container{fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-dasharray:2,2;}#chatgpt-mermaid-_r_c9_ .edgePaths .flowchart-link{stroke:rgb(143, 143, 143);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;}#chatgpt-mermaid-_r_c9_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_c9_ :root{--mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,"Segoe UI",Helvetica,"Apple Color Emoji",Arial,sans-serif,"Segoe UI Emoji","Segoe UI Symbol";}Power ONInitialize ESP32, sensor andalarmSensor signal valid?Show sensor fault and warnlocallyRead eye stateEyes closed?Reset closure timerMeasure continuous closuredurationClosure exceeds threshold?Activate buzzer and warningLEDSend event through Wi-FiCloud reachable?Keep local alarm activeRetry event transmissionn8n webhook receives eventLog event in Google SheetsSend Telegram alertUpdate ThingSpeak anddashboardOptional AI event summaryRe-evaluate eye stateNoYesNoYesNoYesNoYes

This flowchart represents the intended design. The cloud retries, persistent event queue, and sensor-fault detection must be implemented and tested in the final firmware before treating those features as operational.

6. How the system works — step by step

  1. System startup

    The ESP32 initializes the sensor input, warning LED, buzzer output, serial monitor, and Wi-Fi connection.

  2. Eye-state monitoring

    The sensor reports a signal that the firmware interprets as open or closed. Sensor placement and signal polarity must be verified experimentally.

  3. Drowsiness timing

    The ESP32 measures how long the signal continuously indicates closed eyes. A short closure is ignored; a prolonged closure triggers the configured warning.

  4. Local warning

    The buzzer and LED activate without waiting for an internet request. A real driver-monitoring system should also detect sensor obstruction, poor lighting, and invalid readings where applicable.

  5. IoT event upload

    The ESP32 sends an event containing a device identifier, event type, duration, and alert level to an n8n webhook.

  6. n8n automation

    n8n validates the payload, records it, and routes the event to the required services. The n8n Telegram integration supports sending messages through a configured bot.

    n8n Docs

     

  7. Cloud monitoring

    Google Sheets stores a history of events. ThingSpeak records numeric fields for time-series charts, and the webpage displays the latest status and event information.

  8. AI-agent analysis

    An AI agent can summarize repeated events, identify patterns in recorded data, and generate a daily report. Its output is advisory; it does not decide whether the local safety alarm activates.

7. ESP32 Arduino software code

The following is a starter firmware for the IR-sensor version. It implements the local warning and sends an event to an n8n webhook and ThingSpeak.

It assumes the sensor output is LOW when the eyes are detected as closed. If your module works in the opposite direction, change the configuration constant after testing.

Before uploading, install the ESP32 board package in Arduino IDE and configure the board for your exact ESP32 model.


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

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

// ---------- n8n webhook ----------
// Example: https://your-n8n-domain/webhook/driver-event
const char* N8N_WEBHOOK =
  "https://YOUR_N8N_DOMAIN/webhook/driver-event";

// ---------- ThingSpeak ----------
const char* THINGSPEAK_WRITE_KEY = "YOUR_WRITE_API_KEY";

// ---------- GPIO (ESP32 DevKit V1 example) ----------
const int EYE_SENSOR_PIN = 27;
const int BUZZER_PIN = 26;
const int LED_PIN = 25;

// Verify sensor output polarity before using.
const int CLOSED_LEVEL = LOW;

// Demo threshold only. Must be calibrated and validated.
const unsigned long CLOSED_THRESHOLD_MS = 1500;
const unsigned long EVENT_COOLDOWN_MS = 10000;

unsigned long closedSince = 0;
unsigned long lastEvent = 0;
bool wasClosed = false;
bool alarmActive = false;
bool eventSentForClosure = false;

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

  Serial.print("Connecting to Wi-Fi...");
  unsigned long start = millis();

  while (WiFi.status() != WL_CONNECTED &&
         millis() - start < 15000) {
    delay(300);
    Serial.print(".");
  }

  Serial.println();

  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("Wi-Fi connected");
    Serial.println(WiFi.localIP());
  } else {
    Serial.println("Wi-Fi unavailable; local alarm remains active");
  }
}

void setAlarm(bool active) {
  alarmActive = active;
  digitalWrite(BUZZER_PIN, active ? HIGH : LOW);
  digitalWrite(LED_PIN, active ? HIGH : LOW);
}

bool postToN8n(unsigned long durationMs) {
  if (WiFi.status() != WL_CONNECTED) return false;

  WiFiClientSecure client;

  // DEMO ONLY: disables TLS certificate verification.
  // For production, configure the correct CA certificate.
  client.setInsecure();

  HTTPClient https;
  if (!https.begin(client, N8N_WEBHOOK)) return false;

  https.addHeader("Content-Type", "application/json");

  JsonDocument doc;
  doc["device_id"] = "driver-unit-01";
  doc["event"] = "DROWSINESS_WARNING";
  doc["eye_closed_ms"] = durationMs;
  doc["alert_level"] = "HIGH";
  doc["uptime_ms"] = millis();

  String payload;
  serializeJson(doc, payload);

  int status = https.POST(payload);
  https.end();

  Serial.printf("n8n HTTP status: %d\n", status);
  return status >= 200 && status < 300;
}

bool updateThingSpeak(unsigned long durationMs) {
  if (WiFi.status() != WL_CONNECTED) return false;

  WiFiClientSecure client;

  // DEMO ONLY: use certificate validation in production.
  client.setInsecure();

  HTTPClient https;
  String url =
    "https://api.thingspeak.com/update?api_key=" +
    String(THINGSPEAK_WRITE_KEY) +
    "&field1=" + String(alarmActive ? 1 : 0) +
    "&field2=" + String(durationMs / 1000.0, 1) +
    "&field3=1";

  if (!https.begin(client, url)) return false;

  int status = https.GET();
  String response = https.getString();
  https.end();

  Serial.printf("ThingSpeak HTTP status: %d\n", status);
  Serial.println("ThingSpeak response: " + response);

  // ThingSpeak returns a non-zero entry ID for a successful update.
  return status >= 200 && status < 300 &&
         response.toInt() > 0;
}

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

  pinMode(EYE_SENSOR_PIN, INPUT);
  pinMode(BUZZER_PIN, OUTPUT);
  pinMode(LED_PIN, OUTPUT);

  setAlarm(false);
  connectWiFi();

  Serial.println("Driver monitoring prototype ready");
}

void loop() {
  unsigned long now = millis();
  bool eyesClosed =
    digitalRead(EYE_SENSOR_PIN) == CLOSED_LEVEL;

  if (eyesClosed) {
    if (!wasClosed) {
      closedSince = now;
      wasClosed = true;
      eventSentForClosure = false;
    }

    unsigned long duration = now - closedSince;

    if (duration >= CLOSED_THRESHOLD_MS) {
      setAlarm(true);

      if (!eventSentForClosure &&
          (lastEvent == 0 ||
           now - lastEvent >= EVENT_COOLDOWN_MS)) {

        // Try cloud delivery once per qualifying closure.
        bool n8nOk = postToN8n(duration);
        bool tsOk = updateThingSpeak(duration);

        Serial.printf("n8n=%s, ThingSpeak=%s\n",
          n8nOk ? "OK" : "FAILED",
          tsOk ? "OK" : "FAILED");

        lastEvent = now;
        eventSentForClosure = true;
      }
    }
  } else {
    wasClosed = false;
    closedSince = 0;
    eventSentForClosure = false;
    setAlarm(false);
  }

  delay(20);
}

Important notes about the starter code

  • The 1.5-second threshold is a demonstration setting, not a medically or scientifically validated drowsiness threshold.

  • This code does not run an AI vision model. It uses a digital sensor signal and a timing rule.

  • A sensor that cannot reliably identify eye closure cannot reliably detect drowsiness. Validate the actual sensor before relying on its output.

  • setInsecure() disables HTTPS certificate verification. It is included only to simplify a controlled classroom demonstration; replace it with certificate validation before real deployment.

  • The code makes one upload attempt per qualifying closure. A production version needs a persistent retry queue, duplicate-event protection, and verified sensor-fault handling.

  • The example's buzzer turns off when the sensor indicates open eyes. For a validated safety-oriented design, define explicit alarm acknowledgement and recovery logic and test it thoroughly.

  • Do not test the prototype while driving on public roads. Bench-test it first, then conduct any further testing under appropriate controlled conditions.

8. n8n automation workflow

The n8n workflow is the central automation layer. It receives the event from the ESP32 and forwards it to your chosen cloud services.

#chatgpt-mermaid-_r_d0_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,"Segoe UI",Helvetica,"Apple Color Emoji",Arial,sans-serif,"Segoe UI Emoji","Segoe UI Symbol";font-size:16px;fill:rgb(13, 13, 13);}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#chatgpt-mermaid-_r_d0_ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_d0_ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_d0_ .error-icon{fill:rgb(243, 243, 243);}#chatgpt-mermaid-_r_d0_ .error-text{fill:rgb(13, 13, 13);stroke:rgb(13, 13, 13);}#chatgpt-mermaid-_r_d0_ .edge-thickness-normal{stroke-width:1px;}#chatgpt-mermaid-_r_d0_ .edge-thickness-thick{stroke-width:3.5px;}#chatgpt-mermaid-_r_d0_ .edge-pattern-solid{stroke-dasharray:0;}#chatgpt-mermaid-_r_d0_ .edge-thickness-invisible{stroke-width:0;fill:none;}#chatgpt-mermaid-_r_d0_ .edge-pattern-dashed{stroke-dasharray:3;}#chatgpt-mermaid-_r_d0_ .edge-pattern-dotted{stroke-dasharray:2;}#chatgpt-mermaid-_r_d0_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_d0_ .marker.cross{stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_d0_ svg{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,"Segoe UI",Helvetica,"Apple Color Emoji",Arial,sans-serif,"Segoe UI Emoji","Segoe UI Symbol";font-size:16px;}#chatgpt-mermaid-_r_d0_ p{margin:0;}#chatgpt-mermaid-_r_d0_ .label{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,"Segoe UI",Helvetica,"Apple Color Emoji",Arial,sans-serif,"Segoe UI Emoji","Segoe UI Symbol";color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_d0_ .cluster-label text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_d0_ .cluster-label span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_d0_ .cluster-label span p{background-color:transparent;}#chatgpt-mermaid-_r_d0_ .label text,#chatgpt-mermaid-_r_d0_ span{fill:rgb(13, 13, 13);color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_d0_ .node rect,#chatgpt-mermaid-_r_d0_ .node circle,#chatgpt-mermaid-_r_d0_ .node ellipse,#chatgpt-mermaid-_r_d0_ .node polygon,#chatgpt-mermaid-_r_d0_ .node path{fill:rgb(222, 234, 251);stroke:rgb(83, 154, 248);stroke-width:1px;}#chatgpt-mermaid-_r_d0_ .rough-node .label text,#chatgpt-mermaid-_r_d0_ .node .label text,#chatgpt-mermaid-_r_d0_ .image-shape .label,#chatgpt-mermaid-_r_d0_ .icon-shape .label{text-anchor:middle;}#chatgpt-mermaid-_r_d0_ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#chatgpt-mermaid-_r_d0_ .rough-node .label,#chatgpt-mermaid-_r_d0_ .node .label,#chatgpt-mermaid-_r_d0_ .image-shape .label,#chatgpt-mermaid-_r_d0_ .icon-shape .label{text-align:center;}#chatgpt-mermaid-_r_d0_ .node.clickable{cursor:pointer;}#chatgpt-mermaid-_r_d0_ .root .anchor path{fill:rgb(143, 143, 143)!important;stroke-width:0;stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_d0_ .arrowheadPath{fill:rgb(143, 143, 143);}#chatgpt-mermaid-_r_d0_ .edgePath .path{stroke:rgb(143, 143, 143);stroke-width:1px;}#chatgpt-mermaid-_r_d0_ .flowchart-link{stroke:rgb(143, 143, 143);fill:none;}#chatgpt-mermaid-_r_d0_ .edgeLabel{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_d0_ .edgeLabel p{background-color:rgb(252, 252, 252);}#chatgpt-mermaid-_r_d0_ .edgeLabel rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_d0_ .labelBkg{background-color:rgba(252, 252, 252, 0.5);}#chatgpt-mermaid-_r_d0_ .cluster rect{fill:rgb(243, 243, 243);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_d0_ .cluster text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_d0_ .cluster span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_d0_ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,"Segoe UI",Helvetica,"Apple Color Emoji",Arial,sans-serif,"Segoe UI Emoji","Segoe UI Symbol";font-size:12px;background:rgb(243, 243, 243);border:1px solid rgba(0, 0, 0, 0.1);border-radius:2px;pointer-events:none;z-index:100;}#chatgpt-mermaid-_r_d0_ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_d0_ rect.text{fill:none;stroke-width:0;}#chatgpt-mermaid-_r_d0_ .icon-shape,#chatgpt-mermaid-_r_d0_ .image-shape{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_d0_ .icon-shape p,#chatgpt-mermaid-_r_d0_ .image-shape p{background-color:rgb(252, 252, 252);padding:2px;}#chatgpt-mermaid-_r_d0_ .icon-shape .label rect,#chatgpt-mermaid-_r_d0_ .image-shape .label rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_d0_ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#chatgpt-mermaid-_r_d0_ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#chatgpt-mermaid-_r_d0_ .node .neo-node{stroke:rgb(83, 154, 248);}#chatgpt-mermaid-_r_d0_ [data-look="neo"].node rect,#chatgpt-mermaid-_r_d0_ [data-look="neo"].cluster rect,#chatgpt-mermaid-_r_d0_ [data-look="neo"].node polygon{stroke:url(#chatgpt-mermaid-_r_d0_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_d0_ [data-look="neo"].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_d0_ [data-look="neo"].node path{stroke:url(#chatgpt-mermaid-_r_d0_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_d0_ [data-look="neo"].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_d0_ [data-look="neo"].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_d0_ [data-look="neo"].node circle{stroke:url(#chatgpt-mermaid-_r_d0_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_d0_ [data-look="neo"].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_d0_ [data-look="neo"].icon-shape .icon{fill:url(#chatgpt-mermaid-_r_d0_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_d0_ [data-look="neo"].icon-shape .icon-neo path{stroke:url(#chatgpt-mermaid-_r_d0_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_d0_ .node text{font-size:14px;font-weight:600;letter-spacing:normal;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_d0_ .edgeLabels text{font-size:13px;font-weight:600;letter-spacing:-0.08px;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_d0_ .node tspan[font-weight="normal"],#chatgpt-mermaid-_r_d0_ .edgeLabels tspan[font-weight="normal"]{font-weight:600;}#chatgpt-mermaid-_r_d0_ .edgeLabel .label rect{opacity:1;rx:13px;ry:13px;fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-width:1px;}#chatgpt-mermaid-_r_d0_ .node rect,#chatgpt-mermaid-_r_d0_ .node circle,#chatgpt-mermaid-_r_d0_ .node ellipse,#chatgpt-mermaid-_r_d0_ .node polygon,#chatgpt-mermaid-_r_d0_ .node path{fill:rgb(229, 243, 255);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_d0_ .node rect{rx:16px;ry:16px;}#chatgpt-mermaid-_r_d0_ .node.mermaid-decision .label-container{fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-dasharray:2,2;}#chatgpt-mermaid-_r_d0_ .edgePaths .flowchart-link{stroke:rgb(143, 143, 143);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;}#chatgpt-mermaid-_r_d0_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_d0_ :root{--mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,"Segoe UI",Helvetica,"Apple Color Emoji",Arial,sans-serif,"Segoe UI Emoji","Segoe UI Symbol";}ESP32 sends JSON eventWebhook TriggerValidate device and payloadValid event?Reject and log invalid eventNormalize event dataGoogle Sheets: Append RowTelegram: Send MessageAI Agent: Optional eventsummaryText-to-Speech serviceTelegram: Send AudioUpdate event statusIoT Dashboard / APINoYes

Build the workflow in n8n

  1. Create a Webhook node

    Set the HTTP method to POST and use a path such as driver-event. Use the production webhook URL after activating the workflow.

  2. Add an IF node

    Check that device_id, event, and eye_closed_ms exist. Only accept the expected event type, and apply authentication or a secret token to protect the webhook.

  3. Add a Google Sheets node

    Select your Google account, spreadsheet, worksheet, and the append-row operation. Map the incoming JSON properties to spreadsheet columns.

  4. Add a Telegram node

    Configure Telegram credentials and select the operation for sending a text message. n8n has a built-in Telegram integration for bot-based messaging.

    n8n Docs

     

  5. Add optional AI analysis

    Pass a limited event summary and recent aggregate counts to an AI Agent node. Ask it to summarize the history, not to diagnose a medical condition or decide whether the local alarm should sound.

  6. Add voice notifications

    Connect a text-to-speech service or an available TTS endpoint, then pass its generated audio file to Telegram's audio or voice-message operation. Text-to-speech is a separate integration; the Telegram node alone does not create spoken audio from arbitrary text.

  7. Add error handling

    Add error branches and workflow-failure notifications. Do not let a failed Google Sheets request prevent an urgent notification from being sent.

Example Telegram text alert

🚨 DRIVER DROWSINESS WARNING

Device: driver-unit-01
Event: Prolonged eye closure detected
Closure duration: 1.8 seconds
Alert level: HIGH

Please stop driving at a safe location as soon as possible and rest. Do not continue driving while sleepy.

This is an automated sensor alert, not a confirmed medical diagnosis.

Example spoken alert

Your text-to-speech service can turn the following into an audio clip:

Warning. Possible driver drowsiness detected. Please pay attention to your condition, pull over at a safe location, and rest before continuing your journey.

Voice-alert delivery options: a Telegram audio file, a Telegram voice message, or a spoken announcement on a separate in-vehicle speaker. Sending a remote Telegram message does not automatically make the driver's phone speak aloud; that depends on the phone's notification settings and the delivery method.

9. Google Sheets data logging

Create a Google spreadsheet named Driver_Sleep_Monitoring.

Use this first row as your header:

Column

Field

Example

A

Timestamp

Automatically generated by n8n

B

Device ID

driver-unit-01

C

Event

DROWSINESS_WARNING

D

Eye-closed duration (ms)

1800

E

Alert level

HIGH

F

Wi-Fi / device status

Connected

G

Notification status

Sent

H

AI summary

Repeated warning events observed

Configure the Google Sheets node to append one row per accepted event. Generate the timestamp on the server or in n8n rather than relying on a potentially incorrect device clock.

Example data for a demonstration:

Time

Device

Duration

Alert

10:05:01

driver-unit-01

300 ms

Normal

10:15:22

driver-unit-01

1800 ms

Warning

10:23:14

driver-unit-01

2200 ms

Warning

These are sample records, not actual measurements.

10. ThingSpeak cloud dashboard

Create a channel named Driver Sleep Detection.

ThingSpeak supports channels with up to eight numeric fields, making it suitable for storing the numerical values from this prototype.

GitHub
+1

 

Recommended channel fields:

Field

Meaning

Data

Field 1

Alarm status

0 = off, 1 = on

Field 2

Eye-closure duration

Seconds

Field 3

Drowsiness event

0 = no event, 1 = event

Field 4

Event counter

Number of events

For the current starter code, Field 1 represents the alarm state at upload time, Field 2 is closure duration in seconds, and Field 3 is set to 1 on each upload attempt. Field 4 is not yet implemented.

Setup steps:

  1. Create a ThingSpeak account and channel.

  2. Enable the fields listed above.

  3. Copy the channel's Write API Key into the firmware.

  4. Upload the firmware and check whether new channel entries appear.

  5. Use the channel's charts to display alarm status, closure duration, and event counts.

  6. Keep the channel private unless you have a reason to publish the data.

ThingSpeak update requests are subject to service limits and channel update timing. The code does not yet implement a queue or a schedule for failed uploads, so use a suitable sampling interval for your account and application.

11. IoT webpage dashboard

The webpage can be a responsive interface for desktop and mobile devices.

Driver Safety Monitor

Example dashboard layout

Prototype UI

System status

Monitoring

Last alert

Example

Closure duration

1.8 s

Cloud connection

Demo

 

Recommended dashboard sections

  • Current sensor state and alarm status
  • Latest events with timestamps
  • Closure duration and event-count charts
  • Wi-Fi, webhook, and cloud-service health
  • Telegram and voice-notification delivery history
  • Daily event summary generated by the AI agent

The values shown here are illustrative placeholders, not a live connection to your ESP32.

For the first version, embed the ThingSpeak charts in a webpage. For a more advanced version, build a separate webpage that retrieves current status and event history from an authenticated backend. Avoid exposing API keys, Telegram bot tokens, or n8n credentials in browser JavaScript.

12. AI agent design

The AI agent is an optional analysis layer that runs after event collection. It can use the recent event history to explain trends and prepare reports.

Suggested agent inputs

  • Device ID and event timestamp.

  • Eye-closure duration from each event.

  • Number of events in the last hour or day.

  • Sensor, Wi-Fi, and cloud connection status.

  • Notification delivery status.

Suggested AI-agent prompt

You are an assistant for an experimental driver-monitoring IoT system.

Analyze the supplied event records and produce:

  1. A concise summary of recent drowsiness-warning events.

  2. The number of warnings in the supplied period.

  3. Any repeated event patterns or sensor faults evident in the data.

  4. A clear note when data is missing or unreliable.

  5. A safety reminder when repeated warnings are present.

Do not diagnose a medical condition. Do not claim that the driver is safe based on missing events. Do not change the ESP32 alarm thresholds or disable any local warning. If the data is insufficient, state that clearly.

Output a short summary suitable for a monitoring dashboard and a Google Sheets report.

For an advanced version, the AI agent could request a daily aggregate from Google Sheets and write a summary to a separate report sheet. Keep the alert path independent of AI availability.

13. Project mind map

#chatgpt-mermaid-_r_el_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,"Segoe UI",Helvetica,"Apple Color Emoji",Arial,sans-serif,"Segoe UI Emoji","Segoe UI Symbol";font-size:16px;fill:rgb(13, 13, 13);}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#chatgpt-mermaid-_r_el_ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_el_ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_el_ .error-icon{fill:rgb(243, 243, 243);}#chatgpt-mermaid-_r_el_ .error-text{fill:rgb(13, 13, 13);stroke:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .edge-thickness-normal{stroke-width:1px;}#chatgpt-mermaid-_r_el_ .edge-thickness-thick{stroke-width:3.5px;}#chatgpt-mermaid-_r_el_ .edge-pattern-solid{stroke-dasharray:0;}#chatgpt-mermaid-_r_el_ .edge-thickness-invisible{stroke-width:0;fill:none;}#chatgpt-mermaid-_r_el_ .edge-pattern-dashed{stroke-dasharray:3;}#chatgpt-mermaid-_r_el_ .edge-pattern-dotted{stroke-dasharray:2;}#chatgpt-mermaid-_r_el_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_el_ .marker.cross{stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_el_ svg{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,"Segoe UI",Helvetica,"Apple Color Emoji",Arial,sans-serif,"Segoe UI Emoji","Segoe UI Symbol";font-size:16px;}#chatgpt-mermaid-_r_el_ p{margin:0;}#chatgpt-mermaid-_r_el_ .edge{stroke-width:3;}#chatgpt-mermaid-_r_el_ .section--1 rect,#chatgpt-mermaid-_r_el_ .section--1 path,#chatgpt-mermaid-_r_el_ .section--1 circle,#chatgpt-mermaid-_r_el_ .section--1 polygon,#chatgpt-mermaid-_r_el_ .section--1 path{fill:rgb(83, 154, 248);}#chatgpt-mermaid-_r_el_ .section--1 text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section--1 span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .node-icon--1{font-size:40px;color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-edge--1{stroke:rgb(83, 154, 248);}#chatgpt-mermaid-_r_el_ .edge-depth--1{stroke-width:17;}#chatgpt-mermaid-_r_el_ .section--1 line{stroke:rgb(247.0418994413, 166.3240223463, 59.4581005587);stroke-width:3;}#chatgpt-mermaid-_r_el_ .disabled,#chatgpt-mermaid-_r_el_ .disabled circle,#chatgpt-mermaid-_r_el_ .disabled text{fill:lightgray;}#chatgpt-mermaid-_r_el_ .disabled text{fill:#efefef;}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section--1 rect,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section--1 path,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section--1 circle,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section--1 polygon{fill:rgb(83, 154, 248);stroke:rgb(83, 154, 248);stroke-width:1px;}#chatgpt-mermaid-_r_el_ [data-look="neo"].section-edge--1{stroke:rgb(83, 154, 248);}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section--1 text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-0 rect,#chatgpt-mermaid-_r_el_ .section-0 path,#chatgpt-mermaid-_r_el_ .section-0 circle,#chatgpt-mermaid-_r_el_ .section-0 polygon,#chatgpt-mermaid-_r_el_ .section-0 path{fill:rgb(107, 198, 127);}#chatgpt-mermaid-_r_el_ .section-0 text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-0 span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .node-icon-0{font-size:40px;color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-edge-0{stroke:rgb(107, 198, 127);}#chatgpt-mermaid-_r_el_ .edge-depth-0{stroke-width:14;}#chatgpt-mermaid-_r_el_ .section-0 line{stroke:rgb(205.6463414634, 126.8536585367, 188.3292682927);stroke-width:3;}#chatgpt-mermaid-_r_el_ .disabled,#chatgpt-mermaid-_r_el_ .disabled circle,#chatgpt-mermaid-_r_el_ .disabled text{fill:lightgray;}#chatgpt-mermaid-_r_el_ .disabled text{fill:#efefef;}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-0 rect,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-0 path,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-0 circle,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-0 polygon{fill:rgb(107, 198, 127);stroke:rgb(107, 198, 127);stroke-width:1px;}#chatgpt-mermaid-_r_el_ [data-look="neo"].section-edge-0{stroke:rgb(107, 198, 127);}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-0 text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-1 rect,#chatgpt-mermaid-_r_el_ .section-1 path,#chatgpt-mermaid-_r_el_ .section-1 circle,#chatgpt-mermaid-_r_el_ .section-1 polygon,#chatgpt-mermaid-_r_el_ .section-1 path{fill:rgb(239, 139, 87);}#chatgpt-mermaid-_r_el_ .section-1 text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-1 span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .node-icon-1{font-size:40px;color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-edge-1{stroke:rgb(239, 139, 87);}#chatgpt-mermaid-_r_el_ .edge-depth-1{stroke-width:11;}#chatgpt-mermaid-_r_el_ .section-1 line{stroke:rgb(73.760869565, 181.6413043477, 237.7391304348);stroke-width:3;}#chatgpt-mermaid-_r_el_ .disabled,#chatgpt-mermaid-_r_el_ .disabled circle,#chatgpt-mermaid-_r_el_ .disabled text{fill:lightgray;}#chatgpt-mermaid-_r_el_ .disabled text{fill:#efefef;}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-1 rect,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-1 path,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-1 circle,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-1 polygon{fill:rgb(239, 139, 87);stroke:rgb(239, 139, 87);stroke-width:1px;}#chatgpt-mermaid-_r_el_ [data-look="neo"].section-edge-1{stroke:rgb(239, 139, 87);}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-1 text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-2 rect,#chatgpt-mermaid-_r_el_ .section-2 path,#chatgpt-mermaid-_r_el_ .section-2 circle,#chatgpt-mermaid-_r_el_ .section-2 polygon,#chatgpt-mermaid-_r_el_ .section-2 path{fill:rgb(248, 212, 93);}#chatgpt-mermaid-_r_el_ .section-2 text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-2 span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .node-icon-2{font-size:40px;color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-edge-2{stroke:rgb(248, 212, 93);}#chatgpt-mermaid-_r_el_ .edge-depth-2{stroke-width:8;}#chatgpt-mermaid-_r_el_ .section-2 line{stroke:rgb(50.3431952664, 95.8224852073, 246.1568047338);stroke-width:3;}#chatgpt-mermaid-_r_el_ .disabled,#chatgpt-mermaid-_r_el_ .disabled circle,#chatgpt-mermaid-_r_el_ .disabled text{fill:lightgray;}#chatgpt-mermaid-_r_el_ .disabled text{fill:#efefef;}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-2 rect,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-2 path,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-2 circle,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-2 polygon{fill:rgb(248, 212, 93);stroke:rgb(248, 212, 93);stroke-width:1px;}#chatgpt-mermaid-_r_el_ [data-look="neo"].section-edge-2{stroke:rgb(248, 212, 93);}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-2 text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-3 rect,#chatgpt-mermaid-_r_el_ .section-3 path,#chatgpt-mermaid-_r_el_ .section-3 circle,#chatgpt-mermaid-_r_el_ .section-3 polygon,#chatgpt-mermaid-_r_el_ .section-3 path{fill:rgb(184, 151, 244);}#chatgpt-mermaid-_r_el_ .section-3 text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-3 span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .node-icon-3{font-size:40px;color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-edge-3{stroke:rgb(184, 151, 244);}#chatgpt-mermaid-_r_el_ .edge-depth-3{stroke-width:5;}#chatgpt-mermaid-_r_el_ .section-3 line{stroke:rgb(149.7173913044, 219.3043478259, 23.1956521739);stroke-width:3;}#chatgpt-mermaid-_r_el_ .disabled,#chatgpt-mermaid-_r_el_ .disabled circle,#chatgpt-mermaid-_r_el_ .disabled text{fill:lightgray;}#chatgpt-mermaid-_r_el_ .disabled text{fill:#efefef;}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-3 rect,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-3 path,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-3 circle,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-3 polygon{fill:rgb(184, 151, 244);stroke:rgb(184, 151, 244);stroke-width:1px;}#chatgpt-mermaid-_r_el_ [data-look="neo"].section-edge-3{stroke:rgb(184, 151, 244);}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-3 text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-4 rect,#chatgpt-mermaid-_r_el_ .section-4 path,#chatgpt-mermaid-_r_el_ .section-4 circle,#chatgpt-mermaid-_r_el_ .section-4 polygon,#chatgpt-mermaid-_r_el_ .section-4 path{fill:rgb(246, 142, 188);}#chatgpt-mermaid-_r_el_ .section-4 text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-4 span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .node-icon-4{font-size:40px;color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-edge-4{stroke:rgb(246, 142, 188);}#chatgpt-mermaid-_r_el_ .edge-depth-4{stroke-width:2;}#chatgpt-mermaid-_r_el_ .section-4 line{stroke:rgb(18.405737705, 231.0942622953, 137.0204918033);stroke-width:3;}#chatgpt-mermaid-_r_el_ .disabled,#chatgpt-mermaid-_r_el_ .disabled circle,#chatgpt-mermaid-_r_el_ .disabled text{fill:lightgray;}#chatgpt-mermaid-_r_el_ .disabled text{fill:#efefef;}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-4 rect,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-4 path,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-4 circle,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-4 polygon{fill:rgb(246, 142, 188);stroke:rgb(246, 142, 188);stroke-width:1px;}#chatgpt-mermaid-_r_el_ [data-look="neo"].section-edge-4{stroke:rgb(246, 142, 188);}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-4 text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-5 rect,#chatgpt-mermaid-_r_el_ .section-5 path,#chatgpt-mermaid-_r_el_ .section-5 circle,#chatgpt-mermaid-_r_el_ .section-5 polygon,#chatgpt-mermaid-_r_el_ .section-5 path{fill:rgb(83, 154, 248);}#chatgpt-mermaid-_r_el_ .section-5 text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-5 span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .node-icon-5{font-size:40px;color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-edge-5{stroke:rgb(83, 154, 248);}#chatgpt-mermaid-_r_el_ .edge-depth-5{stroke-width:-1;}#chatgpt-mermaid-_r_el_ .section-5 line{stroke:rgb(247.0418994413, 166.3240223463, 59.4581005587);stroke-width:3;}#chatgpt-mermaid-_r_el_ .disabled,#chatgpt-mermaid-_r_el_ .disabled circle,#chatgpt-mermaid-_r_el_ .disabled text{fill:lightgray;}#chatgpt-mermaid-_r_el_ .disabled text{fill:#efefef;}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-5 rect,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-5 path,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-5 circle,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-5 polygon{fill:rgb(83, 154, 248);stroke:rgb(83, 154, 248);stroke-width:1px;}#chatgpt-mermaid-_r_el_ [data-look="neo"].section-edge-5{stroke:rgb(83, 154, 248);}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-5 text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-6 rect,#chatgpt-mermaid-_r_el_ .section-6 path,#chatgpt-mermaid-_r_el_ .section-6 circle,#chatgpt-mermaid-_r_el_ .section-6 polygon,#chatgpt-mermaid-_r_el_ .section-6 path{fill:rgb(107, 198, 127);}#chatgpt-mermaid-_r_el_ .section-6 text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-6 span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .node-icon-6{font-size:40px;color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-edge-6{stroke:rgb(107, 198, 127);}#chatgpt-mermaid-_r_el_ .edge-depth-6{stroke-width:-4;}#chatgpt-mermaid-_r_el_ .section-6 line{stroke:rgb(205.6463414634, 126.8536585367, 188.3292682927);stroke-width:3;}#chatgpt-mermaid-_r_el_ .disabled,#chatgpt-mermaid-_r_el_ .disabled circle,#chatgpt-mermaid-_r_el_ .disabled text{fill:lightgray;}#chatgpt-mermaid-_r_el_ .disabled text{fill:#efefef;}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-6 rect,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-6 path,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-6 circle,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-6 polygon{fill:rgb(107, 198, 127);stroke:rgb(107, 198, 127);stroke-width:1px;}#chatgpt-mermaid-_r_el_ [data-look="neo"].section-edge-6{stroke:rgb(107, 198, 127);}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-6 text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-7 rect,#chatgpt-mermaid-_r_el_ .section-7 path,#chatgpt-mermaid-_r_el_ .section-7 circle,#chatgpt-mermaid-_r_el_ .section-7 polygon,#chatgpt-mermaid-_r_el_ .section-7 path{fill:rgb(239, 139, 87);}#chatgpt-mermaid-_r_el_ .section-7 text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-7 span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .node-icon-7{font-size:40px;color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-edge-7{stroke:rgb(239, 139, 87);}#chatgpt-mermaid-_r_el_ .edge-depth-7{stroke-width:-7;}#chatgpt-mermaid-_r_el_ .section-7 line{stroke:rgb(73.760869565, 181.6413043477, 237.7391304348);stroke-width:3;}#chatgpt-mermaid-_r_el_ .disabled,#chatgpt-mermaid-_r_el_ .disabled circle,#chatgpt-mermaid-_r_el_ .disabled text{fill:lightgray;}#chatgpt-mermaid-_r_el_ .disabled text{fill:#efefef;}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-7 rect,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-7 path,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-7 circle,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-7 polygon{fill:rgb(239, 139, 87);stroke:rgb(239, 139, 87);stroke-width:1px;}#chatgpt-mermaid-_r_el_ [data-look="neo"].section-edge-7{stroke:rgb(239, 139, 87);}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-7 text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-8 rect,#chatgpt-mermaid-_r_el_ .section-8 path,#chatgpt-mermaid-_r_el_ .section-8 circle,#chatgpt-mermaid-_r_el_ .section-8 polygon,#chatgpt-mermaid-_r_el_ .section-8 path{fill:rgb(248, 212, 93);}#chatgpt-mermaid-_r_el_ .section-8 text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-8 span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .node-icon-8{font-size:40px;color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-edge-8{stroke:rgb(248, 212, 93);}#chatgpt-mermaid-_r_el_ .edge-depth-8{stroke-width:-10;}#chatgpt-mermaid-_r_el_ .section-8 line{stroke:rgb(50.3431952664, 95.8224852073, 246.1568047338);stroke-width:3;}#chatgpt-mermaid-_r_el_ .disabled,#chatgpt-mermaid-_r_el_ .disabled circle,#chatgpt-mermaid-_r_el_ .disabled text{fill:lightgray;}#chatgpt-mermaid-_r_el_ .disabled text{fill:#efefef;}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-8 rect,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-8 path,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-8 circle,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-8 polygon{fill:rgb(248, 212, 93);stroke:rgb(248, 212, 93);stroke-width:1px;}#chatgpt-mermaid-_r_el_ [data-look="neo"].section-edge-8{stroke:rgb(248, 212, 93);}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-8 text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-9 rect,#chatgpt-mermaid-_r_el_ .section-9 path,#chatgpt-mermaid-_r_el_ .section-9 circle,#chatgpt-mermaid-_r_el_ .section-9 polygon,#chatgpt-mermaid-_r_el_ .section-9 path{fill:rgb(184, 151, 244);}#chatgpt-mermaid-_r_el_ .section-9 text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-9 span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .node-icon-9{font-size:40px;color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-edge-9{stroke:rgb(184, 151, 244);}#chatgpt-mermaid-_r_el_ .edge-depth-9{stroke-width:-13;}#chatgpt-mermaid-_r_el_ .section-9 line{stroke:rgb(149.7173913044, 219.3043478259, 23.1956521739);stroke-width:3;}#chatgpt-mermaid-_r_el_ .disabled,#chatgpt-mermaid-_r_el_ .disabled circle,#chatgpt-mermaid-_r_el_ .disabled text{fill:lightgray;}#chatgpt-mermaid-_r_el_ .disabled text{fill:#efefef;}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-9 rect,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-9 path,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-9 circle,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-9 polygon{fill:rgb(184, 151, 244);stroke:rgb(184, 151, 244);stroke-width:1px;}#chatgpt-mermaid-_r_el_ [data-look="neo"].section-edge-9{stroke:rgb(184, 151, 244);}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-9 text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-10 rect,#chatgpt-mermaid-_r_el_ .section-10 path,#chatgpt-mermaid-_r_el_ .section-10 circle,#chatgpt-mermaid-_r_el_ .section-10 polygon,#chatgpt-mermaid-_r_el_ .section-10 path{fill:rgb(246, 142, 188);}#chatgpt-mermaid-_r_el_ .section-10 text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-10 span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .node-icon-10{font-size:40px;color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-edge-10{stroke:rgb(246, 142, 188);}#chatgpt-mermaid-_r_el_ .edge-depth-10{stroke-width:-16;}#chatgpt-mermaid-_r_el_ .section-10 line{stroke:rgb(18.405737705, 231.0942622953, 137.0204918033);stroke-width:3;}#chatgpt-mermaid-_r_el_ .disabled,#chatgpt-mermaid-_r_el_ .disabled circle,#chatgpt-mermaid-_r_el_ .disabled text{fill:lightgray;}#chatgpt-mermaid-_r_el_ .disabled text{fill:#efefef;}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-10 rect,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-10 path,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-10 circle,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-10 polygon{fill:rgb(246, 142, 188);stroke:rgb(246, 142, 188);stroke-width:1px;}#chatgpt-mermaid-_r_el_ [data-look="neo"].section-edge-10{stroke:rgb(246, 142, 188);}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-10 text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-root rect,#chatgpt-mermaid-_r_el_ .section-root path,#chatgpt-mermaid-_r_el_ .section-root circle,#chatgpt-mermaid-_r_el_ .section-root polygon{fill:rgb(83, 154, 248);}#chatgpt-mermaid-_r_el_ .section-root text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .section-root span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ .icon-container{height:100%;display:flex;justify-content:center;align-items:center;}#chatgpt-mermaid-_r_el_ .edge{fill:none;}#chatgpt-mermaid-_r_el_ .mindmap-node-label{dy:1em;alignment-baseline:middle;text-anchor:middle;dominant-baseline:middle;text-align:center;}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-root rect,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-root path,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-root circle,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-root polygon{fill:rgb(83, 154, 248);}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-root .text-inner-tspan{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section--1 rect,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section--1 path,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section--1 circle,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section--1 polygon{stroke:url(#chatgpt-mermaid-_r_el_-gradient);fill:rgb(222, 234, 251);}#chatgpt-mermaid-_r_el_ .section--1 line{stroke-width:0;}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-0 rect,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-0 path,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-0 circle,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-0 polygon{stroke:url(#chatgpt-mermaid-_r_el_-gradient);fill:rgb(222, 234, 251);}#chatgpt-mermaid-_r_el_ .section-0 line{stroke-width:0;}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-1 rect,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-1 path,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-1 circle,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-1 polygon{stroke:url(#chatgpt-mermaid-_r_el_-gradient);fill:rgb(222, 234, 251);}#chatgpt-mermaid-_r_el_ .section-1 line{stroke-width:0;}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-2 rect,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-2 path,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-2 circle,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-2 polygon{stroke:url(#chatgpt-mermaid-_r_el_-gradient);fill:rgb(222, 234, 251);}#chatgpt-mermaid-_r_el_ .section-2 line{stroke-width:0;}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-3 rect,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-3 path,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-3 circle,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-3 polygon{stroke:url(#chatgpt-mermaid-_r_el_-gradient);fill:rgb(222, 234, 251);}#chatgpt-mermaid-_r_el_ .section-3 line{stroke-width:0;}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-4 rect,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-4 path,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-4 circle,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-4 polygon{stroke:url(#chatgpt-mermaid-_r_el_-gradient);fill:rgb(222, 234, 251);}#chatgpt-mermaid-_r_el_ .section-4 line{stroke-width:0;}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-5 rect,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-5 path,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-5 circle,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-5 polygon{stroke:url(#chatgpt-mermaid-_r_el_-gradient);fill:rgb(222, 234, 251);}#chatgpt-mermaid-_r_el_ .section-5 line{stroke-width:0;}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-6 rect,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-6 path,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-6 circle,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-6 polygon{stroke:url(#chatgpt-mermaid-_r_el_-gradient);fill:rgb(222, 234, 251);}#chatgpt-mermaid-_r_el_ .section-6 line{stroke-width:0;}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-7 rect,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-7 path,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-7 circle,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-7 polygon{stroke:url(#chatgpt-mermaid-_r_el_-gradient);fill:rgb(222, 234, 251);}#chatgpt-mermaid-_r_el_ .section-7 line{stroke-width:0;}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-8 rect,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-8 path,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-8 circle,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-8 polygon{stroke:url(#chatgpt-mermaid-_r_el_-gradient);fill:rgb(222, 234, 251);}#chatgpt-mermaid-_r_el_ .section-8 line{stroke-width:0;}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-9 rect,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-9 path,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-9 circle,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-9 polygon{stroke:url(#chatgpt-mermaid-_r_el_-gradient);fill:rgb(222, 234, 251);}#chatgpt-mermaid-_r_el_ .section-9 line{stroke-width:0;}#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-10 rect,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-10 path,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-10 circle,#chatgpt-mermaid-_r_el_ [data-look="neo"].mindmap-node.section-10 polygon{stroke:url(#chatgpt-mermaid-_r_el_-gradient);fill:rgb(222, 234, 251);}#chatgpt-mermaid-_r_el_ .section-10 line{stroke-width:0;}#chatgpt-mermaid-_r_el_ .node .neo-node{stroke:rgb(83, 154, 248);}#chatgpt-mermaid-_r_el_ [data-look="neo"].node rect,#chatgpt-mermaid-_r_el_ [data-look="neo"].cluster rect,#chatgpt-mermaid-_r_el_ [data-look="neo"].node polygon{stroke:url(#chatgpt-mermaid-_r_el_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_el_ [data-look="neo"].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_el_ [data-look="neo"].node path{stroke:url(#chatgpt-mermaid-_r_el_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_el_ [data-look="neo"].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_el_ [data-look="neo"].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_el_ [data-look="neo"].node circle{stroke:url(#chatgpt-mermaid-_r_el_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_el_ [data-look="neo"].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_el_ [data-look="neo"].icon-shape .icon{fill:url(#chatgpt-mermaid-_r_el_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_el_ [data-look="neo"].icon-shape .icon-neo path{stroke:url(#chatgpt-mermaid-_r_el_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_el_ :root{--mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,"Segoe UI",Helvetica,"Apple Color Emoji",Arial,sans-serif,"Segoe UI Emoji","Segoe UI Symbol";}AI Driver Sleep DetectionHardwareESP32 or ESP32-S3IR eye sensorOptional cameraBuzzer and LEDFirmwareSensor readingEye-closure timerLocal alarmWi-Fi event uploadAI and Automationn8n webhookEvent validationAI summaryWorkflow error handlingNotificationsTelegram textText-to-speechTelegram audioCloudGoogle SheetsThingSpeakIoT webpageTestingSensor calibrationFalse alarmsNetwork outageSafety validation

14. Testing and validation plan

Complete these tests on a workbench before considering any vehicle installation.

Test

Expected result

Normal sensor signal

No drowsiness alarm

Short simulated closure

No alarm if below the configured threshold

Prolonged simulated closure

Local buzzer and LED activate

Wi-Fi disconnected

Local alarm continues

n8n unavailable

Local alarm continues; event is retried only if retry logic has been implemented

Google Sheets error

Other alert paths should remain operational in the final workflow

Telegram failure

Failure is recorded and retried according to workflow policy

Sensor unplugged or blocked

A fault is detected in the final validated implementation

Power cycle

System starts safely and reconnects to available services

Measure false alarms and missed detections across different users, lighting conditions, eyewear, head positions, and sensor placements. An IR blink sensor is a basic demonstration input; it cannot establish that a driver is alert or reliably distinguish every cause of prolonged eye closure.

Safety limitation: this is an educational prototype, not a certified driver-safety device. Do not rely on it to decide whether it is safe to drive, and do not test it while operating a vehicle.

15. Final project documentation structure

Use the following chapter structure for your college project report.

  1. Chapter 1 — Introduction: Driver fatigue, problem statement, motivation, and objectives.

  2. Chapter 2 — Literature Review: Existing drowsiness-detection techniques, IR sensors, computer vision, and IoT-based alert systems.

  3. Chapter 3 — System Requirements: Hardware, software, communication protocols, and cloud services.

  4. Chapter 4 — System Design: Block diagram, circuit schematic, flowchart, and system architecture.

  5. Chapter 5 — Hardware Implementation: ESP32 connections, sensor installation, alarm circuit, and power supply.

  6. Chapter 6 — Software Implementation: Arduino firmware, sensor timing logic, Wi-Fi, HTTP requests, and event handling.

  7. Chapter 7 — n8n Automation: Webhook, validation, Google Sheets, Telegram, TTS, and AI agent.

  8. Chapter 8 — Cloud Dashboard: ThingSpeak fields, webpage design, and event history.

  9. Chapter 9 — Testing and Results: Sensor calibration, response times, false alarms, network failures, and test records.

  10. Chapter 10 — Conclusion and Future Scope: Camera-based AI, improved eye-state estimation, event buffering, and more reliable driver monitoring.

16. Future improvements

  • Replace the basic IR input with camera-based eye-state detection and a validated model.

  • Add head-pose estimation and additional indicators to reduce false alarms.

  • Store events locally during Wi-Fi outages and upload them when connectivity returns.

  • Add authenticated device-to-server communication and encrypted credential storage.

  • Create a live dashboard with separate device-health and drowsiness-event indicators.

  • Add daily and weekly AI-generated reports from aggregated data.

  • Measure system performance using a documented test dataset.

Useful technical references:

17. Recommended implementation order

To make the project easier to complete and troubleshoot, build it in this order:

  1. Connect the ESP32, IR sensor, LED, and buzzer.
  2. Test the sensor's actual output and verify the local alarm.
  3. Configure the n8n webhook and verify that it receives a test event.
  4. Connect Google Sheets and confirm event records are stored.
  5. Configure Telegram text alerts, then add text-to-speech and audio delivery.
  6. Connect ThingSpeak and display the numerical monitoring data.
  7. Build the IoT webpage and add AI summaries last.
  8. Test network failures, sensor faults, duplicate alerts, and false positives.

The most important next step is to establish a reliable local sensor-and-alarm circuit before adding the cloud services. Once that works, the remaining features can be integrated and tested individually.

 

Project Summary

AI Sleep Detection & Driver Alert System Using ESP32, AI Agent, IoT, n8n and Telegram Voice Alerts

Project title: AI-Powered IoT-Based Driver Sleep Detection and Alert System Using ESP32, n8n Automation, Telegram Voice Notifications, Google Sheets and ThingSpeak Cloud Dashboard.

Abstract

The AI Sleep Detection and Driver Alert System is an IoT-based safety prototype designed to detect possible driver drowsiness and generate immediate warnings. The system uses an ESP32 microcontroller with an eye-blink sensor to monitor eye-closure duration. When prolonged eye closure is detected, the ESP32 activates a buzzer and warning LED to alert the driver locally.

Using built-in Wi-Fi, the ESP32 can transmit event data to an n8n automation workflow. The workflow records events in Google Sheets, sends Telegram notifications, and supports voice alerts through a text-to-speech service. ThingSpeak provides cloud-based data visualization, while an IoT webpage displays system status, event history, and monitoring information. An optional AI agent analyzes recorded events, identifies repeated warning patterns, and generates summaries.

The system is designed to keep local warnings independent of internet connectivity. Future enhancements include camera-based eye-state recognition, improved drowsiness estimation, sensor-fault detection, and reliable offline event storage.

Main objectives

  • Detect possible driver drowsiness using eye-closure monitoring.

  • Activate a local buzzer and LED when a configurable threshold is exceeded.

  • Send remote alerts through Telegram and optional voice notifications.

  • Store event history in Google Sheets.

  • Visualize monitoring data through ThingSpeak and an IoT webpage.

  • Use n8n to automate communication between the ESP32 and cloud services.

  • Apply AI to summarize event history and identify patterns.

Hardware and software requirements

Category

Components

Controller

ESP32 DevKit V1

Sensor

Digital IR eye-blink sensor

Alert devices

Active buzzer, LED and resistor

Optional AI hardware

ESP32-S3 camera board

Programming

Arduino IDE, ESP32 board package

Automation

n8n

Notifications

Telegram Bot API

Data storage

Google Sheets

Cloud visualization

ThingSpeak

AI and voice

AI Agent and text-to-speech service

Dashboard

IoT webpage

Working principle

#chatgpt-mermaid-_r_h1_{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,"Segoe UI",Helvetica,"Apple Color Emoji",Arial,sans-serif,"Segoe UI Emoji","Segoe UI Symbol";font-size:16px;fill:rgb(13, 13, 13);}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#chatgpt-mermaid-_r_h1_ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_h1_ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#chatgpt-mermaid-_r_h1_ .error-icon{fill:rgb(243, 243, 243);}#chatgpt-mermaid-_r_h1_ .error-text{fill:rgb(13, 13, 13);stroke:rgb(13, 13, 13);}#chatgpt-mermaid-_r_h1_ .edge-thickness-normal{stroke-width:1px;}#chatgpt-mermaid-_r_h1_ .edge-thickness-thick{stroke-width:3.5px;}#chatgpt-mermaid-_r_h1_ .edge-pattern-solid{stroke-dasharray:0;}#chatgpt-mermaid-_r_h1_ .edge-thickness-invisible{stroke-width:0;fill:none;}#chatgpt-mermaid-_r_h1_ .edge-pattern-dashed{stroke-dasharray:3;}#chatgpt-mermaid-_r_h1_ .edge-pattern-dotted{stroke-dasharray:2;}#chatgpt-mermaid-_r_h1_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_h1_ .marker.cross{stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_h1_ svg{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,"Segoe UI",Helvetica,"Apple Color Emoji",Arial,sans-serif,"Segoe UI Emoji","Segoe UI Symbol";font-size:16px;}#chatgpt-mermaid-_r_h1_ p{margin:0;}#chatgpt-mermaid-_r_h1_ .label{font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,"Segoe UI",Helvetica,"Apple Color Emoji",Arial,sans-serif,"Segoe UI Emoji","Segoe UI Symbol";color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_h1_ .cluster-label text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_h1_ .cluster-label span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_h1_ .cluster-label span p{background-color:transparent;}#chatgpt-mermaid-_r_h1_ .label text,#chatgpt-mermaid-_r_h1_ span{fill:rgb(13, 13, 13);color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_h1_ .node rect,#chatgpt-mermaid-_r_h1_ .node circle,#chatgpt-mermaid-_r_h1_ .node ellipse,#chatgpt-mermaid-_r_h1_ .node polygon,#chatgpt-mermaid-_r_h1_ .node path{fill:rgb(222, 234, 251);stroke:rgb(83, 154, 248);stroke-width:1px;}#chatgpt-mermaid-_r_h1_ .rough-node .label text,#chatgpt-mermaid-_r_h1_ .node .label text,#chatgpt-mermaid-_r_h1_ .image-shape .label,#chatgpt-mermaid-_r_h1_ .icon-shape .label{text-anchor:middle;}#chatgpt-mermaid-_r_h1_ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#chatgpt-mermaid-_r_h1_ .rough-node .label,#chatgpt-mermaid-_r_h1_ .node .label,#chatgpt-mermaid-_r_h1_ .image-shape .label,#chatgpt-mermaid-_r_h1_ .icon-shape .label{text-align:center;}#chatgpt-mermaid-_r_h1_ .node.clickable{cursor:pointer;}#chatgpt-mermaid-_r_h1_ .root .anchor path{fill:rgb(143, 143, 143)!important;stroke-width:0;stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_h1_ .arrowheadPath{fill:rgb(143, 143, 143);}#chatgpt-mermaid-_r_h1_ .edgePath .path{stroke:rgb(143, 143, 143);stroke-width:1px;}#chatgpt-mermaid-_r_h1_ .flowchart-link{stroke:rgb(143, 143, 143);fill:none;}#chatgpt-mermaid-_r_h1_ .edgeLabel{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_h1_ .edgeLabel p{background-color:rgb(252, 252, 252);}#chatgpt-mermaid-_r_h1_ .edgeLabel rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_h1_ .labelBkg{background-color:rgba(252, 252, 252, 0.5);}#chatgpt-mermaid-_r_h1_ .cluster rect{fill:rgb(243, 243, 243);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_h1_ .cluster text{fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_h1_ .cluster span{color:rgb(13, 13, 13);}#chatgpt-mermaid-_r_h1_ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,"Segoe UI",Helvetica,"Apple Color Emoji",Arial,sans-serif,"Segoe UI Emoji","Segoe UI Symbol";font-size:12px;background:rgb(243, 243, 243);border:1px solid rgba(0, 0, 0, 0.1);border-radius:2px;pointer-events:none;z-index:100;}#chatgpt-mermaid-_r_h1_ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:rgb(13, 13, 13);}#chatgpt-mermaid-_r_h1_ rect.text{fill:none;stroke-width:0;}#chatgpt-mermaid-_r_h1_ .icon-shape,#chatgpt-mermaid-_r_h1_ .image-shape{background-color:rgb(252, 252, 252);text-align:center;}#chatgpt-mermaid-_r_h1_ .icon-shape p,#chatgpt-mermaid-_r_h1_ .image-shape p{background-color:rgb(252, 252, 252);padding:2px;}#chatgpt-mermaid-_r_h1_ .icon-shape .label rect,#chatgpt-mermaid-_r_h1_ .image-shape .label rect{opacity:0.5;background-color:rgb(252, 252, 252);fill:rgb(252, 252, 252);}#chatgpt-mermaid-_r_h1_ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#chatgpt-mermaid-_r_h1_ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#chatgpt-mermaid-_r_h1_ .node .neo-node{stroke:rgb(83, 154, 248);}#chatgpt-mermaid-_r_h1_ [data-look="neo"].node rect,#chatgpt-mermaid-_r_h1_ [data-look="neo"].cluster rect,#chatgpt-mermaid-_r_h1_ [data-look="neo"].node polygon{stroke:url(#chatgpt-mermaid-_r_h1_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_h1_ [data-look="neo"].swimlane.cluster rect{filter:none;}#chatgpt-mermaid-_r_h1_ [data-look="neo"].node path{stroke:url(#chatgpt-mermaid-_r_h1_-gradient);stroke-width:1px;}#chatgpt-mermaid-_r_h1_ [data-look="neo"].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_h1_ [data-look="neo"].node .neo-line path{stroke:rgb(83, 154, 248);filter:none;}#chatgpt-mermaid-_r_h1_ [data-look="neo"].node circle{stroke:url(#chatgpt-mermaid-_r_h1_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_h1_ [data-look="neo"].node circle .state-start{fill:#000000;}#chatgpt-mermaid-_r_h1_ [data-look="neo"].icon-shape .icon{fill:url(#chatgpt-mermaid-_r_h1_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_h1_ [data-look="neo"].icon-shape .icon-neo path{stroke:url(#chatgpt-mermaid-_r_h1_-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#chatgpt-mermaid-_r_h1_ .node text{font-size:14px;font-weight:600;letter-spacing:normal;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_h1_ .edgeLabels text{font-size:13px;font-weight:600;letter-spacing:-0.08px;fill:rgb(0, 79, 153);}#chatgpt-mermaid-_r_h1_ .node tspan[font-weight="normal"],#chatgpt-mermaid-_r_h1_ .edgeLabels tspan[font-weight="normal"]{font-weight:600;}#chatgpt-mermaid-_r_h1_ .edgeLabel .label rect{opacity:1;rx:13px;ry:13px;fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-width:1px;}#chatgpt-mermaid-_r_h1_ .node rect,#chatgpt-mermaid-_r_h1_ .node circle,#chatgpt-mermaid-_r_h1_ .node ellipse,#chatgpt-mermaid-_r_h1_ .node polygon,#chatgpt-mermaid-_r_h1_ .node path{fill:rgb(229, 243, 255);stroke:rgba(0, 0, 0, 0.1);stroke-width:1px;}#chatgpt-mermaid-_r_h1_ .node rect{rx:16px;ry:16px;}#chatgpt-mermaid-_r_h1_ .node.mermaid-decision .label-container{fill:rgb(245, 250, 255);stroke:rgb(206, 219, 229);stroke-dasharray:2,2;}#chatgpt-mermaid-_r_h1_ .edgePaths .flowchart-link{stroke:rgb(143, 143, 143);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;}#chatgpt-mermaid-_r_h1_ .marker{fill:rgb(143, 143, 143);stroke:rgb(143, 143, 143);}#chatgpt-mermaid-_r_h1_ :root{--mermaid-font-family:-apple-system-body,ui-sans-serif,-apple-system,system-ui,"Segoe UI",Helvetica,"Apple Color Emoji",Arial,sans-serif,"Segoe UI Emoji","Segoe UI Symbol";}Eye-Blink SensorESP32 ControllerProlonged Eye Closure?Activate Buzzer and LEDSend Event via Wi-Fin8n AutomationGoogle SheetsTelegram Voice and Text AlertsThingSpeak DashboardAI Event SummaryIoT WebpageNoYes

Expected outcome

The prototype demonstrates how embedded electronics, IoT cloud services, automation, and AI-assisted analysis can work together to monitor possible driver drowsiness. It provides immediate local warnings and supports remote event tracking and reporting.

Safety note: This is an educational prototype, not a certified driver-safety device. An IR sensor and a simple eye-closure threshold cannot reliably determine whether a person is fit to drive. The local warning should work without cloud connectivity, and the system must be thoroughly tested before any real-world use.

Saturday, 10 October 2026

AI Renewable Hybrid Power Generation Monitoring System

AI Renewable Hybrid Power Generation Monitoring System

Full project report, hardware schematic, ESP32 firmware, n8n workflows, AI agent, IoT webpage, Telegram voice alerts, Google Sheets and ThingSpeak

This project is designed as a complete renewable-energy IoT monitoring and automation system using an ESP32 microcontroller, solar PV panel, wind turbine, electrical sensors, n8n automation, an AI agent, Telegram notifications, Google Sheets and ThingSpeak.

The goal is to monitor power generation, display live readings on a webpage, store historical measurements, detect abnormal operating conditions, and automatically send intelligent text and voice notifications to the operator.

The following documentation is structured as an engineering project report and implementation guide. It includes the system architecture, component list, electrical wiring, firmware, cloud configuration, workflow diagrams, AI prompt, dashboard design, testing, and safety requirements.

Fundamental Design of Small Scale Solar Wind Hybrid System
Problem esp32 "INA219 not connected" - Page 2 - Sensors - Arduino Forum
IIoT Solutions in Renewable Energy: 5 Ways to Sustainability

1. Project overview

Renewable energy generation

Solar PV and wind generation measurements, with optional battery and load monitoring.

ESP32 intelligent edge device

Sensor acquisition, power calculations, telemetry validation, Wi-Fi communication and fault reporting.

n8n automation and AI

Data routing, alert rules, AI-generated diagnostics, logging and notification workflows.

IoT cloud and notifications

Custom webpage, ThingSpeak charts, Google Sheets history, Telegram text and voice alerts.

1.1 Abstract

The AI Renewable Hybrid Power Generation Monitoring System is an IoT-based platform for observing the electrical performance of a hybrid renewable-energy installation. Solar panels and a wind turbine produce electrical energy, while suitable sensors measure voltage and current at selected electrical points. An ESP32 collects the measurements, computes instantaneous power, adds device information, and transmits the data to a cloud-connected automation system.

The n8n workflow validates the incoming telemetry, stores measurements in Google Sheets, updates ThingSpeak, and evaluates configurable alarm conditions. An AI agent analyzes validated readings and recent history to produce explanations and recommended diagnostic actions. Telegram delivers immediate text notifications and, when configured with a text-to-speech service, audio or voice-message alerts. A web dashboard displays the latest readings, generation trends, device connectivity, and event history.

The design combines conventional rule-based automation with AI-assisted interpretation. The AI agent supports diagnosis but does not replace electrical protection, battery-management systems, charge controllers, or deterministic safety controls.

1.2 Objectives

  • Monitor solar and wind generation separately.

  • Calculate voltage, current, instantaneous power and accumulated energy.

  • Monitor battery voltage, battery current, load power and state of charge when suitable sensors are installed.

  • Display readings on an IoT webpage.

  • Store historical data in Google Sheets and ThingSpeak.

  • Detect abnormal readings, low generation, low battery voltage and communication failures.

  • Use an AI agent to explain possible causes and recommend safe checks.

  • Send Telegram text alerts and generated audio notifications.

  • Provide a scalable foundation for maintenance analytics and intelligent energy management.

1.3 Applications

  • Solar-wind hybrid systems.

  • Renewable-energy laboratory projects.

  • Educational microgrid demonstrations.

  • Remote monitoring of small off-grid systems.

  • Energy-generation performance studies.

  • Battery and load monitoring prototypes.

2. System block diagram

Renewable power sources

Solar PV + wind turbine

Electrical power stage

Charge controllers, rectification where required, battery, load and protection

Voltage and current sensors

Independent measurements for solar, wind, battery and load branches as required

ESP32 controller

Read → validate → calculate → timestamp → transmit JSON over Wi-Fi

n8n cloud automation

Webhook → validation → rules → storage → AI agent → notification

ThingSpeak

Time-series visualization

Google Sheets

Telemetry and event history

IoT webpage

Live status and charts

Telegram

Text and voice alerts

2.1 Working principle

  1. Solar panels generate electricity from sunlight.

  2. A wind turbine generates electricity when wind conditions permit.

  3. Appropriate controllers regulate the energy supplied to the battery and load.

  4. Electrical sensors measure voltage and current at defined measurement points.

  5. The ESP32 calculates power and sends validated readings to an n8n webhook.

  6. n8n stores readings in Google Sheets and sends channel updates to ThingSpeak.

  7. Rule-based logic detects conditions requiring attention.

  8. The AI agent analyzes the event and produces a short diagnostic summary.

  9. Telegram sends the text alert and, optionally, a generated audio notification.

  10. The webpage displays the latest validated telemetry and historical trends.

The reference implementation below uses a webhook-first architecture: the ESP32 sends data to n8n, which routes the data to cloud storage, charts, and notification services.

3. Hardware requirements and bill of materials

The following components are suitable for a low-voltage educational prototype. Select actual ratings after deciding the solar panel, wind generator, battery and load.

GitHub - TronixLab/DOIT_ESP32_DevKit-v1_30P · GitHub

1. ESP32 DevKit V1

Main controller with Wi-Fi and I²C. Quantity: 1.

Adafruit INA219 High Side DC Spannungs Sensor Breakout, 26V ±3.2A Max

2. INA219 voltage/current sensor

Measures DC bus voltage, current and power. Quantity: 2 for independent solar and wind measurements, subject to sensor ratings.

5V 160mA solar panel (90 x 70mm) – SMARTQAT

3. Solar panel

Primary renewable source. Select voltage and power appropriate to the project.

2026 Dc Mini Wind Generator Wind Turbine 12cm Wind Turbine Led Diy Teaching Model Kit | Fruugo UK

4. Wind turbine and wind controller

Optional second source. Depending on the turbine, a rectifier, diversion controller and overspeed protection may be necessary.

How to Charge a Battery from Solar Panels    – Jackery United Kingdom

5. Battery and protection equipment

Compatible battery, charge controller, DC disconnects, fuses and correctly rated DC converters.

Other required items:

  • USB power supply and USB cable for ESP32.

  • Breadboard or screw terminals, jumper wires and suitable electrical connectors.

  • Optional battery monitor, load-current sensor and temperature sensor.

  • Computer with Arduino IDE and internet access.

  • n8n instance, Telegram bot, Google account and ThingSpeak account.

  • AI API access and a text-to-speech service for voice alerts.

3.1 Measurement-point selection

Parameter

Sensor location

Solar voltage and current

Solar output, at a defined DC measurement point

Wind voltage and current

Suitable DC output of the wind controller

Battery voltage and current

Battery monitor or battery-side measurement point

Load power

Load branch, if load monitoring is required

Battery temperature

Appropriate battery or enclosure sensor

A sensor reading is only meaningful when its electrical location is known. Solar power and wind power can be added to estimate total generation when the readings represent separate generation branches. Do not add battery charging power to those generation readings if it would count the same energy twice.

4. Electrical schematic and ESP32 pin connections

The diagram below shows the functional connection arrangement, rather than a construction-ready power circuit.

Solar panel

Protection → compatible solar charge controller

Solar measurement

INA219 #1 → solar DC voltage and current

Protected DC bus and battery

Battery-compatible charging system and protected load connection

Wind turbine branch

Wind-rated controller/rectifier as required → INA219 #2 at an appropriate DC point

ESP32 low-voltage I²C circuit

GPIO 21

SDA

GPIO 22

SCL

Connect both INA219 modules to the shared I²C bus with distinct addresses. Connect logic ground and a compatible sensor supply.

4.1 Wiring table

ESP32

INA219

3V3

VCC, if supported by the breakout

GND

GND

GPIO 21

SDA

GPIO 22

SCL

Configure the two INA219 modules at distinct I²C addresses, for example 0x40 and 0x41, using the address jumpers or pads provided by the particular boards.

Electrical safety: Do not connect solar panels, wind turbines, batteries, inverter outputs or mains voltage directly to ESP32 GPIO pins. Verify the sensor's common-mode voltage, current rating, shunt rating and board layout. Use correctly rated protection and isolation equipment. An INA219 breakout is not a general-purpose mains meter.

5. Software requirements and official resources

Software

Purpose

Arduino IDE and ESP32 Arduino core

Firmware development

Adafruit INA219 library

Electrical measurements

ArduinoJson

JSON serialization

n8n

Workflow automation

ThingSpeak

Time-series telemetry

Google Sheets

Historical data and event logs

Telegram Bot API

Text and audio notifications

AI model/API

Contextual diagnostics

Text-to-speech service

Speech generation

HTML, CSS and JavaScript

Custom dashboard

Official references:

6. Step-by-step implementation

Step 1 — Assemble and test the hardware

  1. Install the ESP32 board package in Arduino IDE.

  2. Install the Adafruit INA219 and ArduinoJson libraries.

  3. Wire the I²C bus using GPIO 21 for SDA and GPIO 22 for SCL.

  4. Configure the two sensor addresses.

  5. Power the ESP32 over USB.

  6. Test the sensors with a safe, low-voltage DC source.

  7. Compare sensor measurements with a suitable reference meter.

Step 2 — Configure ThingSpeak

  1. Create a ThingSpeak account.

  2. Create a channel named Hybrid Renewable Energy Monitor.

  3. Configure the following fields.

Field

Name

Unit

1

Solar voltage

V

2

Solar current

A

3

Solar power

W

4

Wind power

W

5

Battery voltage

V

6

Load power

W

7

Total generation

W

8

Battery state of charge

%

  1. Save the channel ID and write API key securely.

  2. Use the channel's charts to inspect historical readings.

This is an example channel schema. If battery or load sensors are not installed, leave those values unavailable instead of generating fictional measurements. Check the current account's update restrictions before choosing the telemetry interval.

Step 3 — Create Google Sheets

Create a spreadsheet named Renewable_Energy_Monitor.

Use a Telemetry worksheet with these column headings:

text
timestamp,device_id,solar_voltage_v,solar_current_a,
solar_power_w,wind_voltage_v,wind_current_a,wind_power_w,
battery_voltage_v,load_power_w,total_generation_w,alert_level

Create a second worksheet called Events:

text
timestamp,event_type,severity,measurements,
ai_summary,recommended_action,notification_status

Connect Google Sheets to n8n through its supported authentication mechanism. Use an append-row operation for each validated telemetry record and another append operation for alert events.

Step 4 — Create the Telegram bot

  1. Open Telegram and find the verified @BotFather account.

  2. Send /newbot and follow its instructions.

  3. Store the bot token in secure n8n credentials.

  4. Open the new bot and send it a message.

  5. Retrieve the chat ID using a Telegram update or n8n operation.

  6. Configure Telegram credentials in n8n.

  7. Test a simple text message.

Never publish your bot token or include it in a public GitHub repository.

Step 5 — Set up n8n

Deploy n8n on a supported hosted service or your own server. If the ESP32 must reach the service over the internet, configure a publicly accessible HTTPS webhook with authentication.

Create the following workflows:

  • Workflow A: Telemetry ingestion and validation.

  • Workflow B: Threshold checks and AI diagnostics.

  • Workflow C: Telegram text and voice notifications.

  • Workflow D: Scheduled summaries and maintenance reports.

A small prototype can combine these functions in a single workflow. Separating them makes maintenance and error handling easier as the system grows.

7. ESP32 firmware — sensor monitoring and n8n webhook

This firmware reads solar and wind measurements from two INA219 sensors, calculates power, and sends JSON telemetry to n8n every 30 seconds.

7.1 Arduino code

Before uploading, replace the Wi-Fi credentials and webhook URL. Install the Adafruit INA219 and ArduinoJson libraries from the Arduino IDE Library Manager.

cpp

#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <HTTPClient.h>
#include <Wire.h>
#include <Adafruit_INA219.h>
#include <ArduinoJson.h>
#include <math.h>

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

const char* WEBHOOK_URL =
  "https://YOUR_N8N_DOMAIN/webhook/renewable-telemetry";

const char* DEVICE_ID = "HYBRID-ESP32-01";

Adafruit_INA219 solarSensor(0x40);
Adafruit_INA219 windSensor(0x41);

const unsigned long SEND_INTERVAL_MS = 30000;
unsigned long lastSend = 0;

// -----------------------------------

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

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

  unsigned long start = millis();

  while (WiFi.status() != WL_CONNECTED &&
         millis() - start < 20000) {
    delay(500);
    Serial.print(".");
  }

  Serial.println();

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

  Serial.println("Wi-Fi connection failed");
  return false;
}

bool sendTelemetry(float solarV, float solarA,
                   float solarW, float windV,
                   float windA, float windW) {
  if (!connectWiFi()) return false;

  WiFiClientSecure client;

  // DEVELOPMENT ONLY: skips certificate verification.
  // Replace with CA certificate verification for deployment.
  client.setInsecure();

  HTTPClient http;
  http.setConnectTimeout(5000);
  http.setTimeout(8000);

  if (!http.begin(client, WEBHOOK_URL)) {
    Serial.println("HTTPS initialization failed");
    return false;
  }

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

  JsonDocument doc;
  doc["device_id"] = DEVICE_ID;
  doc["uptime_ms"] = millis();
  doc["solar_voltage_v"] = solarV;
  doc["solar_current_a"] = solarA;
  doc["solar_power_w"] = solarW;
  doc["wind_voltage_v"] = windV;
  doc["wind_current_a"] = windA;
  doc["wind_power_w"] = windW;
  doc["total_generation_w"] = solarW + windW;

  String payload;
  serializeJson(doc, payload);

  int status = http.POST(payload);

  Serial.printf("HTTP status: %d\n", status);

  if (status > 0) {
    Serial.println(http.getString());
  }

  http.end();

  return status >= 200 && status < 300;
}

void setup() {
  Serial.begin(115200);
  Wire.begin(21, 22);

  if (!solarSensor.begin()) {
    Serial.println("Solar INA219 not detected");
    while (true) delay(1000);
  }

  if (!windSensor.begin()) {
    Serial.println("Wind INA219 not detected");
    while (true) delay(1000);
  }

  connectWiFi();
  Serial.println("Hybrid monitor initialized");
}

void loop() {
  if (millis() - lastSend < SEND_INTERVAL_MS) {
    delay(20);
    return;
  }

  lastSend = millis();

  float solarV = solarSensor.getBusVoltage_V();
  float solarA = solarSensor.getCurrent_mA() / 1000.0f;
  float solarW = solarV * solarA;

  float windV = windSensor.getBusVoltage_V();
  float windA = windSensor.getCurrent_mA() / 1000.0f;
  float windW = windV * windA;

  bool valid =
    isfinite(solarV) && isfinite(solarA) &&
    isfinite(windV) && isfinite(windA) &&
    solarV >= 0 && windV >= 0;

  if (!valid) {
    Serial.println("Invalid reading; transmission skipped");
    return;
  }

  Serial.printf("Solar: %.2f V, %.3f A, %.2f W\n",
                solarV, solarA, solarW);
  Serial.printf("Wind: %.2f V, %.3f A, %.2f W\n",
                windV, windA, windW);

  bool ok = sendTelemetry(
    solarV, solarA, solarW,
    windV, windA, windW
  );

  if (!ok) {
    Serial.println("Telemetry failed");
  }
}

7.2 Expected JSON output

json
{
  "device_id": "HYBRID-ESP32-01",
  "uptime_ms": 120000,
  "solar_voltage_v": 18.0,
  "solar_current_a": 2.0,
  "solar_power_w": 36.0,
  "wind_voltage_v": 12.0,
  "wind_current_a": 1.0,
  "wind_power_w": 12.0,
  "total_generation_w": 48.0
}

These values are sample data, not actual measurements.

7.3 Important firmware limitations

  • The example uses setInsecure() only to simplify initial testing. Production firmware must validate the server certificate.

  • The example does not implement device authentication. Add a secret header or another suitable authentication mechanism.

  • The INA219 calibration must match the actual module and shunt.

  • The example calculates power using bus voltage multiplied by current. Validate current direction and the selected measurement point before relying on the result.

  • Battery state of charge and load power are not measured by this firmware.

  • The example stops if a sensor is missing. A production implementation should report sensor faults and recover without treating stale readings as current data.

8. n8n automation workflow — complete node design

mermaid

flowchart TD
    A["ESP32 HTTPS POST"] --> B["Webhook"]
    B --> C["Validate device and JSON"]
    C --> D{"Valid payload?"}
    D -->|No| E["Reject request / log error"]
    D -->|Yes| F["Normalize measurements"]
    F --> G["Google Sheets: append telemetry"]
    F --> H["HTTP Request: ThingSpeak"]
    F --> I["IF: threshold evaluation"]
    I -->|Normal| J["Return success"]
    I -->|Warning or fault| K["Build alert context"]
    K --> L["AI Agent"]
    L --> M["Telegram Send Message"]
    L --> N["Text-to-speech API"]
    N --> O["Telegram Send Audio"]
    M --> P["Google Sheets: append event"]
    O --> P

Node 1 — Webhook

Configure:

  • HTTP method: POST

  • Path: renewable-telemetry

  • Authentication: use the supported authentication options for your n8n deployment.

  • Response: return a success response after the request has been accepted and validated.

During testing, inspect the actual webhook output. Depending on the node settings, incoming data may be nested under body.

Node 2 — Edit Fields

Map these normalized values from the received JSON:

  • device_id

  • solar_voltage_v

  • solar_current_a

  • solar_power_w

  • wind_voltage_v

  • wind_current_a

  • wind_power_w

  • total_generation_w

Validate that all required fields are present, numeric and within the permitted ranges of the hardware. Reject malformed requests rather than forwarding them to the AI agent.

Node 3 — Google Sheets

  • Select the Renewable_Energy_Monitor spreadsheet.

  • Choose the Telemetry worksheet.

  • Select the append-row operation.

  • Map the device ID, timestamp, voltage, current, power and alert level to the matching columns.

Use a consistent timestamp format, preferably ISO 8601 with an explicit timezone.

Node 4 — HTTP Request for ThingSpeak

Configure the request:

  • Method: POST

  • URL: https://api.thingspeak.com/update

  • Body type: form URL encoded.

Map the parameters as follows:

Parameter

Value

api_key

ThingSpeak write API key

field1

Solar voltage

field2

Solar current

field3

Solar power

field4

Wind power

field7

Total generation

Add the remaining fields when their sensors are available. Check the response from ThingSpeak and log unsuccessful writes. Follow the update interval and account restrictions for your channel.

Node 5 — IF: threshold evaluation

Start with configurable rules:

  • Battery voltage is below a battery-specific warning limit.

  • Generation remains below the expected level for a sustained period.

  • The sensor reading is outside its permitted operating range.

  • Telemetry is missing beyond the expected interval.

  • Measured load demand exceeds available generation for a defined duration, if load monitoring is installed.

Use hysteresis, persistence and cooldown timers to prevent repeated alerts during normal fluctuations.

Node 6 — AI Agent

Pass the validated measurements and event context to the AI agent. The agent should return a concise summary, possible causes, recommended action and severity. Keep all alert-triggering and protection decisions in the deterministic rule engine.

Node 7 — Telegram notifications

Use the Telegram node to send the AI summary together with the original measured values. If the AI provider fails, send the rule-engine warning anyway.

9. AI agent prompt

The following prompt can be used in an n8n AI Agent or an equivalent model node.

text

You are an AI assistant for a renewable hybrid power monitoring system.

Analyze validated solar, wind, battery and load measurements
provided in the current event.

Return:
1. A concise system-status summary.
2. The exact threshold violation detected by the rule engine.
3. Possible causes, clearly identified as hypotheses.
4. Safe diagnostic actions.
5. Severity: INFO, WARNING, or CRITICAL.

Requirements:
- Use only supplied readings and historical data.
- Never invent missing measurements or battery state of charge.
- Do not claim a component is faulty without sufficient evidence.
- Never recommend bypassing fuses, protection systems, or grounding.
- Do not directly control electrical hardware.
- Do not override deterministic safety rules.
- Keep the response concise and suitable for Telegram.
- Return structured JSON with summary, possible_causes,
  recommended_action, and severity.

Example AI input

json
{
  "device_id": "HYBRID-ESP32-01",
  "solar_power_w": 18.4,
  "wind_power_w": 4.2,
  "battery_voltage_v": 11.7,
  "load_power_w": 35.0,
  "alert_level": "WARNING",
  "event": "battery_voltage_low"
}

Example AI output

json
{
  "summary": "Battery voltage is below the configured warning limit.",
  "possible_causes": [
    "Load demand exceeds available generation",
    "Battery is partially discharged",
    "Sensor or wiring readings require verification"
  ],
  "recommended_action": "Verify the voltage with a suitable meter and inspect the charging system.",
  "severity": "WARNING"
}

These readings are illustrative. The threshold must be configured for the battery chemistry and system design.

10. Telegram text and voice notifications

Telegram text alerts are sent directly by n8n. Voice alerts require a text-to-speech service that converts the alert into an audio file.

mermaid

flowchart TD
    A["Rule engine detects abnormal condition"] --> B["AI generates alert summary"]
    B --> C["Telegram Send Message"]
    B --> D["Text-to-speech API"]
    D --> E["Receive audio binary"]
    E --> F["Telegram Send Audio or Send Voice"]
    F --> G["Operator receives audio notification"]

10.1 Example Telegram alert

Hybrid Energy Monitor

⚠️ Battery voltage warning

Device: HYBRID-ESP32-01

Solar power: 18.4 W

Wind power: 4.2 W

Battery voltage: 11.7 V (example only)

Action: Verify the battery voltage and inspect the charging system. Check the battery manufacturer's limits before taking corrective action.

10.2 Configure the voice alert

  1. Choose a text-to-speech service that supports an API, or run a compatible service on your server.

  2. Send the AI-generated summary or a fixed warning template to the TTS endpoint.

  3. Request MP3 or a supported Telegram voice format.

  4. Configure the n8n HTTP Request node to retrieve the audio as binary data.

  5. Connect it to Telegram's Send Audio or Send Voice operation.

  6. Select the correct binary property and recipient chat ID.

  7. Test with a simulated warning.

Send Audio is appropriate for an audio file such as MP3. Send Voice is intended for Telegram voice messages and requires a supported format. The exact TTS node configuration depends on the provider you choose.

11. IoT webpage and cloud dashboard

You can use ThingSpeak charts for a quick implementation, or create a custom webpage for more control.

Windora Renewable Energy Dashboard by Ofspace UX/UI on Dribbble
From research to application: aimpera creates AI for intelligent energy management
Renewable Energy Monitoring & Control

11.1 Recommended webpage features

  • Solar power and wind power cards.

  • Total generation in watts.

  • Daily generated energy in Wh or kWh.

  • Battery voltage and state of charge when measured.

  • Load power when a load sensor is installed.

  • Historical power charts.

  • Latest alert and recommended action.

  • ESP32 online/offline status.

  • Last successful telemetry timestamp.

11.2 Simple HTML webpage

Save the following code as index.html. It is a standalone dashboard prototype that uses demonstration values. It does not connect to live sensor data until you integrate it with a backend.

HTML
Wrap linesCopy codePreview

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Hybrid Renewable Energy Monitor</title>
  <style>
    body {
      margin: 0;
      padding: 24px;
      background: #f1f5f9;
      color: #172033;
      font-family: Arial, sans-serif;
    }
    main { max-width: 960px; margin: auto; }
    .cards {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
      gap: 16px;
    }
    .card {
      background: white;
      padding: 20px;
      border-radius: 14px;
      box-shadow: 0 2px 8px #0001;
    }
    .label { color: #64748b; margin-bottom: 10px; }
    .value { font-size: 28px; font-weight: bold; }
    footer { margin-top: 20px; color: #64748b; }
  </style>
</head>
<body>
<main>
  <h1>Renewable Hybrid Energy Monitor</h1>
  <p>ESP32 · Solar PV · Wind generation</p>

  <section class="cards">
    <article class="card">
      <div class="label">Solar power</div>
      <div class="value" id="solar">-- W</div>
    </article>
    <article class="card">
      <div class="label">Wind power</div>
      <div class="value" id="wind">-- W</div>
    </article>
    <article class="card">
      <div class="label">Total generation</div>
      <div class="value" id="total">-- W</div>
    </article>
    <article class="card">
      <div class="label">Connection status</div>
      <div class="value" id="status">Demo</div>
    </article>
  </section>

  <footer id="updated">
    Demo data only — not live electrical measurements.
  </footer>
</main>

<script>
  // Demonstration values only.
  // Replace these with data from an authenticated backend API.
  const telemetry = {
    solar_power_w: 18.4,
    wind_power_w: 4.2
  };

  document.getElementById("solar").textContent =
    telemetry.solar_power_w.toFixed(1) + " W";

  document.getElementById("wind").textContent =
    telemetry.wind_power_w.toFixed(1) + " W";

  document.getElementById("total").textContent =
    (telemetry.solar_power_w + telemetry.wind_power_w)
      .toFixed(1) + " W";

  document.getElementById("updated").textContent =
    "DEMO DATA — connect a live telemetry API for real measurements.";
</script>
</body>
</html>

11.3 Connecting real telemetry

For production, expose an authenticated backend endpoint such as /api/latest. The backend should retrieve the latest validated telemetry and return JSON. The webpage can periodically request that endpoint and update its cards and charts.

Do not place ThingSpeak write keys, Google credentials, Telegram tokens or AI API keys in browser JavaScript. The webpage should only access data through a suitably secured API.

12. Power calculations and energy analysis

12.1 Instantaneous power

For a DC source:

P=V×IP=V\times I

Where PP is watts, VV is volts, and II is amperes.

Example:

Psolar=18×2=36 WP_{\text{solar}}=18\times2=36\text{ W}

12.2 Total generation

If solar and wind power are measured independently at compatible points:

Ptotal=Psolar+PwindP_{\text{total}}=P_{\text{solar}}+P_{\text{wind}}

For 36 W solar and 12 W wind, the combined generation is 48 W.

12.3 Generated energy

For a series of measurements taken at known time intervals:

EWh≈∑iPiΔti3600E_{\text{Wh}}\approx \sum_i P_i\frac{\Delta t_i}{3600}

Here, Δti\Delta t_i is the elapsed time in seconds for interval ii.

For example, a 48 W output sustained for 30 minutes produces approximately 24 Wh.

12.4 Energy balance

When load and battery measurements are available:

Pnet=Pgeneration−PloadP_{\text{net}}=P_{\text{generation}}-P_{\text{load}}

This is a simplified system-level calculation. Actual battery charging and discharging also depend on converter losses, battery current, controller behavior and other loads.

Voltage alone should not be treated as an accurate universal measurement of battery state of charge.

13. Google Sheets data analysis

Keep raw telemetry separate from calculated summaries and events.

Worksheet

Contents

Telemetry

Timestamped sensor readings and device ID

Daily_Summary

Daily energy generation, averages, maximum output and event counts

Events

Alert type, severity, measurements, AI summary and notification status

Example spreadsheet formulas, assuming solar power is in column E and wind power is in column H:

  • Total generation in watts: =E2+H2

  • Energy in Wh for a 30-second interval: =(E2+H2)*30/3600

Use actual elapsed time in production. If the ESP32 loses connectivity, do not assume that every measurement interval is exactly 30 seconds. Record missing readings and handle time gaps explicitly.

14. Testing and troubleshooting

14.1 End-to-end testing sequence

1

Hardware

Both INA219 sensors are detected and agree with suitable reference measurements.

2

ESP32

Wi-Fi connects, telemetry is sent, and communication failures are reported.

3

n8n

Webhook validates incoming JSON and rejects malformed requests.

4

ThingSpeak

Correct channel fields update and charts show expected values.

5

Google Sheets

Telemetry and event rows are stored in the correct worksheets.

6

AI agent

The generated summary uses only supplied measurements and does not invent missing values.

7

Telegram text

The intended recipient receives the correct warning.

8

Telegram voice

The TTS response is valid audio and Telegram delivers it.

9

Dashboard

The latest data is displayed, and stale readings are identified.

10

Recovery and safety

Network and AI failures do not disable local electrical protection.

14.2 Common problems

Problem

Likely cause or check

INA219 not detected

Check wiring and I²C addresses with a scanner.

Negative current

Verify current direction and shunt orientation.

HTTP authentication error

Check webhook authentication and endpoint configuration.

ThingSpeak not updating

Check write key, field mapping and rate limits.

Google Sheets failure

Verify account authorization, spreadsheet and worksheet name.

Telegram message failure

Verify bot token, chat ID and recipient permissions.

Voice notification contains no audio

Check the TTS response type and n8n binary property.

Too many alerts

Add hysteresis, persistence and cooldown logic.

AI diagnosis is unreliable

Validate measurements and constrain the prompt.

Dashboard shows old values

Check last-seen time and network connectivity.

15. Safety and security requirements

  • Use HTTPS certificate validation for production communication.

  • Authenticate the ESP32 webhook and validate every payload.

  • Store credentials securely rather than in public source code.

  • Apply sensible retry limits, rate limits and alert cooldowns.

  • Use a local buffer if telemetry must survive internet outages.

  • Distinguish missing or stale telemetry from a genuine electrical fault.

  • Keep charge controllers, battery-management systems, fuses and hardware interlocks independent of cloud AI.

  • Select the battery-specific warning and shutdown limits using the manufacturer's specifications.

  • Design wind-turbine protection for overspeed, electrical faults and the applicable controller requirements.

The system should remain a monitoring and advisory platform unless a separate, professionally designed control and protection system is implemented.

16. Expected project results

After the hardware and software are configured and tested, the system should demonstrate the following functions.

Function

Expected result

Renewable monitoring

Separate solar and wind measurements

ESP32 telemetry

JSON data transmitted over Wi-Fi

Cloud visualization

ThingSpeak charts and webpage dashboard

Data logging

Timestamped Google Sheets records

Fault detection

Configurable rule-based warnings

AI diagnostics

Contextual explanations and recommended checks

Telegram alerts

Automated text messages

Voice notifications

Generated audio delivered through Telegram

Historical analysis

Daily energy estimates and event records

17. Suggested project report structure

For a final-year engineering project, use this chapter arrangement:

  1. Chapter 1 — Introduction: Background, problem statement, objectives, scope and applications.

  2. Chapter 2 — Literature Review: Renewable hybrid generation, ESP32 IoT monitoring, cloud platforms and AI-assisted diagnostics.

  3. Chapter 3 — System Design: Block diagram, architecture, circuit schematic and component selection.

  4. Chapter 4 — Hardware Implementation: Sensor wiring, measurement points, power electronics and safety.

  5. Chapter 5 — Software Implementation: ESP32 firmware, n8n workflow, AI agent, Telegram, Google Sheets and ThingSpeak.

  6. Chapter 6 — Web Dashboard: Interface design, live data integration, charts and event history.

  7. Chapter 7 — Testing and Results: Sensor calibration, telemetry tests, alert tests, screenshots and measured results.

  8. Chapter 8 — Conclusion and Future Scope: Predictive maintenance, energy forecasting, anomaly detection and scalable multi-device monitoring.

Include actual experimental readings, screenshots and measured results when available. Do not present simulated values as experimental results.

18. Final system summary

The proposed project combines five main layers:

  • Energy layer: Solar PV, wind generation, battery and electrical load.

  • Embedded layer: ESP32 and electrical sensors.

  • IoT layer: Wi-Fi, webhook communication and ThingSpeak.

  • Automation layer: n8n, Google Sheets, AI analysis and Telegram notifications.

  • User interface layer: Custom web dashboard, historical charts and voice alerts.

The central advantage is that the ESP32 continuously gathers the measurements, n8n coordinates the cloud services, and the AI agent explains events in a human-readable way. The result is a renewable-energy monitoring system that is easier to observe, troubleshoot and extend than a standalone sensor display.

One important implementation detail: the code and diagrams above are a starter reference design, not yet a fully hardware-matched deployment. A final schematic and production firmware must reflect the actual sensor modules, electrical ratings, battery chemistry, and selected TTS provider.

 

Project Summary: AI Renewable Hybrid Power Generation Monitoring System

The project is an IoT-based monitoring and automation system that uses an ESP32, solar panel, wind turbine, n8n automation, an AI agent, Telegram voice alerts, Google Sheets, ThingSpeak, and a web dashboard to monitor renewable-energy generation.

Main components

  • ESP32: Reads sensor measurements and transmits data over Wi-Fi.

  • INA219 sensors: Measure DC voltage and current for solar and wind branches.

  • n8n: Automates data processing, cloud logging, alert rules, and notifications.

  • AI Agent: Analyzes validated measurements and recommends diagnostic actions.

  • Telegram: Sends automatic text messages and generated voice alerts.

  • Google Sheets: Stores historical measurements and alert records.

  • ThingSpeak: Displays time-series measurements and generation trends.

  • IoT webpage: Shows power generation, device status, charts, and alerts.

System workflow

mermaid

flowchart TD
    A["Solar Panel + Wind Turbine"] --> B["Voltage / Current Sensors"]
    B --> C["ESP32"]
    C --> D["n8n Webhook"]
    D --> E["Validate and Calculate"]
    E --> F["Google Sheets"]
    E --> G["ThingSpeak"]
    E --> H["Rule-Based Alert Detection"]
    H --> I["AI Agent"]
    I --> J["Telegram Text Alert"]
    I --> K["Text-to-Speech"]
    K --> L["Telegram Voice Alert"]
    G --> M["IoT Web Dashboard"]
    F --> M

Main implementation steps

  1. Assemble the ESP32 and sensors.

  2. Connect the sensors using the I²C interface.

  3. Upload the Arduino firmware.

  4. Configure ThingSpeak and Google Sheets.

  5. Create a Telegram bot.

  6. Configure the n8n webhook and automation workflows.

  7. Integrate the AI agent and text-to-speech service.

  8. Build the webpage and connect it to authenticated telemetry.

  9. Test measurements, notifications, cloud storage, and recovery.

Expected results

  • Real-time solar and wind power monitoring.

  • Automatic data logging and visualization.

  • Rule-based fault and low-generation alerts.

  • AI-generated diagnostic recommendations.

  • Telegram text and voice notifications.

  • Historical generation analysis and energy estimates.

Important: The reference firmware and webpage require configuration before deployment. Battery monitoring requires appropriate additional sensors, and electrical protection must remain independent of AI and cloud connectivity.