Imagine having real-time insights into temperature changes, accessible from anywhere in the world. With an ESP32 and a BME280 sensor, you can build a smart, cloud-connected monitoring system that logs environmental data and visualizes it dynamically.
In this project, you'll configure an ESP32 to read temperature data from a BME280 sensor and transmit it to Telemetry Harbor, a powerful IoT data platform. From there, the data is stored, processed, and displayed on a Grafana dashboard, giving you a live view of temperature trends. Whether you're tracking climate conditions, monitoring sensitive equipment, or just experimenting with IoT, this setup provides a scalable foundation for automation, alerts, and advanced analytics.
By the end of this guide, you'll have a fully functional system that not only logs temperature readings but also lays the groundwork for expanding your IoT network with more sensors, automated triggers, and cloud-based intelligence. Let's dive in!
Hardware Requirements- ESP32 development board (NodeMCU ESP32, WROOM, etc.) - AliExpress Price 3.82USD | Amazon US Price 9.90USD
- BME280 temperature, humidity, and pressure sensor module - AliExpress Price: 4.20USD | Amazon US Price 8.99USD
- Jumper wires - AliExpress Price: 0.42USD | Amazon US Price 5.49USD
- Micro USB Power & Data - AliExpress Price: 3.00USD | Amazon US Price ~5.00USD
- Optional: 3.3V power supply for standalone deployment
- Arduino IDE (1.8.13 or newer) or PlatformIO
Required libraries:
- Adafruit BME280 Library
- Adafruit Unified Sensor
- WiFi Library (built into ESP32 core)
- HTTPClient Library (built into ESP32 core)
- Required libraries:Adafruit BME280 LibraryAdafruit Unified SensorWiFi Library (built into ESP32 core)HTTPClient Library (built into ESP32 core)
- Telemetry Harbor account (free tier available)
- Open Arduino IDE
- Go to File > Preferences
- Add the following URL to the "Additional Boards Manager URLs"
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
- Go to Tools > Board > Boards Manager
- Search for "ESP32" and install the ESP32 by Espressif Systems
- Go to Sketch > Include Library > Manage Libraries
Search for and install:
- Adafruit BME280 Library
- Adafruit Unified Sensor
- Search for and install:Adafruit BME280 LibraryAdafruit Unified Sensor
The BME280 uses the I2C communication protocol, which requires just four connections:
BME280 Pin | ESP32 Pin | Function
VCC | 3.3V | Power
GND | GND | Ground
SDA | GPIO 21 | Data
SCL | GPIO 22 | Clock
Step 3: Setting Up Telemetry HarborTelemetry Harbor provides a straightforward platform for collecting, storing, and visualizing IoT sensor data. Follow these steps to set up your account:
Create an Account:
- Visit Telemetry Harbor and sign up for a new account.
- Create an Account:Visit Telemetry Harbor and sign up for a new account.
Create a New Harbor:
- From your dashboard, click Create New Harbor
- Name it something descriptive like "ESP32_Environmental_Monitor"
- Select the harbor type as General and Specification Free
- Create a New Harbor:From your dashboard, click Create New HarborName it something descriptive like "ESP32_Environmental_Monitor"Select the harbor type as General and Specification Free
Generate an API Key:
- Navigate to "View Details" for your created harbor
- Click "View API Key"
- Copy and save your API Key securely - you'll need it for your ESP32 code
- Note your Harbor ID from the API Endpoint
- Generate an API Key:Navigate to "View Details" for your created harborClick "View API Key"Copy and save your API Key securely - you'll need it for your ESP32 codeNote your Harbor ID from the API Endpoint
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <time.h> // For NTP time
// WiFi credentials
const char* ssid = "WIFI_SSID";
const char* password = "WIFI_PASSWORD";
// Telemetry Harbor API info
const String apiUrl = "https://telemetryharbor.com/api/v1/ingest/ingest/Harbor_ID";
const String apiKey = "API_KEY";
const String shipId = "Living Room";
const String cargoId = "Temperature";
// BME280 setup
Adafruit_BME280 bme; // I2C
#define SEALEVELPRESSURE_HPA (1013.25)
// LED setup
const int ledPin = 2; // Use built-in LED on most ESP32 boards (usually GPIO 2)
// NTP setup
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 0; // Adjust this for your timezone offset
const int daylightOffset_sec = 0;
// Time management
unsigned long previousMillis = 0;
const unsigned long intervalMillis = 60000; // 1-second interval
// Function to flash the LED
void flashLED(int times, int delayMs) {
for (int i = 0; i < times; i++) {
digitalWrite(ledPin, HIGH);
delay(delayMs);
digitalWrite(ledPin, LOW);
delay(delayMs);
}
}
// Function to connect to Wi-Fi
void connectWiFi() {
Serial.println("Connecting to WiFi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting...");
}
Serial.println("Connected to WiFi!");
flashLED(3, 200); // Flash LED 3 times quickly
}
// Function to initialize time using NTP
void initTime() {
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("Failed to obtain time from NTP server.");
while (1); // Stay here if time sync fails
}
Serial.println("Time synchronized successfully.");
}
void setup() {
Serial.begin(115200);
pinMode(ledPin, OUTPUT); // Set LED pin as output
// Initialize BME280 sensor
if (!bme.begin(0x76)) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
while (1);
}
// Connect to Wi-Fi and sync time
connectWiFi();
initTime();
}
void loop() {
// Check Wi-Fi connection
if (WiFi.status() != WL_CONNECTED) {
connectWiFi(); // Reconnect if disconnected
}
// Measure elapsed time to push data every second
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= intervalMillis) {
previousMillis = currentMillis;
const float temperatureOffset = 0; // Adjust temperature by -3°C
const float humidityOffset = 0; // Adjust humidity by +7.2%
// Read temperature and humidity
float temperature = bme.readTemperature() + temperatureOffset;
float humidity = bme.readHumidity() + humidityOffset;
// Get current time in ISO8601 format
time_t now = time(NULL);
struct tm timeinfo;
gmtime_r(&now, &timeinfo); // Convert to UTC time structure
char timeBuffer[30];
strftime(timeBuffer, sizeof(timeBuffer), "%Y-%m-%dT%H:%M:%SZ", &timeinfo); // Format time
// Create JSON payload for temperature
String tempJsonPayload = "{";
tempJsonPayload += "\"time\": \"" + String(timeBuffer) + "\",";
tempJsonPayload += "\"ship_id\": \"" + shipId + "\",";
tempJsonPayload += "\"cargo_id\": \"Temperature\",";
tempJsonPayload += "\"value\": " + String(temperature, 2);
tempJsonPayload += "}";
// Create JSON payload for humidity
String humidityJsonPayload = "{";
humidityJsonPayload += "\"time\": \"" + String(timeBuffer) + "\",";
humidityJsonPayload += "\"ship_id\": \"" + shipId + "\",";
humidityJsonPayload += "\"cargo_id\": \"Humidity\",";
humidityJsonPayload += "\"value\": " + String(humidity, 2);
humidityJsonPayload += "}";
// Send temperature data to API
HTTPClient http;
http.begin(apiUrl);
http.addHeader("X-API-Key", apiKey);
http.addHeader("Content-Type", "application/json");
int tempResponseCode = http.POST(tempJsonPayload);
if (tempResponseCode > 0) {
Serial.println("Temperature data sent successfully! Response:");
Serial.println(http.getString());
flashLED(1, 300); // Flash LED for successful API request
} else {
Serial.print("Error sending temperature data. HTTP Response code: ");
Serial.println(tempResponseCode);
}
http.end();
// Send humidity data to API
http.begin(apiUrl); // Reinitialize HTTPClient for humidity request
http.addHeader("X-API-Key", apiKey);
http.addHeader("Content-Type", "application/json");
int humidityResponseCode = http.POST(humidityJsonPayload);
if (humidityResponseCode > 0) {
Serial.println("Humidity data sent successfully! Response:");
Serial.println(http.getString());
flashLED(1, 300); // Flash LED for successful API request
} else {
Serial.print("Error sending humidity data. HTTP Response code: ");
Serial.println(humidityResponseCode);
}
http.end();
}
}
Select the Correct Board:
- Go to Tools > Board and select your ESP32 board model
- Select the correct COM port under Tools > Port
- Select the Correct Board:Go to Tools > Board and select your ESP32 board modelSelect the correct COM port under Tools > Port
Configure the Code:
- Replace the WiFi SSID and password with your network credentials
- Update the Telemetry Harbor API URL and API key with your account details
- Adjust the sensor reading interval if needed (default is 60 seconds)
- Configure the Code:Replace the WiFi SSID and password with your network credentialsUpdate the Telemetry Harbor API URL and API key with your account detailsAdjust the sensor reading interval if needed (default is 60 seconds)
Upload the Code:
- Click the Upload button (→) in Arduino IDE
- Wait for the compilation and upload to complete
- Upload the Code:Click the Upload button (→) in Arduino IDEWait for the compilation and upload to complete
Verify Operation:
- Open the Serial Monitor (Tools > Serial Monitor) set to 115200 baud
- Check for successful WiFi connection and sensor initialization
- Confirm data is being sent to Telemetry Harbor
- Verify Operation:Open the Serial Monitor (Tools > Serial Monitor) set to 115200 baudCheck for successful WiFi connection and sensor initializationConfirm data is being sent to Telemetry Harbor
Once your ESP32 begins transmitting data, you can create powerful visualizations in Telemetry Harbor through its integrated Grafana dashboards:
Access Grafana Credentials:
- Go back to the Harbor Details page
- Copy the Grafana Password shown on this page
- Click on the Grafana Endpoint link provided
- Access Grafana Credentials:Go back to the Harbor Details pageCopy the Grafana Password shown on this pageClick on the Grafana Endpoint link provided
Login to Grafana:
- Use your Grafana Username (this will be the same as your Telemetry Harbor email)
- Enter the Grafana Password you copied earlier
- Login to Grafana:Use your Grafana Username (this will be the same as your Telemetry Harbor email)Enter the Grafana Password you copied earlier
Navigate to Dashboards:
- In the left sidebar, click on Dashboards
- Select the Comprehensive Telemetry Dashboard (this is the demo dashboard provided by Telemetry Harbor)
- Navigate to Dashboards:In the left sidebar, click on DashboardsSelect the Comprehensive Telemetry Dashboard (this is the demo dashboard provided by Telemetry Harbor)
Configure Your Dashboard View:
- Choose your data source (which will be your harbor)
- Use the filters to view data based on
ship_id
andcargo_id
- Select appropriate time ranges to view your sensor history
- Configure Your Dashboard View:Choose your data source (which will be your harbor)Use the filters to view data based on
ship_id
andcargo_id
Select appropriate time ranges to view your sensor history
Your ESP32 is now up and running with the BME280 sensor, streaming live temperature data to Telemetry Harbor. With this setup, you can keep an eye on environmental changes in real time. Want to take it further? Try adding more sensors, setting up alerts for temperature spikes, or even building a full monitoring system. The possibilities are endless.
Comments
Please log in or sign up to comment.