In this ninth part of our IoT project series, we explore environmental safety monitoring with ESP32-based gas detection systems. This project demonstrates MQ-series sensor integration, threshold-based safety alerting, multi-level LED indicators, and advanced dashboard visualization with real-time safety monitoring capabilities.
Project OverviewThis ESP32 project implements a comprehensive gas detection and safety monitoring system with MQTT communication and intelligent multi-level alerting. It features an MQ2 gas sensor for combustible gas detection, three-tier LED warning system, buzzer alerts for critical conditions, and real-time monitoring with safety threshold management. The Wokwi simulation shows a professional safety monitoring setup:
- MQ2 Gas Sensor: Analog input (GPIO 32) for detecting combustible gases (LPG, propane, methane)
- Three-Tier LED System: Green (GPIO 12), Yellow (GPIO 14), Red (GPIO 27) for visual safety indication
- Buzzer Alert: PWM-driven buzzer (GPIO 13) for audio warnings at critical gas levels
- Safety Thresholds: 300-1000 PPM range with configurable warning (600 PPM) and danger (900 PPM) levels
- Voltage Monitoring: Real-time sensor voltage measurement for diagnostic purposes
The firmware uses a safety-focused approach with five core components. Connection Management handles WiFi with retry logic, MQTT with authentication, and automatic reconnection. Sensor Processing provides MQ2 analog reading with noise simulation, PPM conversion using linear mapping, and voltage calculation for diagnostics. Safety Logic implements three-tier threshold monitoring, LED control based on gas concentration, and PWM buzzer activation for critical alerts. Alert System features immediate visual feedback, audio warnings for danger levels, and JSON data transmission. System Activation includes MQTT-based enable/disable, status reporting, and 1-second update intervals.
MQTT Communication Protocol
The system uses structured MQTT topics for safety monitoring:
arduino/gas
- JSON-formatted gas concentration and voltage datamqtt/request
- System activation and status requestsmqtt/response
- Device status and health reports
Message Formats:
Gas Data: {"gas_ppm": 450, "voltage": 2.15}
Status Response: "Board : ESP32 Status : Connected"
Status Request: "status_request"
System Control: "TurnOFF"
Key Firmware Features
MQ2 Sensor Reading with Noise Simulation:
int readGasSensor() {
int raw_value = analogRead(Pin);
// Add noise simulation for realistic readings
raw_value += random(-50, 50);
raw_value = constrain(raw_value, 0, 4095);
return raw_value;
}
int convertToPPM(int raw_value) {
// Linear mapping from ADC range to PPM range
return map(raw_value, 0, 4095, MIN_PPM, MAX_PPM);
}
Three-Tier Safety Alert System:
void loop() {
if (systemActive) {
// Control LEDs and buzzer based on gas levels
if (gas_value_ppm > 900) {
// HIGH DANGER - Red LED + Buzzer
digitalWrite(GREEN_LED, LOW);
digitalWrite(YELLOW_LED, LOW);
digitalWrite(RED_LED, HIGH);
ledcWrite(BUZZER_CHANNEL, 128); // 50% duty cycle
Serial.println("ALERT: High gas concentration detected!");
}
else if (gas_value_ppm > 600) {
// MEDIUM DANGER - Yellow LED
digitalWrite(GREEN_LED, LOW);
digitalWrite(YELLOW_LED, HIGH);
digitalWrite(RED_LED, LOW);
ledcWrite(BUZZER_CHANNEL, 0);
}
else {
// SAFE - Green LED
digitalWrite(GREEN_LED, HIGH);
digitalWrite(YELLOW_LED, LOW);
digitalWrite(RED_LED, LOW);
ledcWrite(BUZZER_CHANNEL, 0);
}
}
}
JSON Data Publishing with Diagnostics:
// Create JSON payload with gas concentration and voltage
String gasData = "{\"gas_ppm\":" + String(gas_value_ppm) +
",\"voltage\":" + String(voltage_value, 2) + "}";
if (client.connected()) {
client.publish("arduino/gas", gasData.c_str());
}
PyQt5 Dashboard IntegrationThe dashboard interface provides comprehensive safety monitoring through six main sections:
- MQTT Status Panel - Connection monitoring with LED indicators
- Gas Concentration Display - LCD-style digital readouts for PPM and voltage values
- Three-Tier LED Indicators - Visual safety status with gradient LED styling
- Gas Concentration Plot - PyQtGraph real-time plotting with threshold visualization
- Voltage Monitoring Plot - Separate sensor voltage tracking for diagnostics
- Safety Threshold Management - Configurable warning (500 PPM) and danger (900 PPM) levels
Signal-Based Architecture
Signal-slot mechanism for thread-safe safety monitoring:
class GasSensorController(QObject):
# Signal definitions for thread-safe UI updates
gas_data_changed = pyqtSignal(float, float)
led_status_changed = pyqtSignal(float)
board_status_changed = pyqtSignal(str, str, str)
plot_update_signal = pyqtSignal(float, float)
error_state_signal = pyqtSignal()
Thread-Safe Safety Level Processing:
@pyqtSlot(float)
def update_gas_leds_ui(self, gas_ppm):
if gas_ppm > self.danger_threshold:
self.apply_gas_led_styles("danger")
elif gas_ppm > self.warning_threshold:
self.apply_gas_led_styles("warning")
else:
self.apply_gas_led_styles("safe")
def apply_gas_led_styles(self, status):
led_styles = {
"active_red": """
QLabel {
background-color: qradialgradient(cx:0.5, cy:0.5, radius: 0.6,
fx:0.5, fy:0.5, stop:0 #FF0000, stop:1 #8B0000);
border: 2px solid gray;
border-radius: 25px;
}
""",
"active_green": """
QLabel {
background-color: qradialgradient(cx:0.5, cy:0.5, radius: 0.6,
fx:0.5, fy:0.5, stop:0 #00FF00, stop:1 #008800);
border: 2px solid gray;
border-radius: 25px;
}
"""
}
MQTT Message Handling
JSON Gas Data Processing:def handle_gas_message(self, topic, payload):
if topic == MQTT_TOPIC_GAS:
try:
sensor_data = json.loads(payload)
# Extract data with fallback values
gas_ppm = sensor_data.get("gas_ppm", 0)
voltage = sensor_data.get("voltage", 0)
# Update UI through signals
self.gas_data_changed.emit(gas_ppm, voltage)
self.led_status_changed.emit(gas_ppm)
self.plot_update_signal.emit(gas_ppm, voltage)
except json.JSONDecodeError as e:
print(f"JSON decode error: {e}")
self.error_state_signal.emit()
Status Monitoring with Safety Context:
def handle_status_response_message(self, topic, payload):
try:
if "Board :" in payload and "Status :" in payload:
board_part, status_part = payload.split("Status :")
board_name = board_part.replace("Board :", "").strip()
status = status_part.strip().lower()
if status == "connected":
self.board_status_changed.emit(board_name, "Connected", "green")
self.board_led_status_changed.emit("green")
self.status_received = True
except Exception as e:
print(f"Error processing status message: {e}")
Control Flow Analysis
Safety Monitoring Flow:
- Gas Detection: MQ2 sensor continuously monitors combustible gas concentration
- Data Processing: Raw ADC values converted to PPM with noise filtering
- Safety Assessment: Three-tier threshold comparison for immediate hazard evaluation
- Alert Activation: LED indicators and buzzer alerts based on safety levels
- Dashboard Update: Real-time visualization with safety status indication
Emergency Response Flow:
- Critical Detection: Gas concentration exceeds 900 PPM danger threshold
- Immediate Alert: Red LED activation and buzzer alarm at 50% duty cycle
- Data Transmission: Emergency-level gas data sent via MQTT to dashboard
- Visual Feedback: Dashboard LED indicators immediately reflect critical status
- Continuous Monitoring: System maintains alert state until gas levels normalize
Advanced Features
Dual-Plot Safety Visualization:
def init_plots(self):
# Gas concentration plot with safety context
self.gas_plot.setTitle("Gas Concentration (ppm)", color='w', size='14pt', bold=True)
self.gas_plot.setLabel('left', 'Concentration (ppm)')
self.gas_plot.showGrid(x=True, y=True)
self.gas_curve = self.gas_plot.plot(pen='r', name="Gas PPM")
# Voltage diagnostic plot
self.voltage_plot.setTitle("Sensor Voltage (V)", color='w', size='14pt', bold=True)
self.voltage_plot.setLabel('left', 'Voltage (V)')
self.voltage_curve = self.voltage_plot.plot(pen='b', name="Voltage")
Gradient LED Styling for Safety Indication:
"active_yellow": """
QLabel {
background-color: qradialgradient(cx:0.5, cy:0.5, radius: 0.6,
fx:0.5, fy:0.5, stop:0 #FFFF00, stop:1 #CCCC00);
border: 2px solid gray;
border-radius: 25px;
min-width: 50px;
min-height: 50px;
}
"""
Configurable Safety Thresholds:
def __init__(self, mqtt_client, ui):
# Gas concentration thresholds
self.danger_threshold = 900 # PPM for red alert + buzzer
self.warning_threshold = 500 # PPM for yellow warning
self.max_data_points = 100 # History buffer size
Complete System Safety Reset:
def deactivate(self):
# Send shutdown command
self.mqtt_client.publish(MQTT_TOPIC_MQTT_Rq, "TurnOFF")
# Reset all safety indicators
self.apply_gas_led_styles("safe")
self.board_status_changed.emit("Unknown", "Disconnected", "red")
# Clear all monitoring data
self.gas_data.clear()
self.voltage_data.clear()
self.time_data.clear()
# Completely reset plots with empty curves
if hasattr(self, 'gas_plot'):
self.gas_plot.clear()
self.gas_curve = self.gas_plot.plot(pen='r', name="Gas PPM")
self.gas_curve.setData([], [])
ConclusionThis ESP32 gas detection and safety monitoring system demonstrates advanced environmental safety sensing with multi-level alerting, real-time visualization, and comprehensive hazard management capabilities. The system provides reliable combustible gas detection with immediate visual and audio alerts, professional dashboard monitoring, and configurable safety thresholds suitable for industrial and residential safety applications.
This concludes our comprehensive IoT project series, showcasing the progression from basic LED control to advanced safety monitoring systems with professional-grade sensor integration, real-time communication, and sophisticated user interfaces.
That's all!If you have any questions or suggestions, don’t hesitate to leave a comment below.
Comments