Static snapshot — not a live app. These are saved files, not the running program. Every reading is simulated demo data, frozen at the moment of capture, and the charts are drawn from saved API responses. Buttons, forms and the 5-second live refresh do nothing here. What is for sale is the Flask source you run yourself → · All demos

ESP32 + DHT11 → Flask JSON
Design & Implementation Guide

Monochrome, print‑ready documentation. Focused on reproducibility, wiring correctness, timing, and payload contracts.

Contents

  1. Overview
  2. Bill of Materials
  3. Wiring & Power
  4. Network & Endpoint
  5. Payload Contract
  6. Build & Flash (Arduino IDE)
  7. Runtime Behavior
  8. Timing & Throughput
  9. Full Sketch
  10. Expected Serial Logs
  11. Troubleshooting
  12. Validation Checklist
  13. Security & Hardening
  14. Extensions & Variations
  15. DHT11 Quick Specs

1) Overview

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).

2) Bill of Materials

ItemNotes
ESP32 DevKit (ESP‑WROOM‑32 or equivalent)3.3 V logic, integrated Wi‑Fi
DHT11 sensor modulePrefer a module with onboard 10 kΩ pull‑up on DATA
Jumper wiresMale‑to‑female recommended if module header pins
USB cableFor power and flashing

3) Wiring & Power

Connections

DHT11ESP32Notes
VCC3V3DHT11 supports 3.3–5 V. Use 3V3 on ESP32.
GNDGNDCommon ground required.
DATAGPIO 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.

Power Notes

  • Typical DHT11 draw < 2.5 mA.
  • Avoid long, noisy cables; keep DATA run short to reduce timing errors.
  • USB 5 V → ESP32 onboard regulator → 3.3 V rail.

4) Network & Endpoint

Wi‑Fi SSIDYOUR_WIFI_SSID
Wi‑Fi PasswordYOUR_WIFI_PASSWORD
HTTP MethodPOST
Content‑Typeapplication/json
Endpointhttp://192.168.1.10:5001/add_data
Timeout5 s (client‑side)
IntervalEvery 60 s, two consecutive posts per cycle

5) Payload Contract

The Flask route expects JSON keys shown below. plant_id is an integer in this build.

Temperature POST

{
  "sensor_type": "dht11_temp_f",   // or "dht11_temp_c" if USE_FAHRENHEIT=false
  "reading": 73.00,                // float
  "plant_id": 1                    // int
}

Humidity POST

{
  "sensor_type": "dht11_humidity_pct",
  "reading": 45.00,
  "plant_id": 1
}

Server response 200/201 indicates success; other codes are logged to Serial.

6) Build & Flash (Arduino IDE)

  1. Install ESP32 board support via Boards Manager (Espressif Systems).
  2. Libraries:
    • DHT sensor library by Adafruit.
    • (Optional) Adafruit Unified Sensor if prompted as a dependency.
  3. Board: ESP32 Dev Module (or your specific ESP32 variant).
  4. Set correct COM/tty port.
  5. Open the sketch and edit the User Config block:
    • WIFI_SSID, WIFI_PASS
    • SERVER_URL (defaults to your LAN host)
    • PLANT_ID (int)
    • DHT_PIN (GPIO for DATA)
    • USE_FAHRENHEIT (true/false)
  6. Compile and upload. Open Serial Monitor at 115200 baud.

7) Runtime Behavior

State Flow

  1. Boot: Start Serial → init DHT → connect Wi‑Fi.
  2. Cycle (once per minute):
    1. Read humidity, tempC, tempF.
    2. Validate (reject NaN, clamp humidity 0–100%).
    3. POST temperature JSON.
    4. POST humidity JSON.
    5. Hard delay 60 s.
  3. Connectivity: If Wi‑Fi drops, reconnect before next cycle.

Design Notes

  • DHT11 has ~1 Hz max sample rate. One read per minute is conservative and reliable.
  • Back‑to‑back posts ensure separate DB rows per measurement.
  • Client timeout 5 s avoids long stalls on server issues.

8) Timing & Throughput

ParameterValueNotes
POST interval60 sTwo HTTP requests per interval
DHT sample rate≤ 1 HzVendor guidance; minute spacing is safe
HTTP timeout5 sClient abort if server unresponsive
Loop idle25 msCooperative multitasking

9) Full Sketch

/*
  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);
}

10) Expected Serial Logs

[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

11) Troubleshooting

NaN Readings

  • Verify DATA pin and DHT_PIN match.
  • Ensure 10 kΩ pull‑up on DATA if using bare sensor.
  • Reduce cable length; keep under ~20 cm if possible.
  • Power the sensor from 3V3, not 5V, on ESP32.

Wi‑Fi Fails

  • Check SSID/password.
  • Confirm 2.4 GHz enabled on AP.
  • Observe IP printed after connect; ping from PC.

Server Unreachable

  • Open the Flask route URL from a browser on same LAN.
  • Check Flask logs for incoming requests or errors.
  • Test with 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

Outliers

  • DHT11 accuracy: ±2 °C, ±5% RH typical; do not overfit.
  • Consider debouncing spikes server‑side if needed.

12) Validation Checklist

13) Security & Hardening

14) Extensions & Variations

15) DHT11 Quick Specs

PropertyValue
Temp range0–50 °C
Temp accuracy±2 °C (typical)
Humidity range20–90% RH (non‑condensing)
Humidity accuracy±5% RH (typical)
Resolution1 °C, 1% RH
Sampling period> 1 s
Supply3.3–5.0 V