#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <DHT.h>
// WiFi credentials for Wokwi Simulator
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// ====================================================================================
// CRITICAL: Update this URL with your public server address (e.g., from cloudflared or ngrok).
// The address 127.0.0.1 will NOT work from inside the Wokwi simulator.
// Example (cloudflared): "https://your-unique-name.trycloudflare.com/api/receive-data/"
// ====================================================================================
const char* apiEndpoint = "http://YOUR_PUBLIC_SERVER_ADDRESS/api/receive-data/";
// --- Sensor Pin Definitions ---
// Use `const int` for type safety, which is generally preferred in C++.
const int MQ2_PIN = 36; // VP pin on ESP32 DevKit V1
const int DHT_PIN = 2; // D2 pin (GPIO2)
#define DHT_TYPE DHT22
// --- Sensor Objects ---
DHT dht(DHT_PIN, DHT_TYPE);
// --- Device Configuration ---
const String deviceId = "WOKWI_MQ2_001";
const String sensorName = "Kitchen Smoke Detector";
const String sensorType = "MQ2";
const String location = "kitchen";
void setup() {
Serial.begin(115200);
Serial.println("Starting ESP32 MQ2 Gas Sensor...");
// Configure ADC for ESP32
analogReadResolution(12); // 12-bit resolution (0-4095)
analogSetAttenuation(ADC_11db); // Full 0-3.3V range
// Initialize DHT sensor
dht.begin();
// --- Connect to WiFi ---
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nConnected to WiFi");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
void loop() {
Serial.println("\n--- Reading Sensors ---");
// --- Read MQ2 Sensor ---
int analogValue = analogRead(MQ2_PIN);
float voltage = analogValue * (3.3 / 4095.0); // Convert analog reading to voltage
// Calculate gas concentration by passing the pre-calculated voltage.
float gasConcentration = calculateGasConcentration(voltage);
// --- Read DHT22 Sensor ---
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
// Handle NaN (Not a Number) readings from DHT sensor, which indicates a failed read.
if (isnan(temperature)) {
temperature = 25.0; // Use a default value
Serial.println("Warning: DHT22 temperature reading failed, using default value.");
}
if (isnan(humidity)) {
humidity = 50.0; // Use a default value
Serial.println("Warning: DHT22 humidity reading failed, using default value.");
}
// --- Print Readings to Serial Monitor for Debugging ---
Serial.println("Sensor Readings:");
Serial.println(" Analog Value: " + String(analogValue));
Serial.println(" Voltage: " + String(voltage, 2) + "V");
Serial.println(" Gas Concentration: " + String(gasConcentration, 2) + " PPM");
Serial.println(" Temperature: " + String(temperature, 1) + "°C");
Serial.println(" Humidity: " + String(humidity, 1) + "%");
// --- Send Data to API ---
sendSensorData(gasConcentration, analogValue, voltage, temperature, humidity);
// Wait 30 seconds before the next reading cycle
Serial.println("Waiting 30 seconds for next reading...");
delay(30000);
}
/**
* @brief Calculates gas concentration based on sensor voltage.
* @param voltage The voltage read from the MQ2 sensor's analog output.
* @return The calculated gas concentration in PPM (parts per million).
*/
float calculateGasConcentration(float voltage) {
// Prevent division by zero if voltage is 0.
if (voltage <= 0) return 0;
// Calculate sensor resistance Rs (assuming a 10kOhm load resistor RL)
// Formula derived from voltage divider: Vout = Vin * (RL / (Rs + RL))
float resistance = (3.3 - voltage) / voltage * 10000.0;
// MQ2 calibration formula for smoke detection.
// NOTE: These values are approximations. For accurate readings, you must
// calibrate the sensor against known gas concentrations.
// The formula is derived from the log-log scale graph in the sensor datasheet.
float ppm = 613.9 * pow(resistance / 1000.0, -2.074);
// Ensure the PPM value stays within a reasonable range.
return constrain(ppm, 0, 1000);
}
/**
* @brief Sends sensor data to the Django server via an HTTP POST request.
* @param gasConc The gas concentration value.
* @param analogVal The raw analog value from the sensor.
* @param volt The calculated voltage.
* @param temp The temperature reading.
* @param hum The humidity reading.
*/
void sendSensorData(float gasConc, int analogVal, float volt, float temp, float hum) {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
http.begin(apiEndpoint);
http.addHeader("Content-Type", "application/json");
// Create JSON payload using ArduinoJson library
StaticJsonDocument<400> doc;
doc["sensor_name"] = sensorName;
doc["device_id"] = deviceId;
doc["sensor_type"] = sensorType;
doc["location"] = location;
doc["gas_concentration"] = round(gasConc * 100) / 100.0; // Round to 2 decimal places
doc["analog_value"] = analogVal;
doc["voltage"] = round(volt * 100) / 100.0;
doc["temperature"] = round(temp * 10) / 10.0; // Round to 1 decimal place
doc["humidity"] = round(hum * 10) / 10.0;
String jsonString;
serializeJson(doc, jsonString);
Serial.println("Sending data to Django API:");
Serial.println(" Endpoint: " + String(apiEndpoint));
Serial.println(" JSON Data: " + jsonString);
// Send the POST request
int httpResponseCode = http.POST(jsonString);
if (httpResponseCode > 0) {
String response = http.getString();
Serial.println("✅ HTTP Response Code: " + String(httpResponseCode));
Serial.println("📡 Response: " + response);
if (httpResponseCode == 201) {
Serial.println("✅ Data sent successfully!");
}
} else {
Serial.println("❌ Error sending data. HTTP Response Code: " + String(httpResponseCode));
Serial.println(" Check if your server is running and the endpoint URL is correct.");
}
http.end(); // Free resources
} else {
Serial.println("❌ WiFi not connected - cannot send data.");
}
}