Back to IoT Blog
DIY Projects 25 min read â€Ē Updated: March 2025

Getting Started with ESP32: Complete Beginner's Guide

Learn everything you need to know about ESP32 microcontroller. From setup to your first IoT project with WiFi and Bluetooth.

1. What is ESP32?

The ESP32 is a low-cost, low-power system on a chip (SoC) microcontroller with integrated Wi-Fi and dual-mode Bluetooth. Developed by Espressif Systems (the same company behind ESP8266), it's become the go-to choice for IoT projects.

📊 Key Specifications:
  • CPU: Dual-core Tensilica LX6 @ 160-240 MHz
  • SRAM: 520 KB
  • Flash: 4 MB (typical)
  • WiFi: 802.11 b/g/n (2.4 GHz)
  • Bluetooth: v4.2 BR/EDR and BLE
  • GPIO: 34 pins with multiple functions
  • ADC: 18 channels, 12-bit
  • DAC: 2 channels, 8-bit
  • Price: $3-10 USD

Why Choose ESP32?

2. ESP32 Variants Compared

Board CPU WiFi Bluetooth Price
ESP32 DevKit V1 Dual-core 240MHz ✅ ✅ Classic + BLE $6-10
ESP32-WROOM-32 Dual-core 240MHz ✅ ✅ Classic + BLE $5-8
ESP32-S3 Dual-core 240MHz ✅ ✅ BLE 5.0 $8-12
ESP32-C3 Single-core 160MHz ✅ ✅ BLE 5.0 $3-5
NodeMCU-32S Dual-core 240MHz ✅ ✅ Classic + BLE $6-10
ðŸ’Ą Recommendation for Beginners:

Start with ESP32 DevKit V1 or NodeMCU-32S. They're well-documented, widely supported, and perfect for learning.

3. Getting Started - What You Need

ESP32 Development Board ESP32 DevKit V1 or similar ($6-10)
USB Cable Micro-USB or USB-C (check your board)
Computer Windows, macOS, or Linux
Breadboard & Jumper Wires For prototyping circuits
LEDs & Resistors For testing GPIO pins
Optional: Sensors DHT22, ultrasonic, etc.

4. Arduino IDE Setup

Step 1: Install Arduino IDE

  1. Download from arduino.cc
  2. Install for your operating system
  3. Launch Arduino IDE

Step 2: Add ESP32 Board Support

  1. Go to File → Preferences
  2. In "Additional Board Manager URLs", add:
    https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
  3. Click OK
  4. Go to Tools → Board → Boards Manager
  5. Search for "esp32"
  6. Install "esp32 by Espressif Systems"
  7. Wait for installation to complete (may take a few minutes)

Step 3: Select Your Board

  1. Go to Tools → Board → ESP32 Arduino
  2. Select your board (e.g., "DOIT ESP32 DEVKIT V1")
  3. Go to Tools → Port and select your COM port
⚠ïļ Driver Issues?

If your board isn't recognized, you may need USB driver:
â€Ē CP2102: Download here
â€Ē CH340: Download here

5. Your First Program - Blink LED

Let's start with the classic "Hello World" of hardware - blinking an LED!

Hardware Setup

LED Connection:
ESP32          LED
─────          ───
GPIO 2  ──────â–ķ|───┐
              LED  │
GND     ──────────â”ī──[220ÎĐ]──â–ķ GND

Note: Many ESP32 boards have built-in LED on GPIO 2

Blink Code

void setup() {
  // Initialize GPIO 2 as output
  pinMode(2, OUTPUT);
}

void loop() {
  digitalWrite(2, HIGH);  // Turn LED on
  delay(1000);             // Wait 1 second
  digitalWrite(2, LOW);   // Turn LED off
  delay(1000);             // Wait 1 second
}

/*
Upload Instructions:
1. Copy this code into Arduino IDE
2. Click Upload button (→ arrow)
3. If upload fails, hold BOOT button while uploading
4. Release BOOT button when upload starts
*/

Upload Troubleshooting

If upload fails with "Failed to connect to ESP32":

  1. Hold the BOOT button on ESP32
  2. Press EN (or RST) button
  3. Release EN button
  4. Release BOOT button
  5. Try uploading again

6. Understanding GPIO Pins

ESP32 DevKit V1 Pinout (Top View): ┌────────────────────────────────┐ │ ┌────────────────────┐ │ │ │ ESP32 │ │ │ │ │ │ │ 3V3 │ EN │ GND │ │ GND │ │ GND │ │ 23 │ │ 21 │ │ 22 │ │ TX │ │ 01 │ │ RX │ │ 03 │ │ 09 │ │ 04 │ │ 10 │ │ 05 │ │ 11 │ │ 18 │ │ 12 │ │ 19 │ │ 13 │ │ 27 │ │ 14 │ │ 16 │ │ 26 │ │ 17 │ │ 25 │ │ 32 │ │ 33 │ │ 35 │ │ 34 │ │ GND │ │ VIN │ │ └────────────────────┘ │ └────────────────────────────────┘

GPIO Pin Capabilities

Pin Type GPIO Numbers Notes
Digital I/O Most GPIOs Input or output, 3.3V logic
ADC GPIO 32-39 Analog input only (12-bit)
DAC GPIO 25, 26 Analog output (8-bit)
PWM Most GPIOs Software PWM on any pin
I2C Any GPIO Default: SDA=21, SCL=22
SPI GPIO 5, 18, 19, 23 VSPI pins
UART GPIO 1, 3, 16, 17 TX0=1, RX0=3
Touch GPIO 0, 2, 4, 12-15 Capacitive touch sensors
⚠ïļ GPIO Warnings:
  • GPIO 34-39: Input only (no internal pull-up)
  • GPIO 6-11: Connected to flash chip (don't use)
  • GPIO 1 (TX0): Avoid during boot
  • GPIO 2: Built-in LED, affects boot
  • GPIO 12: Affects boot mode
  • GPIO 34-39: No internal pull-up/pull-down
  • Voltage: 3.3V logic (NOT 5V tolerant!)

Basic GPIO Examples

// Digital Output
pinMode(2, OUTPUT);
digitalWrite(2, HIGH);  // 3.3V
digitalWrite(2, LOW);   // 0V

// Digital Input with Pull-up
pinMode(4, INPUT_PULLUP);
int value = digitalRead(4);  // HIGH or LOW

// Analog Read (ADC)
int sensorValue = analogRead(34);  // 0-4095
float voltage = sensorValue * (3.3 / 4095.0);

// PWM (LED Control)
ledcSetup(0, 5000, 8);  // Channel 0, 5kHz, 8-bit
ledcAttachPin(2, 0);    // Attach GPIO 2 to channel 0
ledcWrite(0, 128);      // 50% duty cycle (0-255)

7. Connecting to WiFi

Basic WiFi Connection

#include <WiFi.h>

const char* ssid = "YourWiFiName";
const char* password = "YourWiFiPassword";

void setup() {
  Serial.begin(115200);
  
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  
  WiFi.begin(ssid, password);
  
  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  // Your code here
  delay(10000);
}

WiFi Connection with Status Check

void checkWiFi() {
  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("WiFi disconnected! Reconnecting...");
    WiFi.reconnect();
    delay(5000);
  }
}

WiFi Scanner

#include <WiFi.h>

void setup() {
  Serial.begin(115200);
  
  // Scan for networks
  int n = WiFi.scanNetworks();
  
  Serial.println("Available Networks:");
  for (int i = 0; i < n; i++) {
    Serial.print(i + 1);
    Serial.print(". ");
    Serial.print(WiFi.SSID(i));
    Serial.print(" (");
    Serial.print(WiFi.RSSI(i));
    Serial.print(" dBm)");
    Serial.println(WiFi.encryptionType(i) == WIFI_AUTH_OPEN ? " " : "*");
  }
}

void loop() {}

8. Bluetooth Classic & BLE

Bluetooth Classic (Serial)

#include <BluetoothSerial.h>

BluetoothSerial BT;

void setup() {
  Serial.begin(115200);
  BT.begin("ESP32-Serial");  // Device name
  Serial.println("Bluetooth Serial Ready");
}

void loop() {
  if (BT.available()) {
    Serial.write(BT.read());
  }
  if (Serial.available()) {
    BT.write(Serial.read());
  }
}

Bluetooth Low Energy (BLE) Server

#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

// UUIDs (generate your own at uuidgenerator.net)
#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

BLEServer *pServer = NULL;
BLECharacteristic *pCharacteristic = NULL;
bool deviceConnected = false;

class MyServerCallbacks: public BLEServerCallbacks {
  void onConnect(BLEServer* pServer) {
    deviceConnected = true;
  }
  void onDisconnect(BLEServer* pServer) {
    deviceConnected = false;
  }
};

void setup() {
  Serial.begin(115200);
  
  // Create BLE Device
  BLEDevice::init("ESP32-BLE-Server");
  
  // Create Server
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());
  
  // Create Service
  BLEService *pService = pServer->createService(SERVICE_UUID);
  
  // Create Characteristic
  pCharacteristic = pService->createCharacteristic(
    CHARACTERISTIC_UUID,
    BLECharacteristic::PROPERTY_READ |
    BLECharacteristic::PROPERTY_WRITE |
    BLECharacteristic::PROPERTY_NOTIFY
  );
  
  pCharacteristic->addDescriptor(new BLE2902());
  
  // Start Service
  pService->start();
  
  // Start Advertising
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->start();
  
  Serial.println("BLE Server Ready");
}

void loop() {
  if (deviceConnected) {
    pCharacteristic->setValue("Hello from ESP32");
    pCharacteristic->notify();
    delay(2000);
  }
}

9. Deep Sleep & Power Saving

ESP32's deep sleep mode reduces power consumption to ~5-10 ΞA, perfect for battery-powered projects!

Deep Sleep with Timer Wake-up

#define uS_TO_S_FACTOR 1000000ULL  // Conversion factor
#define TIME_TO_SLEEP  10          // Sleep for 10 seconds

RTC_DATA_ATTR int bootCount = 0;

void setup() {
  Serial.begin(115200);
  
  // Increment boot number
  ++bootCount;
  Serial.println("Boot number: " + String(bootCount));
  
  // Configure timer wake-up
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  
  Serial.println("Going to sleep for " + String(TIME_TO_SLEEP) + " seconds");
  Serial.flush();
  
  // Enter deep sleep
  esp_deep_sleep_start();
}

void loop() {
  // This won't run (ESP32 sleeps in setup)
}

Deep Sleep with External Wake-up

#define BUTTON_PIN 39  // GPIO 39 (input only)

void setup() {
  Serial.begin(115200);
  
  // Configure ext1 wake-up on GPIO 39
  esp_sleep_enable_ext1_wakeup(BUTTON_PIN, ESP_EXT1_WAKEUP_ALL_LOW);
  
  // Check wake reason
  esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause();
  
  switch(wakeup_reason) {
    case ESP_SLEEP_WAKEUP_EXT1:
      Serial.println("Woken by GPIO button press");
      break;
    case ESP_SLEEP_WAKEUP_TIMER:
      Serial.println("Woken by timer");
      break;
    default:
      Serial.println("Woken by other reason");
  }
  
  Serial.flush();
  esp_deep_sleep_start();
}

Power Consumption Comparison

Mode Current Draw Description
Active (WiFi on) 80-100 mA Full operation, transmitting
Active (WiFi off) 50-70 mA CPU running, no WiFi
Modem Sleep 15-20 mA WiFi disconnected, CPU running
Light Sleep 0.8-1 mA CPU paused, RAM retained
Deep Sleep 5-10 ΞA Most circuits off, RTC on
Hibernate 2-5 ΞA Everything off, no wake

10. Complete Project Example

WiFi Weather Station

Build a simple weather station that reads temperature and publishes to MQTT:

#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>

// WiFi & MQTT
const char* ssid = "YOUR_WIFI";
const char* password = "YOUR_PASSWORD";
const char* mqtt_server = "broker.hivemq.com";

// DHT Sensor
#define DHTPIN 4
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);

WiFiClient espClient;
PubSubClient client(espClient);

void setup_wifi() {
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
}

void reconnect() {
  while (!client.connected()) {
    String clientId = "ESP32Weather-" + String(random(0xffff), HEX);
    if (client.connect(clientId.c_str())) {
      Serial.println("MQTT connected");
    } else {
      delay(5000);
    }
  }
}

void setup() {
  Serial.begin(115200);
  dht.begin();
  setup_wifi();
  client.setServer(mqtt_server, 1883);
}

void loop() {
  if (!client.connected()) reconnect();
  client.loop();
  
  // Read sensor
  float humidity = dht.readHumidity();
  float temp = dht.readTemperature();
  
  if (isnan(humidity) || isnan(temp)) {
    Serial.println("Failed to read from DHT");
    return;
  }
  
  // Publish to MQTT
  char tempStr[8];
  char humStr[8];
  dtostrf(temp, 1, 2, tempStr);
  dtostrf(humidity, 1, 2, humStr);
  
  client.publish("weather/temperature", tempStr);
  client.publish("weather/humidity", humStr);
  
  Serial.print("Temp: ");
  Serial.print(temp);
  Serial.print("°C, Humidity: ");
  Serial.print(humidity);
  Serial.println("%");
  
  // Deep sleep for 60 seconds
  esp_sleep_enable_timer_wakeup(60 * 1000000ULL);
  esp_deep_sleep_start();
}

11. Troubleshooting

Problem: Board Not Recognized

Problem: Upload Fails

Problem: WiFi Won't Connect

Problem: Brownout Reset

Problem: GPIO Not Working

12. Next Steps & Resources

Continue Learning

Now that you know ESP32 basics, try these projects:

  • Smart home temperature monitoring
  • MQTT-based sensor network
  • Web server on ESP32
  • Bluetooth remote control
  • Battery-powered sensor node
  • OTA (Over-The-Air) updates

Useful Resources