Monochrome, print‑ready documentation. Focused on reproducibility, wiring correctness, timing, and payload contracts.
This firmware reads temperature and relative humidity from a DHT11 sensor on an ESP32, then issues two back‑to‑back HTTP POST requests once per minute to a Flask endpoint on the local network. Each POST contains one measurement:
The route persists records into a database table readings(sensor_type, plant_id, reading).
| Item | Notes |
|---|---|
| ESP32 DevKit (ESP‑WROOM‑32 or equivalent) | 3.3 V logic, integrated Wi‑Fi |
| DHT11 sensor module | Prefer a module with onboard 10 kΩ pull‑up on DATA |
| Jumper wires | Male‑to‑female recommended if module header pins |
| USB cable | For power and flashing |
| DHT11 | ESP32 | Notes |
|---|---|---|
| VCC | 3V3 | DHT11 supports 3.3–5 V. Use 3V3 on ESP32. |
| GND | GND | Common ground required. |
| DATA | GPIO 4 (configurable) | Define via #define DHT_PIN 4. |
If using a bare DHT11 (not a module), add a 10 kΩ pull‑up from DATA to 3V3.
| Wi‑Fi SSID | YOUR_WIFI_SSID |
|---|---|
| Wi‑Fi Password | YOUR_WIFI_PASSWORD |
| HTTP Method | POST |
| Content‑Type | application/json |
| Endpoint | http://192.168.1.10:5001/add_data |
| Timeout | 5 s (client‑side) |
| Interval | Every 60 s, two consecutive posts per cycle |
The Flask route expects JSON keys shown below. plant_id is an integer in this build.
{
"sensor_type": "dht11_temp_f", // or "dht11_temp_c" if USE_FAHRENHEIT=false
"reading": 73.00, // float
"plant_id": 1 // int
}
{
"sensor_type": "dht11_humidity_pct",
"reading": 45.00,
"plant_id": 1
}
Server response 200/201 indicates success; other codes are logged to Serial.
| Parameter | Value | Notes |
|---|---|---|
| POST interval | 60 s | Two HTTP requests per interval |
| DHT sample rate | ≤ 1 Hz | Vendor guidance; minute spacing is safe |
| HTTP timeout | 5 s | Client abort if server unresponsive |
| Loop idle | 25 ms | Cooperative multitasking |
/*
ESP32 + DHT11 -> Flask JSON (back-to-back posts each minute)
Route expects JSON:
{ "sensor_type": "<string>", "reading": <float>, "plant_id": <int> }
Posts in this order each cycle:
1) sensor_type = "dht11_temp_c" (or "_f" if USE_FAHRENHEIT = true)
2) sensor_type = "dht11_humidity_pct"
Library deps (Arduino Library Manager):
- "DHT sensor library" by Adafruit
*/
#include <WiFi.h>
#include <HTTPClient.h>
#include <DHT.h>
// ========= USER CONFIG =========
const char* WIFI_SSID = "YOUR_WIFI_SSID"; // e.g. "YOUR_WIFI_SSID"
const char* WIFI_PASS = "YOUR_WIFI_PASSWORD"; // e.g. "YOUR_WIFI_PASSWORD"
// Flask route
const char* SERVER_URL = "http://192.168.1.10:5001/add_data";
// Identify the plant in your DB
const int PLANT_ID = 1;
// DHT wiring and type
#define DHT_PIN 4 // <-- set to your GPIO
#define DHT_TYPE DHT11 // DHT11 module
// Units
#define USE_FAHRENHEIT true // true => post temp in °F with type "dht11_temp_f"
// Interval
constexpr unsigned long POST_INTERVAL_MS = 60UL * 1000UL;
// ===============================
// Sensor types for route
const char* SENSOR_TYPE_TEMP_C = "dht11_temp_c";
const char* SENSOR_TYPE_TEMP_F = "dht11_temp_f";
const char* SENSOR_TYPE_HUM = "dht11_humidity_pct";
// Globals
DHT dht(DHT_PIN, DHT_TYPE);
unsigned long lastPostMs = 0;
// Forward decls
void connectWiFi();
void ensureWiFiConnected();
bool postReading(const char* sensorType, float value);
void doOneCycle();
void setup() {
Serial.begin(115200);
delay(150);
Serial.println("\n[BOOT] ESP32 DHT11 -> Flask JSON");
// Start sensors
dht.begin();
Serial.printf("[DHT] Init on pin %d, type DHT11\n", DHT_PIN);
// Wi-Fi
connectWiFi();
// Trigger immediate first send
lastPostMs = 0;
Serial.println("[BOOT] Ready.");
}
void loop() {
ensureWiFiConnected();
unsigned long now = millis();
if (lastPostMs == 0 || (now - lastPostMs) >= POST_INTERVAL_MS) {
lastPostMs = now;
doOneCycle(); // back-to-back posts
// Explicit pause to match "back to back then pause 60s"
// Note: we also guard via millis() above, but this enforces a hard wait.
delay(POST_INTERVAL_MS);
}
delay(25);
}
void doOneCycle() {
// Read once. Adafruit DHT does an internal sample and caches briefly.
// DHT11 resolution is low; expect integers or 0.5 steps.
float h = dht.readHumidity(); // %
float tC = dht.readTemperature(); // °C
float tF = dht.readTemperature(true); // °F
// Debug prints for raw reads
Serial.printf("[READ] Raw -> humidity=%.1f%% tempC=%.1fC tempF=%.1fF\n", h, tC, tF);
// Validate readings (NaN when read fails)
if (isnan(h) || isnan(tC) || isnan(tF)) {
Serial.println("[READ] DHT read failed (NaN). Skipping this cycle.");
return;
}
// Clamp humidity to a sane range
if (h < 0.0f) h = 0.0f;
if (h > 100.0f) h = 100.0f;
// Choose temp unit
float tempValue = USE_FAHRENHEIT ? tF : tC;
const char* tempType = USE_FAHRENHEIT ? SENSOR_TYPE_TEMP_F : SENSOR_TYPE_TEMP_C;
// Back-to-back posts: temperature then humidity
bool ok1 = postReading(tempType, tempValue);
bool ok2 = postReading(SENSOR_TYPE_HUM, h);
Serial.printf("[POST] temp=%s hum=%s\n", ok1 ? "OK" : "FAIL", ok2 ? "OK" : "FAIL");
}
void connectWiFi() {
Serial.printf("[WIFI] Connecting to SSID: %s\n", WIFI_SSID);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
uint32_t start = millis();
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
if (millis() - start > 20000) {
Serial.println("\n[WIFI] Timeout. Re-attempting.");
WiFi.disconnect(true);
WiFi.begin(WIFI_SSID, WIFI_PASS);
start = millis();
}
}
Serial.printf("\n[WIFI] Connected. IP=%s\n", WiFi.localIP().toString().c_str());
}
void ensureWiFiConnected() {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("[WIFI] Disconnected. Reconnecting.");
connectWiFi();
}
}
bool postReading(const char* sensorType, float value) {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("[HTTP] No Wi-Fi. Abort POST.");
return false;
}
WiFiClient client; // HTTP (no TLS)
HTTPClient http;
http.setTimeout(5000);
if (!http.begin(client, SERVER_URL)) {
Serial.println("[HTTP] http.begin() failed");
return false;
}
http.addHeader("Content-Type", "application/json");
// Build compact JSON manually
String payload = String("{\"sensor_type\":\"") + sensorType +
"\",\"reading\":" + String(value, 2) +
",\"plant_id\":" + String(PLANT_ID) + "}";
Serial.print("[HTTP] POST payload: ");
Serial.println(payload);
int code = http.POST(payload);
Serial.printf("[HTTP] Status: %d\n", code);
String resp = http.getString();
Serial.print("[HTTP] Response: ");
Serial.println(resp);
http.end();
return (code == 201 || code == 200);
}
[BOOT] ESP32 DHT11 -> Flask JSON
[DHT] Init on pin 4, type DHT11
[WIFI] Connecting to SSID: YOUR_WIFI_SSID
....
[WIFI] Connected. IP=192.168.1.xxx
[BOOT] Ready.
[READ] Raw -> humidity=44.0% tempC=23.0C tempF=73.0F
[HTTP] POST payload: {"sensor_type":"dht11_temp_f","reading":73.00,"plant_id":1}
[HTTP] Status: 201
[HTTP] Response: {"success": true}
[HTTP] POST payload: {"sensor_type":"dht11_humidity_pct","reading":44.00,"plant_id":1}
[HTTP] Status: 201
[HTTP] Response: {"success": true}
[POST] temp=OK hum=OK
curl -X POST -H "Content-Type: application/json" \
-d '{"sensor_type":"test","reading":1,"plant_id":1}' http://192.168.1.10:5001/add_data| Property | Value |
|---|---|
| Temp range | 0–50 °C |
| Temp accuracy | ±2 °C (typical) |
| Humidity range | 20–90% RH (non‑condensing) |
| Humidity accuracy | ±5% RH (typical) |
| Resolution | 1 °C, 1% RH |
| Sampling period | > 1 s |
| Supply | 3.3–5.0 V |