<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: DIY Electronics</title>
    <description>The latest articles on DEV Community by DIY Electronics (@diy_electronics_1a54d645a).</description>
    <link>https://dev.to/diy_electronics_1a54d645a</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4003420%2F57fab897-a0b2-44c4-9a40-c0f2bd7be17e.jpg</url>
      <title>DEV Community: DIY Electronics</title>
      <link>https://dev.to/diy_electronics_1a54d645a</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/diy_electronics_1a54d645a"/>
    <language>en</language>
    <item>
      <title>How to Build an ESP32 Stress Detector Using a MAX30100 Sensor</title>
      <dc:creator>DIY Electronics</dc:creator>
      <pubDate>Mon, 06 Jul 2026 06:13:25 +0000</pubDate>
      <link>https://dev.to/diy_electronics_1a54d645a/how-to-build-an-esp32-stress-detector-using-a-max30100-sensor-1b7</link>
      <guid>https://dev.to/diy_electronics_1a54d645a/how-to-build-an-esp32-stress-detector-using-a-max30100-sensor-1b7</guid>
      <description>&lt;p&gt;Combine an ESP32 30 Pin CP2102 Development Board and a MAX30100 Heart Rate Oxygen Pulse Sensor to build a real-time biometric stress detector - no specialized medical hardware required. &lt;br&gt;
The MAX30100 continuously measures heart rate and Heart Rate Variability (HRV), while the ESP32's built-in capacitive touch pins serve as a Galvanic Skin Response (GSR) sensor, detecting subtle changes in skin conductance caused by stress. Together, these three physiological signals - heart rate, HRV, and skin conductance - are processed and combined into a live Stress Index Score, streamed directly to your PC over USB Serial.&lt;/p&gt;

&lt;p&gt;This project is a practical deep-dive into I2C sensor interfacing, capacitive touch sensing, signal smoothing algorithms, and multi-parameter biometric scoring on the ESP32 platform.&lt;/p&gt;
&lt;h2&gt;
  
  
  Components Required
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://quartzcomponents.com/products/esp32-30-pin-development-board-with-wi-fi-and-bluetooth" rel="noopener noreferrer"&gt;ESP32 30 Pin CP2102 Development Board
&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://quartzcomponents.com/products/max30102-heart-rate-oxygen-pulse-sensor" rel="noopener noreferrer"&gt;MAX30100 Heart Rate Oxygen Pulse Sensor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://quartzcomponents.com/products/push-button-2-pin-tactile-micro-switch" rel="noopener noreferrer"&gt;Push Button
&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://quartzcomponents.com/collections/all/products/jumper-wire-combo-m-to-m-m-to-f-f-to-f" rel="noopener noreferrer"&gt;Connecting wires (Jumper wires)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://quartzcomponents.com/collections/all/products/small-breadboard-mini-solderless-board" rel="noopener noreferrer"&gt;Breadboard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://quartzcomponents.com/products/raspberry-pi-cable-for-charging" rel="noopener noreferrer"&gt;Micro-USB Cable&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Laptop or PC (for Serial Monitor / Serial Plotter)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  How It Works ?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe7eru2l1efvhz0b44qkr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe7eru2l1efvhz0b44qkr.png" alt=" " width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Stress triggers involuntary physiological changes in the body — the same responses that polygraph machines have measured for decades. This project captures three of those signals simultaneously and combines them into a single real-time Stress Index Score.&lt;/p&gt;

&lt;p&gt;All three signals are measured against a personal baseline captured while the subject is at rest. The composite Stress Index Score (0–100) produces one of three verdicts: Relaxed (below 25), Mild Stress (25–55), or High Stress Detected (above 55).&lt;/p&gt;

&lt;p&gt;Finger Placement&lt;br&gt;
All three signals are measured against a personal baseline captured while the subject is at rest. The composite Stress Index Score (0–100) produces one of three verdicts: Relaxed (below 25), Mild Stress (25–55), or High Stress Detected (above 55).&lt;/p&gt;

&lt;p&gt;Index finger — pressed firmly on top of the MAX30100 sensor chip (HR + SpO2)&lt;br&gt;
Middle finger — pinching the bare metal tip of the jumper wire on GPIO12 (T5)&lt;br&gt;
Ring finger — pinching the bare metal tip of the jumper wire on GPIO13 (T4)&lt;br&gt;
Alternatively, place the index finger on the MAX30100 with your left hand and hold both jumper wire tips between the thumb and index finger of your right hand. Both placements work equally well.&lt;/p&gt;
&lt;h2&gt;
  
  
  Circuit Diagram
&lt;/h2&gt;

&lt;p&gt;The MAX30100 connects to the ESP32 over I2C using just four wires. The GSR circuit requires no additional components — two jumper wires plugged into GPIO12 and GPIO13 are all that's needed. The calibration button connects GPIO14 to GND, with the internal pull-up resistor enabled in firmware.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Floel70nfd0oo93oyemgp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Floel70nfd0oo93oyemgp.png" alt=" " width="800" height="588"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn3k51vmrl4k4y0n2rqj4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn3k51vmrl4k4y0n2rqj4.png" alt=" " width="800" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feudjopitaz08mxqpozg0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feudjopitaz08mxqpozg0.png" alt=" " width="799" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiv3xl2czr6bis59jtfw6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiv3xl2czr6bis59jtfw6.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Code Explanation
&lt;/h2&gt;
&lt;h2&gt;
  
  
  Libraries and Pin Definitions
&lt;/h2&gt;

&lt;p&gt;The firmware uses Wire.h for I2C communication and MAX30100_PulseOximeter.h from the MAX30100lib library for sensor management. The two capacitive touch pins (for GSR) and the calibration button pin are defined at the top. Several baseline variables are declared to store the user's calm-state reference values, which are captured during the calibration phase.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include &amp;lt;Wire.h&amp;gt;
#include "MAX30100_PulseOximeter.h"

#define REPORTING_PERIOD_MS 500

#define TOUCH_1   T5    // GPIO12
#define TOUCH_2   T4    // GPIO13
#define BTN_PIN   25    // Calibration button

PulseOximeter pox;

float baseHR  = 0;
float baseHRV = 0;
float baseGSR = 0;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  GSR Reading with Smoothing
&lt;/h2&gt;

&lt;p&gt;The readGSR() function captures skin conductance by averaging the two ESP32 capacitive touch pins. Because raw touch readings are highly susceptible to physical noise (like finger micro-movements), an exponential moving average (low-pass filter) is applied. By combining 80% of the previous smoothed value with 20% of the new raw reading, minor jitters are ignored, allowing only genuine sweat-driven conductance changes to pass through to the scoring logic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;float smoothGSR = 0;
float prevGSR   = 0;

float readGSR() {
  float raw = (touchRead(TOUCH_1) + touchRead(TOUCH_2)) / 2.0;
  smoothGSR = smoothGSR * 0.8 + raw * 0.2;  // low-pass filter
  return smoothGSR;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Heart Rate Variability (HRV) is derived from the heart rate using a mathematical approximation of RMSSD (Root Mean Square of Successive Differences). The RR interval (milliseconds between beats) is computed from the BPM, and the last 10 successive differences are tracked. A stressed state typically triggers the sympathetic nervous system, causing HRV to drop rapidly as heartbeats become unnaturally rigid.&lt;/p&gt;

&lt;p&gt;$$RMSSD = \sqrt{\frac{1}{N} \sum_{i=1}^{N} (RR_i - RR_{i-1})^2}$$&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;float lastRR      = 0;
float rrDiffs[10] = {0};
int   rrIdx       = 0;

float calcHRV(float hr) {
  if (hr &amp;lt; 30) return lastRR ? lastRR : 50.0;
  float rr = 60000.0 / hr;
  if (lastRR &amp;gt; 0) {
    rrDiffs[rrIdx % 10] = abs(rr - lastRR);
    rrIdx++;
  }
  lastRR = rr;
  if (rrIdx &amp;lt; 3) return 50.0;

  float sum = 0;
  int n = min(rrIdx, 10);
  for (int i = 0; i &amp;lt; n; i++) sum += rrDiffs[i] * rrDiffs[i];
  return sqrt(sum / n);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Stress Scoring
&lt;/h2&gt;

&lt;p&gt;The stressScore() function computes a weighted composite score (0 to 100) based on four distinct biometric sub-signals: HR delta (25%), HRV delta (35%), absolute GSR delta (25%), and GSR rate of change (15%). The rate-of-change component is the most sensitive metric—it catches immediate, sharp conductance spikes that occur before the absolute levels have shifted significantly. Each sub-score is clamped to 0–100 before weighting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;int stressScore(float hr, float hrv, float gsr) {
  float dHR     = hr  - baseHR;
  float dHRV    = hrv - baseHRV;
  float dGSR    = baseGSR - gsr;    // lower touchRead = more stressed
  float rateGSR = prevGSR - gsr;    // sudden spike detection

  float s = 0;
  s += constrain(dHR     / 20.0 * 100, 0, 100) * 0.25;  // HR spike
  s += constrain(-dHRV   / 10.0 * 100, 0, 100) * 0.35;  // HRV drop
  s += constrain(dGSR    / 20.0 * 100, 0, 100) * 0.25;  // GSR level
  s += constrain(rateGSR /  4.0 * 100, 0, 100) * 0.15;  // GSR rate
  return (int)s;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Baseline Calibration
&lt;/h2&gt;

&lt;p&gt;Because everyone's resting physiology is different, pressing the button triggers a non-blocking 3-second calibration window. It gathers biometric data every 300ms, averages it, and establishes a stable resting baseline. All subsequent stress scores are calculated as deviations from this saved baseline, which eliminates inter-person differences in resting HR, HRV, and skin conductance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (isCalibrating) {
  if (millis() - lastSampleTick &amp;gt;= 300) {
    sumHR  += hr;
    sumHRV += hrv;
    sumGSR += gsr;
    samplesCount++;
    lastSampleTick = millis();
  }

  if (millis() - calibrationStartTime &amp;gt;= 3000) {
    isCalibrating = false;
    baseHR  = sumHR  / (float)samplesCount;
    baseHRV = sumHRV / (float)samplesCount;
    baseGSR = sumGSR / (float)samplesCount;

    Serial.printf("Baseline set — HR: %.1f | HRV: %.1f | GSR: %.1f\n\n",
                  baseHR, baseHRV, baseGSR);
  }
  return; // Skip standard reporting while calibrating
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Main Loop - Reading and Verdict Output
&lt;/h2&gt;

&lt;p&gt;The main loop calls pox.update() continuously at the top to keep the MAX30100 I2C processing alive without blocking delays. Every 500ms, it evaluates the sensor values, computes the stress score (if a baseline exists), and prints the result. The output format is natively compatible with both the Serial Monitor (readable text) and the Serial Plotter (graphs automatically)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;void loop() {
  pox.update();

  float hr   = pox.getHeartRate();
  float spo2 = pox.getSpO2();
  float hrv  = calcHRV(hr);
  float gsr  = readGSR();

  if (millis() - tsLastReport &amp;gt; REPORTING_PERIOD_MS) {
    Serial.print("HR: ");      Serial.print(hr);    Serial.print(" bpm");
    Serial.print(" | SpO2: "); Serial.print(spo2);  Serial.print(" %");
    Serial.print(" | HRV: ");  Serial.print(hrv);
    Serial.print(" | GSR: ");  Serial.print(gsr);

    if (baseHR &amp;gt; 0) {
      prevGSR   = smoothGSR;
      int score = stressScore(hr, hrv, gsr);
      Serial.print(" | Score: "); Serial.print(score);
      Serial.print(" | ");

      if      (score &amp;lt; 25) Serial.println("CALM");
      else if (score &amp;lt; 45) Serial.println("ANXIOUS");
      else                 Serial.println("HIGH STRESS DETECTED");
    } else {
      Serial.println(" | [press button to calibrate]");
    }

    tsLastReport = millis();
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How to Use
&lt;/h2&gt;

&lt;p&gt;Upload the firmware and open Serial Monitor at 115200 baud.&lt;br&gt;
Place your index finger firmly on the MAX30100 chip. Wait for a stable HR reading.&lt;br&gt;
Pinch the two jumper wire metal tips with your middle and ring finger of the same hand.&lt;br&gt;
Stay calm and press the calibration button. Hold completely still for 3 seconds until the baseline confirmation message appears.&lt;br&gt;
Ask a few neutral control questions first ("What is your name?") to ensure the score stays near zero.&lt;br&gt;
Ask the test questions and watch the Score column and verdict update in real time.&lt;br&gt;
To visualize all signals as live graphs, switch from Serial Monitor to Tools → Serial Plotter in Arduino IDE. HR, HRV, GSR, and Score will each render as a separate trace.&lt;/p&gt;

&lt;p&gt;uts a live composite stress score every 500ms, and delivers a real-time, three-level verdict (CALM, ANXIOUS, or HIGH STRESS DETECTED) over USB Serial. It achieves this with zero external circuitry beyond the sensor module, a push button, and two jumper wires.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu4znylysl7ax0dqwpc20.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu4znylysl7ax0dqwpc20.png" alt=" " width="360" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the final prototype, the exponential low-pass filter on the GSR inputs successfully eliminates micro-motion noise while preserving genuine conductance spikes. The HRV (RMSSD) drop component provides the most reliable long-duration indicator of stress, while the GSR rate-of-change metric catches immediate sympathetic nervous system responses within 1–2 seconds of a question or stimulus. Working in tandem, these core signals cover the same physiological channels monitored by professional polygraph systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Complete Code
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include &amp;lt;Wire.h&amp;gt;
#include "MAX30100_PulseOximeter.h"

#define REPORTING_PERIOD_MS 500

// Touch GSR pins
#define TOUCH_1  T5   // GPIO12
#define TOUCH_2  T4   // GPIO13

// Calibration button
#define BTN_PIN  25

PulseOximeter pox;
uint32_t tsLastReport = 0;

// Baselines (set on button press)

float baseHR  = 0;
float baseHRV = 0;
float baseGSR = 0;

// HRV tracking
float lastRR      = 0;
float rrDiffs[10] = {0};
int   rrIdx       = 0;

// GSR smoothing
float smoothGSR = 0;
float prevGSR   = 0;

// Beat callback — also used for HRV
void onBeatDetected() {
  Serial.println("Beat!");
}

// ── GSR read with smoothing ────────────────────────
float readGSR() {
  float raw = (touchRead(TOUCH_1) + touchRead(TOUCH_2)) / 2.0;
  smoothGSR = smoothGSR * 0.8 + raw * 0.2;
  return smoothGSR;
}

// ── HRV from heart rate (RMSSD approximation) ─────
float calcHRV(float hr) {
  if (hr &amp;lt; 30) return lastRR ? lastRR : 50.0;
  float rr = 60000.0 / hr;
  if (lastRR &amp;gt; 0) {
    rrDiffs[rrIdx % 10] = abs(rr - lastRR);
    rrIdx++;
  }
  lastRR = rr;
  if (rrIdx &amp;lt; 3) return 50.0;
  float sum = 0;
  int n = min(rrIdx, 10);
  for (int i = 0; i &amp;lt; n; i++) sum += rrDiffs[i] * rrDiffs[i];
  return sqrt(sum / n);
}

// ── Stress score 0–100 ─────────────────────────────
int stressScore(float hr, float hrv, float gsr) {
  float dHR      = hr - baseHR;
  float dHRV     = hrv - baseHRV;
  float dGSR     = baseGSR - gsr;      // lower = more stressed
  float rateGSR  = prevGSR - gsr;      // sudden spike

  float s = 0;
  s += constrain(dHR     / 20.0 * 100, 0, 100) * 0.25;
  s += constrain(-dHRV   / 10.0 * 100, 0, 100) * 0.35;
  s += constrain(dGSR    / 20.0 * 100, 0, 100) * 0.25;
  s += constrain(rateGSR /  4.0 * 100, 0, 100) * 0.15;
  return (int)s;
}

// ── Setup ──────────────────────────────────────────
void setup() {
  delay(10000);
  Serial.begin(115200);
  pinMode(BTN_PIN, INPUT_PULLUP);

  Serial.println("Initializing MAX30100...");
  if (!pox.begin()) {
    Serial.println("MAX30100 FAILED");
    while (true);
  }
  Serial.println("MAX30100 SUCCESS");

  pox.setIRLedCurrent(MAX30100_LED_CURR_7_6MA);
  pox.setOnBeatDetectedCallback(onBeatDetected);
  Serial.println("\n=== Pocket Stress Detector ===");
  Serial.println("1. Place index finger on MAX30100");
  Serial.println("2. Hold both GSR jumper wires (GPIO12 &amp;amp; GPIO13)");
  Serial.println("3. Stay CALM and press button (GPIO25) to calibrate\n");
}

// Global variables to track non-blocking calibration state
bool isCalibrating = false;
uint32_t calibrationStartTime = 0;
uint32_t lastSampleTick = 0;
float sumHR = 0, sumHRV = 0, sumGSR = 0;
int samplesCount = 0;
void loop() {
  // Always call this at the absolute top of the loop with no barriers
  pox.update();
  float hr   = pox.getHeartRate();
  float spo2 = pox.getSpO2();
  float hrv  = calcHRV(hr);
  float gsr  = readGSR();

  // ── 1. Check if the physical button is pressed ──
  if (digitalRead(BTN_PIN) == LOW &amp;amp;&amp;amp; !isCalibrating) {
    delay(50); // Small debounce
    if (digitalRead(BTN_PIN) == LOW) {
      isCalibrating = true;
      calibrationStartTime = millis();
      lastSampleTick = millis();
      sumHR = 0; sumHRV = 0; sumGSR = 0;
      samplesCount = 0;
      Serial.println("Calibrating... Keep your finger steady for 3 seconds.");
    }
  }

  // ── 2. Run the Calibration collection seamlessly ──
  if (isCalibrating) {
    // Collect a sample every 300ms
    if (millis() - lastSampleTick &amp;gt;= 300) {
      sumHR   += hr;
      sumHRV  += hrv;
      sumGSR  += gsr;
      samplesCount++;
      lastSampleTick = millis();
      Serial.print("."); // Progress indicator
    }

    // Check if 3 seconds have passed
    if (millis() - calibrationStartTime &amp;gt;= 3000) {
      isCalibrating = false; // End calibration window

      if (samplesCount &amp;gt; 0) {
        baseHR  = sumHR  / (float)samplesCount;
        baseHRV = sumHRV / (float)samplesCount;
        baseGSR = sumGSR / (float)samplesCount;
      }

      Serial.println("\n=== BASELINE SAVED ===");
      Serial.printf("Base HR: %.1f | Base HRV: %.1f | Base GSR: %.1f\n\n", baseHR, baseHRV, baseGSR);
    }
    return; // Don't print regular reports while calibrating
  }

  // ── 3. Regular Report Every 500ms ──
  if (millis() - tsLastReport &amp;gt; REPORTING_PERIOD_MS) {
    Serial.print("HR: ");    Serial.print(hr);    Serial.print(" bpm");
    Serial.print(" | SpO2: "); Serial.print(spo2); Serial.print(" %");
    Serial.print(" | HRV: "); Serial.print(hrv);
    Serial.print(" | GSR: "); Serial.print(gsr);

    if (baseHR &amp;gt; 0) {
      prevGSR   = smoothGSR;
      int score = stressScore(hr, hrv, gsr);
      Serial.print(" | Score: "); Serial.print(score);
      Serial.print(" | ");

      if      (score &amp;lt; 25) Serial.println("CALM");
      else if (score &amp;lt; 45) Serial.println("ANXIOUS");
      else                 Serial.println("HIGH STRESS DETECTED");
    } else {
      Serial.println(" | [press button to calibrate]");
    }

    tsLastReport = millis();
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>programming</category>
      <category>productivity</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>DIY Electronics</dc:creator>
      <pubDate>Fri, 26 Jun 2026 07:05:31 +0000</pubDate>
      <link>https://dev.to/diy_electronics_1a54d645a/-3b7g</link>
      <guid>https://dev.to/diy_electronics_1a54d645a/-3b7g</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/akshay_jain/long-range-appliance-control-system-using-arduino-and-lora-3jah" class="crayons-story__hidden-navigation-link"&gt;Long-Range Appliance Control System Using Arduino and LoRa&lt;/a&gt;
    &lt;div class="crayons-article__cover crayons-article__cover__image__feed"&gt;
      &lt;iframe src="https://www.youtube.com/embed/01V1MLmuCQE" title="Long-Range Appliance Control System Using Arduino and LoRa"&gt;&lt;/iframe&gt;
    &lt;/div&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/akshay_jain" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1489699%2F54ac2f6b-a1e3-47e2-a897-11bf89afa477.png" alt="akshay_jain profile" class="crayons-avatar__image" width="50" height="50"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/akshay_jain" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Akshay Jain
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Akshay Jain
                
              
              &lt;div id="story-author-preview-content-3956499" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/akshay_jain" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1489699%2F54ac2f6b-a1e3-47e2-a897-11bf89afa477.png" class="crayons-avatar__image" alt="" width="50" height="50"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Akshay Jain&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/akshay_jain/long-range-appliance-control-system-using-arduino-and-lora-3jah" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jun 21&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/akshay_jain/long-range-appliance-control-system-using-arduino-and-lora-3jah" id="article-link-3956499"&gt;
          Long-Range Appliance Control System Using Arduino and LoRa
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/programming"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;programming&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/arduino"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;arduino&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/iot"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;iot&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/akshay_jain/long-range-appliance-control-system-using-arduino-and-lora-3jah" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;2&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/akshay_jain/long-range-appliance-control-system-using-arduino-and-lora-3jah#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>5 Things I Wish I Knew Before Starting with Arduino</title>
      <dc:creator>DIY Electronics</dc:creator>
      <pubDate>Fri, 26 Jun 2026 07:03:01 +0000</pubDate>
      <link>https://dev.to/diy_electronics_1a54d645a/5-things-i-wish-i-knew-before-starting-with-arduino-3djf</link>
      <guid>https://dev.to/diy_electronics_1a54d645a/5-things-i-wish-i-knew-before-starting-with-arduino-3djf</guid>
      <description>&lt;p&gt;When I bought my first Arduino board, I was excited to build robots, automate tasks, and create cool electronics projects. Like many beginners, I thought the hardest part would be writing the code.&lt;/p&gt;

&lt;p&gt;I was wrong.&lt;/p&gt;

&lt;p&gt;Most of my early mistakes had nothing to do with programming—they came from wiring, understanding hardware, and learning how to troubleshoot. Looking back, there are a few things I wish someone had told me on day one.&lt;/p&gt;

&lt;p&gt;If you're just starting your Arduino journey, here are five lessons that can save you hours of frustration.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Debugging Is More Important Than Writing Code
&lt;/h2&gt;

&lt;p&gt;When something doesn't work, it's tempting to assume your code is broken. In reality, the problem is often much simpler.&lt;/p&gt;

&lt;p&gt;I've spent hours searching for software bugs, only to realize a jumper wire wasn't connected properly or a sensor wasn't receiving power.&lt;/p&gt;

&lt;p&gt;Before changing your code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check all wiring connections.&lt;/li&gt;
&lt;li&gt;Verify power and ground.&lt;/li&gt;
&lt;li&gt;Make sure you've selected the correct board and COM port.&lt;/li&gt;
&lt;li&gt;Use the Serial Monitor to see what's happening.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A systematic debugging process will save you far more time than randomly editing code.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Datasheets Aren't as Scary as They Look
&lt;/h2&gt;

&lt;p&gt;At first, I avoided datasheets because they seemed too technical.&lt;/p&gt;

&lt;p&gt;Eventually, I realized that most of the information I needed was in just a few pages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pin configuration&lt;/li&gt;
&lt;li&gt;Operating voltage&lt;/li&gt;
&lt;li&gt;Current limits&lt;/li&gt;
&lt;li&gt;Communication protocol&lt;/li&gt;
&lt;li&gt;Example circuits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Learning to read even the basic sections of a datasheet made working with new components much easier.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Every Project Doesn't Need to Be Perfect
&lt;/h2&gt;

&lt;p&gt;In the beginning, I wanted every project to look professional.&lt;/p&gt;

&lt;p&gt;The truth is, messy breadboards, loose jumper wires, and failed prototypes are part of the learning process.&lt;/p&gt;

&lt;p&gt;Some of my best lessons came from projects that didn't work the first time.&lt;/p&gt;

&lt;p&gt;Build first. Improve later.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Start Small Before Building Big Projects
&lt;/h2&gt;

&lt;p&gt;It's exciting to dream about building a smart home, a robot, or an IoT system.&lt;/p&gt;

&lt;p&gt;But jumping into complex projects too early can become overwhelming.&lt;/p&gt;

&lt;p&gt;Instead, master the basics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Blink an LED&lt;/li&gt;
&lt;li&gt;Read a button&lt;/li&gt;
&lt;li&gt;Control a servo motor&lt;/li&gt;
&lt;li&gt;Display sensor values on an LCD&lt;/li&gt;
&lt;li&gt;Read data from a temperature sensor&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each small project teaches a new concept that becomes useful in larger builds.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. The Arduino Community Is One of the Best Learning Resources
&lt;/h2&gt;

&lt;p&gt;One thing that surprised me was how helpful the Arduino community is.&lt;/p&gt;

&lt;p&gt;Whether it's forums, GitHub repositories, YouTube tutorials, or communities like DEV, chances are someone has faced the same problem you're dealing with.&lt;/p&gt;

&lt;p&gt;Don't be afraid to ask questions, share your projects, or help others when you can.&lt;/p&gt;

&lt;p&gt;Learning becomes much more enjoyable when you're part of a community.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Starting with Arduino opened the door to embedded systems, IoT, and electronics for me. Every failed upload, loose connection, and debugging session taught me something valuable.&lt;/p&gt;

&lt;p&gt;If you're just getting started, don't worry about making mistakes—they're part of the process.&lt;/p&gt;

&lt;p&gt;I'm still learning, and through future posts, I'll be sharing project tutorials, debugging tips, and lessons from my journey in embedded systems.&lt;/p&gt;

&lt;p&gt;If you're also beginning your Arduino journey, I'd love to hear what project you're working on in the comments.&lt;/p&gt;

&lt;p&gt;Happy building! 🚀&lt;/p&gt;

</description>
      <category>arduino</category>
      <category>iot</category>
      <category>electronics</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
