← Back to Academy

You did it. You survived the breadboard spaghetti. You survived the magic blue smoke. You even survived Lesson 153 where we set up a local web server without throwing your laptop out the window. Now, it’s time to put it all together into something you can actually use: A complete, standalone ESP32 Smart Home Hub.

We’re going to build a central node that reads environmental data (temperature, humidity, and pressure) using a BME280 sensor, displays it locally on a crisp OLED screen, and serves a live web dashboard to any device on your Wi-Fi network. No cloud subscriptions. No weird companion apps that harvest your data. Just pure, unadulterated maker glory.

What You’ll Need

The Wiring

This is the beauty of I2C (Inter-Integrated Circuit). Both the BME280 and the OLED display can share the exact same two data pins on the ESP32. They just need different I2C addresses (which they have by default).

  1. Power: Connect the 3V3 pin on the ESP32 to the VCC (or VIN) pins on both the OLED and the BME280.
  2. Ground: Connect a GND pin on the ESP32 to the GND pins on both modules.
  3. Data (SDA): Connect GPIO 21 on the ESP32 to the SDA pin on both the OLED and BME280.
  4. Clock (SCL): Connect GPIO 22 on the ESP32 to the SCL pin on both modules.

Troubleshooting Tip: If you power this up and the display is completely blank, double check your SDA and SCL lines. Getting those backward is a rite of passage. If you’re still having issues, refer to our guide on I2C Devices Not Found.

The Code

This code combines the Adafruit BME280 library, the Adafruit SSD1306 library (for the OLED), and the standard WiFi library to host a simple web page.

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <WiFi.h>

// Replace with your network credentials
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
Adafruit_BME280 bme; 

WiFiServer server(80);

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

  // Initialize OLED
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }
  display.clearDisplay();
  display.setTextColor(WHITE);

  // Initialize BME280
  if (!bme.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }

  // Connect to Wi-Fi
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  
  server.begin();
}

void loop() {
  // Read Sensor Data
  float temp = bme.readTemperature();
  float hum = bme.readHumidity();
  float pres = bme.readPressure() / 100.0F;

  // Update OLED
  display.clearDisplay();
  display.setCursor(0, 0);
  display.setTextSize(1);
  display.println("Smart Home Hub");
  display.println("----------------");
  display.print("Temp: "); display.print(temp); display.println(" *C");
  display.print("Hum:  "); display.print(hum); display.println(" %");
  display.print("Pres: "); display.print(pres); display.println(" hPa");
  display.display();

  // Handle Web Clients
  WiFiClient client = server.available();
  if (client) {
    String currentLine = "";
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        if (c == '\n') {
          if (currentLine.length() == 0) {
            // Send standard HTTP response header
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();
            
            // Build the Web Page
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<style>body { font-family: sans-serif; text-align: center; margin-top: 50px; h1 { color: #333; } p { font-size: 24px; color: #666; } }</style></head>");
            client.println("<body><h1>ESP32 Environment Hub</h1>");
            client.println("<p>Temperature: " + String(temp) + " &deg;C</p>");
            client.println("<p>Humidity: " + String(hum) + " %</p>");
            client.println("<p>Pressure: " + String(pres) + " hPa</p>");
            client.println("</body></html>");
            client.println();
            break;
          } else {
            currentLine = "";
          }
        } else if (c != '\r') {
          currentLine += c;
        }
      }
    }
    client.stop();
  }
  delay(2000); // Wait 2 seconds before the next loop
}

Testing Your Hub

  1. Upload the code.
  2. Open the Serial Monitor (set to 115200 baud).
  3. Wait for the ESP32 to connect to your Wi-Fi network. It will print out an IP address (e.g., 192.168.1.145).
  4. Open a web browser on your phone or computer and type in that IP address.

Boom. You should see a live webpage serving up your room’s environmental stats, perfectly mirroring the little OLED display on your desk.

From here, the sky is the limit. You can add relays to trigger fans based on the temperature, hook it into Home Assistant using MQTT (as we covered in Lesson 154), or add more sensors to the I2C bus.