#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <DHT.h>
#include <MQUnifiedsensor.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
/************************Hardware Related Macros************************************/
#define Board ("ESP-32")
#define Pin (32) //Analog input 3 of your arduino
/***********************Software Related Macros************************************/
#define Type ("MQ-2") //MQ2
#define Voltage_Resolution (3.3)
#define ADC_Bit_Resolution (12) // For arduino UNO/MEGA/NANO
#define RatioMQ2CleanAir (9.83) //RS / R0 = 9.83 ppm
#define DHTPIN 26
#define DHTTYPE DHT22
#define LDR_PIN 35
#define STATUS_LED 2 // Built-in LED on most ESP32 boards
/*****************************Globals***********************************************/
MQUnifiedsensor MQ2(Board, Voltage_Resolution, ADC_Bit_Resolution, Pin, Type);
LiquidCrystal_I2C lcd(0x27, 16, 2);
DHT dht(DHTPIN, DHTTYPE);
// WiFi credentials
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// MQTT Broker settings
const char* mqtt_server = "broker.hivemq.com"; // Public MQTT broker
const int mqtt_port = 1883;
const char* mqtt_topic = "esp32/data";
const char* mqtt_client_id = "ESP32Client";
// Set up WiFi and MQTT clients
WiFiClient espClient;
PubSubClient client(espClient);
// Sensor values
int valor_gas = 0;
float temperature = 0;
float humidity = 0;
float lux = 0;
float Ph =0;
float soil_hum =0;
int gas_level = 0; // Added for compatibility with your publish function
const float TEMP_THRESHOLD_HIGH = 30.0;
const float GAMMA = 0.7;
const float RL10 = 33;
// Timer for sending data
unsigned long previousMillis = 0;
const long interval = 10000; // Send data every 10 seconds
void setup() {
// Initialize serial communication
Serial.begin(9600);
// Initialize status LED
pinMode(STATUS_LED, OUTPUT);
digitalWrite(STATUS_LED, LOW);
// Initialize DHT sensor
dht.begin();
// Initialize LCD
lcd.init();
lcd.begin(16, 2);
lcd.clear();
lcd.backlight();
lcd.print("PRACTICA");
delay(1000);
lcd.clear();
lcd.print("SENSADO LM35");
lcd.setCursor(0,1);
lcd.print("CURSO 1 ");
delay(1000);
lcd.clear();
// Initialize MQ2 sensor
MQ2.setRegressionMethod(1); //_PPM = a*ratio^b
MQ2.setA(574.25); MQ2.setB(-2.222); // Configure the equation to calculate LPG concentration
Serial.print("Calibrating please wait.");
float calcR0 = 0;
for(int i = 1; i<=10; i ++)
{
MQ2.update(); // Update data, the arduino will read the voltage from the analog pin
calcR0 += MQ2.calibrate(RatioMQ2CleanAir);
Serial.print(".");
}
MQ2.setR0(calcR0/10);
Serial.println("R0 = " + String(calcR0/10));
lcd.clear();
lcd.setCursor(0,0);
lcd.print("MQ2 = ");
lcd.print(calcR0/10);
delay(500);
if(isinf(calcR0)) {
Serial.println("Warning: Connection issue, R0 is infinite (Open circuit detected) please check your wiring and supply");
while(1);
}
if(calcR0 == 0) {
Serial.println("Warning: Connection issue found, R0 is zero (Analog pin shorts to ground) please check your wiring and supply");
while(1);
}
// Setup WiFi
setup_wifi();
// Setup MQTT
client.setServer(mqtt_server, mqtt_port);
client.setCallback(callback);
MQ2.serialDebug(true);
}
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("Connecting to WiFi: ");
Serial.println(ssid);
displayMessage("Connecting WiFi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
displayMessage("WiFi connected!");
delay(1000);
}
void reconnect() {
// Loop until we're reconnected to the MQTT broker
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
displayMessage("Connecting MQTT...");
// Attempt to connect
if (client.connect(mqtt_client_id)) {
Serial.println("connected");
displayMessage("MQTT connected!");
delay(1000);
// Subscribe to topics if needed
// client.subscribe("sensor/commands");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
displayMessage("MQTT failed!");
delay(5000);
}
}
}
void callback(char* topic, byte* payload, unsigned int length) {
// Handle incoming messages here
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
String message = "";
for (int i = 0; i < length; i++) {
message += (char)payload[i];
}
Serial.println(message);
// You can add commands handling here
// if (String(topic) == "sensor/commands") {
// // Process commands
// }
}
void displayMessage(const char* message) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(message);
}
// Using your custom MQTT publish function
void publish_mqtt_data() {
StaticJsonDocument<256> doc;
doc["nhiet_do"] = temperature;
doc["do_am"] = humidity;
doc["nong_do_khoi"] = gas_level;
doc["cuong_do_sang"] = lux;
doc["do_PH"] = Ph;
doc["do_am_dat"] = soil_hum;
char buffer[256];
serializeJson(doc, buffer);
if (client.publish(mqtt_topic, buffer)) {
Serial.println("MQTT published");
delay(100);
} else {
Serial.println("MQTT publish failed");
}
}
void readSensors() {
// Read MQ2 sensor
MQ2.update();
MQ2.readSensor();
// Read gas value
valor_gas = analogRead(Pin);
valor_gas = map(valor_gas, 0, 4095, 0, 100);
gas_level = valor_gas; // Set gas_level for MQTT publishing
// Read temperature and humidity
temperature = dht.readTemperature();
humidity = dht.readHumidity();
// Read light sensor
int analogValue = analogRead(LDR_PIN);
float voltage = analogValue / 4096.0 * 3.3;
float resistance = 2000 * voltage / (1 - voltage / 3.3);
lux = pow(RL10 * 1e3 * pow(10, GAMMA) / resistance, (1 / GAMMA));
Ph = random(5.5,7.7);
soil_hum = random(40,100);
// Print to serial
Serial.println("-------- Sensor Readings --------");
Serial.println("Gas: " + String(gas_level) + "%");
Serial.println("Temperature: " + String(temperature) + "°C");
Serial.println("Humidity: " + String(humidity) + "%");
Serial.println("Light: " + String(lux) + " lux");
Serial.println("PH: " + String(Ph) + " Ph");
Serial.println("Soil humidity: " + String(soil_hum) + " %");
Serial.println("---------------------------------");
}
void updateLCD() {
// Clear the LCD and update with new values
lcd.clear();
// First row - Gas sensor value and light
lcd.setCursor(0, 0);
lcd.print("G:");
lcd.print(gas_level);
lcd.print("% L:");
lcd.print((int)lux);
lcd.print("lx");
// lcd.print("% SH:");
// lcd.print((int)soil_hum);
// lcd.print("%");
// Second row - Temperature and humidity
lcd.setCursor(0, 1);
lcd.print("T:");
lcd.print(temperature, 1);
lcd.print("C H:");
lcd.print(humidity, 0);
lcd.print("%");
lcd.print("PH:");
lcd.print(Ph);
lcd.print("lx");
}
void loop() {
// Ensure MQTT connection
if (!client.connected()) {
reconnect();
}
client.loop();
// Read all sensors
readSensors();
// Update the LCD with current readings
updateLCD();
// Check if it's time to send data to MQTT broker
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
publish_mqtt_data(); // Use your custom publish function
}
delay(500); // Update LCD every 500ms
}