Body Dehydration Detector Using GSR Sensor

Published Nov 30, 2025
 25 hours to build
 Intermediate

This project is a wearable GSR-based stress monitoring system that tracks galvanic skin response, temperature, and heart rate in real time. The glove-mounted sensors send live readings to a wrist-mounted display and simultaneously push notifications to a mobile app for continuous emotional and physiological monitoring. It provides a simple and portable way to observe stress patterns during daily activities.

display image

Components Used

TP4056 Battery charging Module
Power Management IC Development Tools Lithium Battery Charger
1
MAX30102 Heart Rate Sensor
It's a heart rate SpO2 I2C based sensor to measure the heart rate level
1
BME 280
Small I2C based temperature and Atmospheric Pressure Sensor used in this project to measure the temperature of body
1
GSR Sensor (Galvanic Skin Response)
GSR sensor give information about body skin conductivity.
1
0.96 inch OLED
A compact display to show the data on the device
1
ESP32 C6
The brain of the device is ESP32 C6 that communicates with telegram bot via internet.
1
3.7V lipo battry
To power the full device a 3.7V li-op battery is used
1
Description

                                 Wearable GSR-Based Stress Monitoring System

Stress is one of the most common but least measured conditions in everyday life. Most people only recognize stress after visible symptoms appear—racing heart, sweating, trembling, or emotional discomfort. There is no simple, affordable, and wearable solution that continuously monitors real-time stress signals such as skin conductance, temperature changes, and physiological responses while a person goes about their normal activities.
A device that can quietly and accurately track these signals would help individuals monitor their emotional state, identify stress triggers, and take action before stress escalates.

1. Abstract

This project presents a wearable stress-monitoring system that uses Galvanic Skin Response (GSR), body temperature, and heart rate to evaluate the user’s physiological state in real time. The system combines finger-mounted GSR electrodes with a wrist-worn ESP32 module that collects data, displays it on an OLED screen, and sends readings directly to a smartphone. The design is simple, portable, and built using low-cost components, making real-time stress tracking accessible to everyday users. The project demonstrates the potential of wearable sensing for emotional health monitoring and early stress detection.

3. Aim

To design and develop a wearable device capable of continuously monitoring stress-related physiological parameters and transmitting them to a smartphone for real-time awareness and analysis.

4. Methodology

4.1 Sensor Selection

  • GSR Sensor → A GSR (Galvanic Skin Response) sensor measures the electrical conductivity of the skin, which changes based on a person’s emotional or physiological state. When someone feels stressed, anxious, or excited, their sweat glands become more active, even if it’s not visible on the skin. This increases moisture and reduces skin resistance, allowing the GSR sensor to detect subtle changes in conductance. Because of this direct link between sweat gland activity and emotional arousal, GSR sensors are widely used in stress monitoring, biofeedback, lie detection, and human-computer interaction applications.

  • MAX30102 / Heart Rate Sensor →The MAX30102 is an integrated optical sensor that measures heart rate and blood oxygen levels using a combination of red and infrared LEDs. It works by shining light into the skin and detecting the amount reflected back, allowing it to track tiny changes in blood volume with each heartbeat. The sensor includes built-in photodetectors, signal processing, and ambient light cancellation, making it highly accurate even in varying lighting conditions. Its low power consumption, compact size, and I²C interface make it ideal for wearable devices, health-monitoring gadgets, and fitness trackers.

  • BME280 → The BME280 is a compact environmental sensor capable of measuring temperature, humidity, and atmospheric pressure with high accuracy. Designed by Bosch, it uses advanced digital sensing technology and communicates through I²C making it easy to integrate into microcontroller projects. Its temperature readings are stable and precise, making it suitable for health monitoring, weather stations, indoor air quality systems, and wearable applications. 

     

My Digi Key List:

 https://www.digikey.in/en/mylists/list/HSZQ5IVWOY 

4.2 Hardware Design

                                                  Circuit Diagram 

   1. ESP32-C6 Development Board (Central Brain)

  • The ESP32-C6 acts as the main controller. It reads data from all sensors, displays values on the OLED screen, and sends them wirelessly to your phone telegram.
  • 2. OLED Display (I²C Communication)
  • Pins: GND, VCC, SCL, SDA
    Connected to ESP32:
  • GND → GND
  • VCC → 3.3V
  • SCL → GPIO10 (I²C Clock)
  • SDA → GPIO9 (I²C Data)
  • Purpose:
    Displays GSR value, heart rate, and temperature in real time on the wrist module.

    2. MAX30102 Heart Rate Sensor (I²C)

  • Pins: VIN, GND, SCL, SDA
    Connected to ESP32:
  • VIN → 3.3V
  • GND → GND
  • SCL → GPIO10
  • SDA → GPIO9
  • Purpose:
    Measures heart rate and blood oxygen using red/IR LEDs.
    Communicates using the same I²C bus shared with OLED and BME280.

     3. BME280 Temperature / Humidity / Pressure Sensor (I²C)

  • Pins: VIN, GND, SCL, SDA
    Connected to ESP32:
  • VIN → 3.3V
  • GND → GND
  • SCL → GPIO10
  • SDA → GPIO9
  • Purpose:
    Measures body-surface temperature (used as an additional stress indicator).
    Also uses the same shared I²C bus.

    4. GSR Sensor (Galvanic Skin Response – Analog Input)

  • Pins: VCC, GND, SIG
    Connected to ESP32:
  • VCC → 3.3V
  • GND → GND
  • SIG → GPIO4 (analog input pin)
  • Purpose:
    Reads changes in skin resistance from finger electrodes.
    These variations indicate stress or emotional arousal.

5. Code

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <WiFiS3.h>
#include <WiFiSSLClient.h>
#include <UniversalTelegramBot.h>
#include "MAX30105.h"
#include "heartRate.h"
#include <Adafruit_GFX.h>        // OLED Library
#include <Adafruit_SSD1306.h>    // OLED Library

 
// GSR reading and percentage
int GSR;
int GSR_percentage;

 
// WiFi credentials
#define WIFI_SSID " ----------------"//Put you details
#define WIFI_PASSWORD "--------"//Put your details 

 
// Telegram bot token
#define BOT_API_TOKEN "-------"//Put your details 

 
// BME280 sensor configuration
Adafruit_BME280 bme;  // I2C

 
// MAX30105 sensor configuration
MAX30105 particleSensor;

 
// OLED display configuration
#define SCREEN_WIDTH 128         // OLED display width, in pixels
#define SCREEN_HEIGHT 64         // OLED display height, in pixels
#define OLED_RESET    -1         // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); //Declaring the display name (display)

 
const byte RATE_SIZE = 4; // Increase for more averaging
byte rates[RATE_SIZE]; // Array of heart rates
byte rateSpot = 0;
long lastBeat = 0; // Time of the last beat
float beatsPerMinute;
int beatAvg;
String chat_id = "";             // Chat ID for Telegram
int message_id = -1;             // Message ID for Telegram
unsigned long last_call = 0;     // Last call time for checking messages
const unsigned long interval = 1000; // Interval between message checks

 
// Object for secure WiFi client management
WiFiSSLClient securedClient;

 
// Object for managing the Telegram bot
UniversalTelegramBot bot(BOT_API_TOKEN, securedClient);

 
// Function to handle incoming messages from Telegram
void handleMessages(int num_new_messages) {
  for (int i = 0; i < num_new_messages; i++) {
    message_id = bot.messages[i].message_id;
    chat_id = bot.messages[i].chat_id;
    String text = bot.messages[i].text;

 
    // Command handling
    if (text == "/GSR") {
      // Send the GSR value and mapped percentage to the chat
      bot.sendMessage(chat_id, "Mapped GSR: " + String(GSR_percentage) + "%", "Markdown");
    } else if (text == "/TEMP") {
      float temperature = bme.readTemperature(); // Read temperature
      bot.sendMessage(chat_id, "Temperature: " + String(temperature, 2) + " °C", "Markdown");
      Serial.print("Temperature: ");
      Serial.print(temperature, 2);
      Serial.println(" °C");
    } else if (text == "/BPM") {
      bot.sendMessage(chat_id, "Average BPM: " + String(beatAvg), "Markdown");
    } else if (text == "/start") {
      bot.sendMessage(chat_id, "Use /GSR Value to get the GSR value, /TEMP to get the temperature, and /BPM to get the average heart rate.", "Markdown");
    }
  }
}

 
// Function to connect to WiFi network
void connectToWiFi() {
  Serial.print("Connecting to WiFi network ");
  Serial.println(WIFI_SSID);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  
  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting...");
  }
  
  Serial.print("WiFi connected. IP Address: ");
  Serial.println(WiFi.localIP());
}

 
// Initialization function
void setup() {
  Serial.begin(115200);            // Start serial communication
  pinMode(D10, INPUT);              // Set GSR pin as input
  randomSeed(analogRead(A1));      // Use an unconnected pin (A1) for better random seed initialization

 
  connectToWiFi();                // Connect to WiFi
  
  // Initialize BME280 sensor
  if (!bme.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);  // Stop execution if sensor is not found
  }

 
  // Initialize MAX30105 sensor
  if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) { // Use default I2C port, 400kHz speed
    Serial.println("MAX30105 was not found. Please check wiring/power.");
    while (1);  // Stop execution if sensor is not found
  }

 
  Serial.println("Place your index finger on the sensor with steady pressure.");
  particleSensor.setup();         // Configure sensor with default settings
  particleSensor.setPulseAmplitudeRed(0x0A);  // Turn Red LED to low to indicate sensor is running
  particleSensor.setPulseAmplitudeGreen(0);    // Turn off Green LED

 
  bot.sendMessage(chat_id, "BOT Started", "Markdown"); // Notify that the bot has started

 
  // Initialize the OLED display
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {  // Check the display initialization
    Serial.println(F("SSD1306 allocation failed"));
    while (1);
  }

 
  display.clearDisplay();  // Clear the display
  display.setTextColor(SSD1306_WHITE);  // Set text color to white
  display.setTextSize(2); // Set larger text size
  display.display();  // Display initial settings
  delay(2000);  // Wait for 2 seconds to let the user see "Initializing" message
}

 
// Main loop
void loop() {
  GSR = analogRead(A0);  // Read the GSR sensor value (0-1023 range)

 
  // Map the GSR value from 700-300 to 0-100%
  GSR_percentage = map(GSR, 300, 700, 0, 100);
  if (GSR_percentage < 0) GSR_percentage = 0; // Ensure percentage does not go below 0
  if (GSR_percentage > 100) GSR_percentage = 100; // Ensure percentage does not go above 100

 
  // Check for new messages from Telegram
  if (millis() - last_call > interval) {
    int num_new_messages = bot.getUpdates(bot.last_message_received + 1);
    while (num_new_messages) {
      handleMessages(num_new_messages);  // Handle incoming messages
      num_new_messages = bot.getUpdates(bot.last_message_received + 1);
    }
    last_call = millis(); // Update the last call time
  }

 
  // Update the OLED display with sensor data
  display.clearDisplay();
  
  // Display GSR data
  display.setCursor(0, 0);  // Set the cursor to top-left corner
  display.print("GSR: ");
  display.print(GSR_percentage);
  display.print("%");

 
  // Display temperature data
  float temperature = bme.readTemperature();
  display.setCursor(0, 24);  // Set cursor for next line
  display.print("Temp: ");
  display.print(int(temperature));
  display.print("C");

 
  // Check heart rate data
  long irValue = particleSensor.getIR();
  if (irValue > 50000) {
    if (checkForBeat(irValue) == true) {
      long delta = millis() - lastBeat;
      lastBeat = millis();
      beatsPerMinute = 60 / (delta / 1000.0);

 
      if (beatsPerMinute < 255 && beatsPerMinute > 20) {
        rates[rateSpot++] = (byte)beatsPerMinute; // Store reading in the array
        rateSpot %= RATE_SIZE; // Wrap variable

 
        // Take average of readings
        beatAvg = 0;
        for (byte x = 0; x < RATE_SIZE; x++)
          beatAvg += rates[x];
        beatAvg /= RATE_SIZE;
      }

 
      // Display the heart rate (BPM) on OLED
      display.setCursor(0, 48);  // Set cursor for heart rate
      display.print("BPM: ");
      display.print(beatAvg);
    }
  }

 
  // Check if all conditions are met: GSR > 400, Temp > 39°C, BPM > 90
  if (GSR_percentage > 40 && temperature > 39.0 && beatAvg > 90) {
    bot.sendMessage(chat_id, "Try to relax, you are stressed!", "Markdown");
  }

 
  // Show the display contents
  display.display();
  
  // Print to serial for debugging
  Serial.print("GSR: ");
  Serial.print(GSR);
  Serial.print(" | Mapped GSR: ");
  Serial.print(GSR_percentage);
  Serial.print(" | Temp: ");
  Serial.print(temperature);
  Serial.print(" | BPM: ");
  Serial.println(beatAvg);
}

This code ties together all the “brains” of the wearable stress-monitoring system. It connects the ESP32 to three sensors—GSR on an analog pin, a BME280 for temperature over I²C, and a MAX3010x heart-rate sensor—then displays their values on a 128×64 OLED screen and also exposes them through a Telegram bot. After joining the Wi-Fi network, the sketch initializes all sensors and the display, then continuously reads the GSR value, maps it to a 0–100% stress scale, measures body temperature from the BME280, and calculates average BPM from the IR signal of the MAX3010x. Users can send /GSR, /TEMP, or /BPM commands in Telegram to get live readings, while the OLED shows GSR%, temperature, and BPM locally on the wrist. Finally, a simple rule checks if all three indicators cross defined thresholds (high GSR%, high temperature, high BPM); if so, the bot automatically sends a message saying “Try to relax, you are stressed!”, turning the code into a real-time stress alert system.



6. Conclusion

This project successfully demonstrates a wearable, affordable, and practical system for stress monitoring using physiological signals. By combining GSR, temperature, and heart rate into a lightweight glove-and-wrist module, the system provides continuous visibility into the user’s emotional state. Such devices can support wellness, biofeedback training, mental health applications, and early detection of stress-related conditions.

7.Final Demo YouTube Video

Codes

Downloads

GSR Circuit Diagram Download
Comments
Ad