Preview build — page text is a draft awaiting human review. Code badges come from real compiles. The flasher is real but not yet hardware-tested; the Playground is still a preview.

MQ-7 CO sensor with ESP32 DevKit V1 — divided AO and an Rs/R0 trend

Run an MQ-7 module on an ESP32 DevKit V1: 5 V heater on VIN, AO via a 10 kΩ / 20 kΩ divider to D34, and an Rs/R0 trend that needs no load-resistor value.

Arduino C++Verified — core esp32 3.3.12, 3 Nov 2026Compile-only

Community draft — report a mistake

The MQ-7 is the carbon-monoxide member of the MQ family, and CO is a real danger in Indian homes: a generator or inverter-charging setup in a closed room, a charcoal sigri during winter, or a gas geyser in a bathroom without ventilation.

On the ESP32 DevKit V1 the module runs from VIN (5 V), and its analog output reaches D34 through a 10 kΩ / 20 kΩ divider, because AO can rise to 5 V and the ESP32’s pins stop at 3.3 V. The sketch warms the heater for three minutes, takes a clean-air reference, then prints the sensor’s Rs/R0 ratio and lights the blue LED when it falls well below the start value.

Not a CO alarm. CO can kill while you sleep. Use this only as an extra, experimental indicator next to a certified CO detector — never as the only protection near a generator, geyser or stove.

Wiring

ESP32 DevKit V1Only the pins used are shown · 3.3 V logicMQ-7 carbon monoxide (CO) sensor module10k│20kD34GNDVINVCCGNDDO (not connected)AO
Also needed: 10 kΩ and 20 kΩ resistors, A certified CO alarm for any real room — this build is only an extra indicator.
Every connection
ESP32 DevKit V1MQ-7 carbon monoxide (CO) sensor moduleWireNotes
VINVCCredHeater and load circuit both need 5 V (about 150 mA). VIN carries USB 5 V.
GNDGNDblack
D34AOyellowVia 10 kΩ / 20 kΩ divider — 10 kΩ from AO to D34, 20 kΩ from D34 to GND. AO can reach ~5 V; the pin sees at most 3.33 V.

5 V (heater: about 150 mA) part, 3.3 V board. The heater needs 5 V. AO can reach about 5 V, so on ESP32 and Pico feed AO through a 10 kΩ / 20 kΩ divider to stay under 3.3 V. DO swings to VCC too — divide it on 3.3 V boards.

Board quirks

  • The cheap module skips the MQ-7’s heater cycle. The datasheet heats at 5 V for 60 s, then 1.4 V for 90 s, and reads CO at the end of the low phase. The common red module ties the heater to a constant 5 V, so the sensor reacts to CO and other gases. This guide treats it honestly as a relative “bad air is rising” indicator, not a CO meter in ppm.
  • The sketch reports Rs/R0, the ratio the datasheet curves use. Because Rs = RL × (5 V − V) / V, the load resistor RL cancels out of the ratio — you don’t need to read the tiny SMD resistor on your module. A falling ratio means more gas.
  • R0 is taken at start-up, so start the board in clean air (outdoors or by an open window). Starting next to a running generator makes everything afterwards look “clean”.
  • D34 is an ADC1 pin: readings keep working with Wi-Fi on, which you need for a phone alert later. ADC2 pins (D4, D13, D25–D27…) don’t.
  • USB 5 V is rarely exactly 5.0 V (often 4.7–5.1 V). That shifts the ratio a little; for a better number measure VIN with a multimeter and set VC in the sketch.
  • For a datasheet-style reading, the heater must be switched separately from the load circuit (a logic-level MOSFET on the heater and a modified module). That is beyond this guide — and even then, a DIY sensor is not a CO alarm.

Code

mq7-esp32.inoArduino C++Open in PlaygroundOpen in PlaygroundFlash
// MQ-7 CO sensor module on an ESP32 DevKit V1 — relative "bad air" trend as an Rs/R0 ratio.
// VCC → VIN (5 V heater), GND → GND, AO → 10 kΩ → D34 (GPIO34), 20 kΩ from D34 to GND.
// The common module keeps the heater at a constant 5 V, so this is a relative indicator,
// not a CO measurement in ppm and NOT a CO alarm. Fit a certified CO detector for safety.

constexpr uint8_t MQ_PIN = 34;     // ADC1_CH6: works with Wi-Fi on
constexpr uint8_t LED_PIN = 2;     // on-board blue LED
constexpr float DIVIDER = 1.5f;    // (10 kΩ + 20 kΩ) / 20 kΩ
constexpr float VC = 5.0f;         // module supply (USB 5 V — real value 4.7–5.1 V)
constexpr float ALARM_RATIO = 0.6f;  // Rs/R0 below this = clearly more gas than at start-up

float r0Term = 0;  // (VC - V0) / V0 in clean air; RL cancels out of the ratio

float readAoVolts() {
  uint32_t sum = 0;
  for (int i = 0; i < 32; i++) sum += analogReadMilliVolts(MQ_PIN);
  return (sum / 32.0f) / 1000.0f * DIVIDER;
}

// Rs = RL × (VC − V) / V, so Rs/R0 = [(VC − V)/V] / [(VC − V0)/V0] — no need to know RL.
float rsTerm(float v) { return (VC - v) / max(v, 0.01f); }

void setup() {
  Serial.begin(115200);
  pinMode(LED_PIN, OUTPUT);
  Serial.println("MQ-7 on GPIO34 — heater warming up (3 min). Start in clean outdoor air.");
  for (int s = 180; s > 0; s -= 30) {
    Serial.printf("  %d s…\n", s);
    delay(30000);
  }
  float sum = 0;
  for (int i = 0; i < 20; i++) {
    sum += readAoVolts();
    delay(500);
  }
  float v0 = sum / 20;
  r0Term = rsTerm(v0);
  Serial.printf("Clean-air reference: AO %.2f V (R0 taken here)\n", v0);
}

void loop() {
  static float smooth = -1;
  float v = readAoVolts();
  smooth = smooth < 0 ? v : smooth * 0.8f + v * 0.2f;  // slow the reading a little
  float ratio = rsTerm(smooth) / r0Term;               // falls as CO (and other gases) rise
  bool alarm = ratio < ALARM_RATIO;
  digitalWrite(LED_PIN, alarm);
  Serial.printf("AO %.2f V  Rs/R0 %.2f%s\n", smooth, ratio, alarm ? "  RISING GAS — ventilate, check a real CO alarm" : "");
  delay(2000);
}

Expected serial output

Serial Monitor · 115200Output
MQ-7 on GPIO34 — heater warming up (3 min). Start in clean outdoor air.
  180 s…
Clean-air reference: AO 0.42 V (R0 taken here)
AO 0.43 V  Rs/R0 0.97
AO 0.91 V  Rs/R0 0.41  RISING GAS — ventilate, check a real CO alarm

Common errors

Rs/R0 stays near 1.0 even next to exhaust smoke

Expected to a degree with a constant-5 V heater: the sensor is far less CO-selective than the datasheet suggests. Check the module’s power LED (heater on), and let a new sensor burn in for 48 hours.

Ratio is below 0.6 right after start-up

R0 was taken before the heater settled or in dirty air. Leave it powered for 10 minutes in fresh air, then press EN to take a new reference.

AO reads 0 V

The 10 kΩ and 20 kΩ are swapped, or the heater isn’t powered. 10 kΩ goes from AO to D34; 20 kΩ from D34 to GND.

↑↓ to move · Enter to open