ESP32: read an MQ-2 gas sensor (the honest reading)
Wire an MQ-2 gas sensor to an ESP32 and read combustible gas concentrations. Important caveats about what MQ sensors can and cannot tell you.
The MQ-2 is the cheap gas sensor for detecting LPG, propane, methane, alcohol, and smoke. It is a $2 sensor that outputs an analog voltage proportional to gas concentration. It is also the sensor with the most misleading documentation on the internet. This tutorial is the honest version: what it can detect, what it cannot, and how to interpret the readings.
The single most important thing to know about MQ sensors: they cannot distinguish between gases. The MQ-2 responds to LPG, propane, methane, hydrogen, alcohol, and smoke all at once. The analog reading tells you “something combustible is present” but not what.
What you need
- ESP32 dev board
- MQ-2 sensor module (the breakout board with the comparator; about $2)
- 5 jumper wires
Wiring
The MQ-2 module has 4 pins: VCC, GND, DO (digital out), AO (analog out).
MQ-2 VCC -- ESP32 5V (the sensor heater needs 5V; 3.3V may not work)
MQ-2 GND -- ESP32 GND
MQ-2 AO -- ESP32 GPIO 34 (ADC1 pin)
MQ-2 DO -- (not used in this tutorial; leave disconnected)
The MQ-2’s heater draws about 150 mA. The ESP32’s 5V pin can supply this from a USB port, but it pushes the limit. For long-term projects, power the heater from a separate 5V supply.
The 24-hour warm-up
The MQ-2 needs a long warm-up before readings are stable. The heater burns off contaminants and stabilizes the sensing element. Cold-start readings are nonsense.
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("MQ-2 warming up, wait 24 hours for stable readings...");
Serial.println("Pre-warm readings will be meaningless.");
}
void loop() {
int raw = analogRead(MQ2_PIN);
Serial.print("Raw: ");
Serial.println(raw);
delay(5000);
}
After the sensor has been powered for 24 hours, the readings will stabilize. Many projects get away with 5-10 minutes of warm-up if the sensor was recently used, but for first-time use, 24 hours is the safe answer.
The code
ESP32 (Arduino)
const int MQ2_PIN = 34;
void setup() {
Serial.begin(115200);
delay(1000);
analogReadResolution(12);
Serial.println("MQ-2 sensor active (warm-up complete)");
}
void loop() {
int raw = analogRead(MQ2_PIN);
Serial.print("Raw: ");
Serial.println(raw);
delay(1000);
}
Arduino (Uno, Nano, Mega)
const int MQ2_PIN = A0; // any analog pin
void setup() {
Serial.begin(9600);
delay(1000);
Serial.println("MQ-2 sensor active (warm-up complete)");
}
void loop() {
int raw = analogRead(MQ2_PIN); // 0-1023
Serial.print("Raw: ");
Serial.println(raw);
delay(1000);
}
The Uno’s ADC is 10-bit. The threshold and calibration values from the ESP32 example need to be halved for the Uno. Take the raw value in clean air, divide by 2, and use that as your “safe” threshold.
MicroPython (ESP32 or Pico)
from machine import ADC, Pin
import time
# ESP32 ADC1: GPIO 34-39
# Pico ADC: GPIO 26-29
mq2 = ADC(Pin(34))
mq2.atten(ADC.ATTN_11DB) # full 0-3.3V range
print('MQ-2 sensor active (warm-up complete)')
while True:
raw = mq2.read_u16() >> 4 # 0-4095
print(f'Raw: {raw}')
time.sleep(1)
Raspberry Pi Python (with MCP3008)
from gpiozero import MCP3008
import time
mq2 = MCP3008(channel=0)
print('MQ-2 sensor active (warm-up complete)')
while True:
raw = int(mq2.value * 1024) # MCP3008 is 10-bit
print(f'Raw: {raw}')
time.sleep(1)
Same wiring as the soil moisture tutorial. Enable SPI on the Pi first.
What you should see
Upload. The raw value will be somewhere in the 0-4095 range. Lower means more gas (the sensor’s resistance drops as gas concentration rises).
Converting to PPM
The MQ-2 datasheet has a chart of resistance ratio vs. gas concentration. The conversion is approximate. Use the chart in the datasheet for the gas you care about.
For LPG (liquefied petroleum gas, the most common use case):
const float R0 = 10.0; // sensor resistance in clean air (calibrate per sensor)
const float RL = 5.0; // load resistance on the module (usually 5k ohm)
float readLPGppm() {
int raw = analogRead(MQ2_PIN);
float voltage = raw * 3.3 / 4095.0;
float rs = (3.3 - voltage) / voltage * RL; // sensor resistance
float ratio = rs / R0;
// From MQ-2 datasheet: ratio of 0.4 ~= 200 ppm LPG
// ratio of 0.2 ~= 1000 ppm LPG
// ratio of 0.1 ~= 5000 ppm LPG
// Approximate log-linear interpolation:
float ppm = 1000.0 * pow(0.4 / ratio, 2.3);
return ppm;
}
The formula is approximate. Real MQ-2 readings vary 20-50% from sensor
to sensor. The R0 value needs to be calibrated per sensor (the
datasheet says 10k in clean air, but real sensors vary).
Calibration in clean air
For accurate readings, calibrate the sensor in clean outdoor air or in a room with no combustible gases:
void calibrate() {
Serial.println("Calibrating MQ-2 in clean air, wait 5 minutes...");
delay(300000);
int raw = analogRead(MQ2_PIN);
float voltage = raw * 3.3 / 4095.0;
float R0 = (3.3 - voltage) / voltage * RL;
Serial.print("Calibration R0: ");
Serial.println(R0);
// Write this to EEPROM or hardcode it for future runs
}
The R0 value you measure is what to use in the conversion formula.
The “gas detected” alarm
For most projects (gas leak detection), you do not need actual PPM. You just need to know “is the gas level above some threshold”:
const int ALARM_THRESHOLD = 1500; // calibrate per environment
void loop() {
int raw = analogRead(MQ2_PIN);
if (raw < ALARM_THRESHOLD) {
Serial.println("Gas detected!");
digitalWrite(BUZZER_PIN, HIGH);
} else {
digitalWrite(BUZZER_PIN, LOW);
}
delay(500);
}
Pick a threshold based on what your sensor reads in clean air vs. in a known gas concentration. Test with a controlled source if possible (a little propane from a lighter, in a ventilated area).
What the MQ-2 cannot do
Be honest about what MQ sensors can and cannot tell you:
- Cannot distinguish gases. LPG, methane, propane, alcohol, and smoke all register similarly. Use a more specific sensor if you need to identify the gas.
- Cannot quantify accurately. PPM readings are approximate.
- Cannot detect below ~100 ppm. For lower concentrations, you need a more sensitive sensor.
- Sensor drifts over time. The MQ-2’s baseline shifts as the sensor ages. Recalibrate every few months.
- Cannot detect carbon monoxide reliably. Use an MQ-7 or a dedicated CO sensor.
For safety-critical applications (gas leak alarms, fire alarms), use the MQ-2 as a “something is wrong” indicator, not a primary safety device. Pair it with a commercial gas detector for anything that has to trigger evacuation.
What you learned
- The MQ-2 detects combustible gases (LPG, propane, methane, smoke) but cannot distinguish between them.
- It needs a 24-hour warm-up for stable readings.
- The analog output is approximate; calibrate per sensor.
- Use it as a “something is wrong” indicator, not a safety device.
When something breaks
- Readings are 0 all the time. Sensor is not powered (5V required), or the analog pin is wrong.
- Readings are 4095 all the time. Sensor is in extremely clean air (unusual), or the wiring is wrong.
- Readings fluctuate wildly. Inconsistent power, or heater is not at temperature. Wait longer.
- Sensor stops responding after a few weeks. The sensing element is contaminated. Some can be revived by baking at high temperature (about 200°C for 24 hours). Most just need replacement.
What to build next
- The PIR motion tutorial combines with this for a kitchen safety alarm that wakes on motion and checks gas.
- The book ESP32 Smart Home covers gas leak detection with multiple sensor types and a real alarm panel.
- The book ESP32 Safety Systems covers proper sensor placement, calibration, and fail-safe design.