// =====================================================
// PROJECT 1 — Temperature & Humidity Monitor
// =====================================================
// ─── PART 1: LIBRARIES ────────────────────────────
// Bring in all the tools we need
#include <Arduino.h> // Main Arduino library - always first
#include "DHT.h" // DHT22 sensor library
#include <Wire.h> // I2C communication library
#include <Adafruit_GFX.h> // Graphics library for display
#include <Adafruit_SSD1306.h> // OLED display driver library
// ─── PART 2: PIN DEFINITIONS ──────────────────────
// Give nicknames to pin numbers
#define DHT_PIN 15 // DHT22 data wire connected to GPIO 15
#define DHT_TYPE DHT22 // We are using DHT22 type sensor
#define SCREEN_WIDTH 128 // OLED display width in pixels
#define SCREEN_HEIGHT 64 // OLED display height in pixels
#define OLED_RESET -1 // No reset pin needed, so -1
// ─── PART 3: CREATE OBJECTS ───────────────────────
// Create sensor and display so we can use them in code
DHT dht(DHT_PIN, DHT_TYPE);
// This creates a DHT sensor object
// DHT_PIN = which pin to read from (GPIO 15)
// DHT_TYPE = what type of sensor (DHT22)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// This creates a display object
// SCREEN_WIDTH, SCREEN_HEIGHT = size of display (128x64)
// &Wire = use I2C communication
// OLED_RESET = no reset pin (-1)
// ─── PART 4: VARIABLES ────────────────────────────
// Boxes to store our data while program runs
float temperature = 0.0; // stores temperature value (float = decimal number)
float humidity = 0.0; // stores humidity value
int readCount = 0; // counts how many readings done (int = whole number)
// ─── PART 5: TIMING VARIABLES ─────────────────────
unsigned long lastReadTime = 0; // stores last time we read sensor
const int READ_INTERVAL = 2000; // read every 2000 milliseconds = 2 seconds
// unsigned long = big number that stores milliseconds since ESP32 started
// const = this value never changes during the program
// =====================================================
// SETUP — runs ONCE when ESP32 starts or resets
// =====================================================
void setup() {
// Start Serial Monitor
// This opens a communication channel between ESP32 and your laptop
// 115200 is the speed (baud rate) - both sides must use same speed
Serial.begin(115200);
// Print a welcome message to Serial Monitor
Serial.println("=============================");
Serial.println(" Project 1 - Temp Monitor ");
Serial.println("=============================");
// Start the DHT22 sensor
dht.begin();
Serial.println("DHT22 sensor started");
// Start the OLED display
// 0x3C is the I2C address of display - like a house address
// Every I2C device has a unique address so ESP32 knows who to talk to
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
// If display fails to start, print error and stop program
Serial.println("ERROR: Display not found! Check wiring.");
while (true); // stop here forever
}
Serial.println("OLED display started");
// Show welcome screen on display
display.clearDisplay(); // clear any old data
display.setTextColor(SSD1306_WHITE); // set text colour to white
display.setTextSize(1); // text size 1 = small
display.setCursor(20, 10); // set position x=20, y=10 pixels
display.println("Project 1");
display.setCursor(5, 30);
display.println("Temp & Humidity");
display.setCursor(20, 50);
display.println("Starting...");
display.display(); // IMPORTANT - this line actually sends to screen
// without this line nothing shows on display
delay(2000); // wait 2 seconds showing welcome screen
// Print table header to Serial Monitor
Serial.println("Count | Temp C | Humidity % | Status");
Serial.println("--------------------------------------");
}
// =====================================================
// LOOP — runs FOREVER after setup finishes
// =====================================================
void loop() {
// millis() returns how many milliseconds have passed since ESP32 started
// We use this instead of delay() because delay() freezes the entire ESP32
// With millis() the ESP32 keeps running and just checks if enough time passed
if (millis() - lastReadTime >= READ_INTERVAL) {
lastReadTime = millis(); // save current time for next comparison
readCount++; // add 1 to read counter
// Read temperature and humidity from DHT22 sensor
temperature = dht.readTemperature(); // reads Celsius value
humidity = dht.readHumidity(); // reads humidity percentage
// isnan() means "is not a number"
// If sensor gives bad reading it returns NaN (not a number)
// We check for this so we do not show garbage values
if (isnan(temperature) || isnan(humidity)) {
Serial.println("ERROR: Sensor read failed!");
showError();
return; // skip rest of loop and start again
}
// Get status based on temperature value
// This calls our function below and stores the result
String status = getStatus(temperature);
// Print reading to Serial Monitor in neat format
// %d = integer, %.1f = float with 1 decimal, %s = string
Serial.printf("%d | %.1f | %.1f | %s\n",
readCount, temperature, humidity, status.c_str());
// Show reading on OLED display
showOnDisplay(temperature, humidity, status, readCount);
}
}
// =====================================================
// FUNCTION 1 — getStatus()
// Takes temperature value and returns a status word
// INPUT: float temp (the temperature number)
// OUTPUT: String (the status word)
// =====================================================
String getStatus(float temp) {
if (temp < 20.0) {
return "COLD"; // below 20 degrees
} else if (temp < 30.0) {
return "NORMAL"; // 20 to 29 degrees
} else if (temp < 40.0) {
return "WARM"; // 30 to 39 degrees
} else {
return "HOT!"; // 40 and above
}
}
// NOTE: This exact same pattern is used in welding project
// if (current > 5.0) { arcActive = true; touchCount++; }
// =====================================================
// FUNCTION 2 — showOnDisplay()
// Takes all readings and shows them on OLED screen
// INPUT: temp, hum, status, count values
// OUTPUT: nothing (void) - just updates screen
// =====================================================
void showOnDisplay(float temp, float hum, String status, int count) {
display.clearDisplay(); // always clear first before drawing new data
// ROW 1 - Title at top
display.setTextSize(1); // small text
display.setCursor(0, 0); // top left corner x=0, y=0
display.println("-- Temp Monitor --");
// ROW 2 - Temperature in big text
display.setTextSize(2); // bigger text
display.setCursor(0, 14); // move down 14 pixels
display.print("T:");
display.print(temp, 1); // print temp with 1 decimal place
display.println("C");
// ROW 3 - Humidity in small text
display.setTextSize(1); // back to small text
display.setCursor(0, 36); // move down to y=36
display.print("Hum: ");
display.print(hum, 1);
display.println("%");
// ROW 4 - Status and count at bottom
display.setCursor(0, 50); // bottom of screen y=50
display.print(status);
display.print(" #");
display.println(count);
display.display(); // send everything to screen - never forget this line!
}
// =====================================================
// FUNCTION 3 — showError()
// Shows error message on display when sensor fails
// =====================================================
void showError() {
display.clearDisplay();
display.setTextSize(1);
display.setCursor(15, 20);
display.println("SENSOR ERROR!");
display.setCursor(10, 40);
display.println("Check wiring...");
display.display();
}