There are a ton of tutorials on how to use the MQ7 Carbon Monoxide sensor with Arduino, Raspberry Pis, and other microcontrollers but they are all making a big mistake.
Based on the sensor datasheet, it should always be preheated for a certain amount of time and most importantly, in order for it to be precise and release any CO buildup, it needs to be powered in cycles with 5V and 1.4V.
The cycle requires that the sensor is operated at 5V for 60 seconds, and then at 1.4V for 90 seconds. Only then, at the end of the 1.4V cycle, we can properly measure the CO levels, just before starting the operation again.
The commonly available modules are all basically ignoring this and they apply 5V constantly to the sensor and that really makes the reading useless in most cases. The only article that I found that does it properly is from the ESPHome website where they explain how to modify the module to remove the digital output from it and replace it with a digital control pin to control the voltage on the heater.
I attempted this modification myself and I got it to work but not without challenges, and you can see more about those challenges in the video below.
The original code can be found at the ESPHome website but below is what I ended up using myself in my setup with the addition of the DHT11 sensor.
substitutions:
mq7_name: "MQ7"
mq7_id: "mq7"
# Both pins are 3.3V compatible and can be directly connected to the ESP if you followed the heater mod tutorial
mq7_heater_pin: D2
mq7_analog_pin: A0
# Voltage divider values
mq7_low_side_resistor: "1000"
mq7_high_side_resistor: "470"
mq7_supply_voltage: "5.0V"
# Temperature / Humidity Compensation
# replace "temperature" with the id of your temperature sensor (celsius) and "humidity" with the id of your humidity sensor
temperature_sensor_id: "temperature"
humidity_sensor_id: "humidity"
# Calibration: place the sensor in clean air (outdoor) for a few hours and use the value of mq7_compensated_resistance
mq7_clean_air_compensated_resistance: "203747"
output:
- platform: gpio
pin: ${mq7_heater_pin}
id: ${mq7_id}_heater_pin
switch:
- platform: output
name: "${mq7_name} Heater"
icon: mdi:fire
entity_category: diagnostic
disabled_by_default: True
id: ${mq7_id}_heater
output: ${mq7_id}_heater_pin
interval:
- interval: 150s
then:
- switch.turn_on: ${mq7_id}_heater
- logger.log: "${mq7_name}: The sensor is heating!"
- delay: 55s
- switch.turn_off: ${mq7_id}_heater
- logger.log: "${mq7_name}: The sensor is measuring!"
- delay: 90s
- if:
condition:
- switch.is_off: ${mq7_id}_heater
then:
- component.update: ${mq7_id}_raw
- logger.log: "${mq7_name}: Done"
- switch.turn_on: ${mq7_id}_heater
- delay: 5s
sensor:
# Replace with your own temperature / humidity sensor, located near the MQ-7
# - platform: homeassistant
# id: ${temperature_sensor_id}
# entity_id: sensor.temperature
# - platform: homeassistant
# id: ${humidity_sensor_id}
# entity_id: sensor.humidity
- platform: dht
pin: D0
temperature:
id: "temperature"
name: "Temperature"
humidity:
id: "humidity"
name: "Humidity"
update_interval: 60s
- platform: adc
id: ${mq7_id}_raw
name: "${mq7_name} Voltage"
entity_category: diagnostic
disabled_by_default: True
pin: ${mq7_analog_pin}
#attenuation: auto
update_interval: never
- platform: resistance
id: ${mq7_id}_resistance
name: "${mq7_name} Resistance"
icon: mdi:omega
entity_category: diagnostic
disabled_by_default: True
sensor: ${mq7_id}_raw
configuration: UPSTREAM
resistor: ${mq7_low_side_resistor}
reference_voltage: ${mq7_supply_voltage}
filters:
- lambda: return (x - ${mq7_high_side_resistor});
on_value:
then:
- component.update: ${mq7_id}_compensated_resistance
- platform: template
id: ${mq7_id}_compensated_resistance
name: "${mq7_name} Compensated Resistance"
icon: mdi:omega
entity_category: diagnostic
unit_of_measurement: Ω
lambda: |-
return (id(${mq7_id}_resistance).state / ( -0.01223333 * id(${temperature_sensor_id}).state -0.00609615 * id(${humidity_sensor_id}).state + 1.70860897));
update_interval: never
on_value:
then:
- component.update: ${mq7_id}_ratio
- platform: template
id: ${mq7_id}_ratio
name: "${mq7_name} Ratio"
icon: mdi:percent
entity_category: diagnostic
disabled_by_default: True
unit_of_measurement: "%"
lambda: |-
return 100.0 * (id(${mq7_id}_compensated_resistance).state / ${mq7_clean_air_compensated_resistance});
update_interval: never
on_value:
then:
- component.update: ${mq7_id}_co
- platform: template
id: ${mq7_id}_co
name: "${mq7_name} Carbon Monoxide"
unit_of_measurement: "ppm"
device_class: carbon_monoxide
lambda: |-
auto ratio_ln = log(id(${mq7_id}_ratio).state / 100.0);
return exp(-0.685204 - 2.67936 * ratio_ln - 0.488075 * ratio_ln * ratio_ln - 0.07818 * ratio_ln * ratio_ln * ratio_ln);
update_interval: never
By buying through the links below, you support the channel at no extra cost!
Tools and materials used in the video:
- MQ7 Carbon Monoxide Sensor Module - https://s.click.aliexpress.com/e/_DmqKxkP
- DHT11 Temperature/Humidity Sensor - https://s.click.aliexpress.com/e/_DEvBJR9
- NodeMCU board - https://s.click.aliexpress.com/e/_DBsbgM3
- ESP32 board - https://s.click.aliexpress.com/e/_oCw0PRb
- Soldering station - https://s.click.aliexpress.com/e/_DEwIziT
- Desoldering wire - https://s.click.aliexpress.com/e/_EQ7zhuL
- Wire snippers - https://s.click.aliexpress.com/e/_Dd93z2L
- Wire strippers - https://s.click.aliexpress.com/e/_DmQOvLV
- Tweezers - https://s.click.aliexpress.com/e/_DdkDzuX
- Project box - https://s.click.aliexpress.com/e/_DkwYInZ
- RD6012 Bench power supply - https://s.click.aliexpress.com/e/_DBQ2Mf1