Difference between revisions of "MHZ19"

From RevSpace
Jump to navigation Jump to search
(4 intermediate revisions by the same user not shown)
Line 2: Line 2:
 
   |Name=MHZ19
 
   |Name=MHZ19
 
   |Picture=mhz19.jpg
 
   |Picture=mhz19.jpg
   |Omschrijving=Some research into the MH-Z19 CO2 sensor
+
   |Omschrijving=Some research into the MH-Z19 CO<sub>2</sub> sensor
 
   |Status=Initializing
 
   |Status=Initializing
 
   |Contact=bertrik
 
   |Contact=bertrik
Line 8: Line 8:
  
 
== Introduction ==
 
== Introduction ==
This page is about the MH-Z19 CO2 sensor and some experiments done with it.
+
This page is about the MH-Z19 CO<sub>2</sub> sensor and some experiments done with it.
  
This sensor gives a digital (serial) output of the CO2 concentration in air, in parts-per-million (ppm).
+
This sensor gives a digital (serial) output of the CO<sub>2</sub> concentration in air, in parts-per-million (ppm).
It uses the optical measurement principle of measuring CO2, which should be much more accurate than the inexpensive electro-chemical sensors you can find.
+
It uses the optical measurement principle of measuring CO<sub>2</sub>, which should be much more accurate than the inexpensive electro-chemical sensors you can find.
 
As far as I know, the optical measurement principle uses a broadband light-source to send some light through an air-sample.
 
As far as I know, the optical measurement principle uses a broadband light-source to send some light through an air-sample.
 
The sensor then looks at the relative intensity of the light at two different frequencies.
 
The sensor then looks at the relative intensity of the light at two different frequencies.
The CO2 gas inside the air absorbs light strongly at very specific wavelengths, allowing a determination of the concentration (ppm) of CO2.
+
The CO<sub>2</sub> gas inside the air absorbs light strongly at very specific wavelengths, allowing a determination of the concentration (ppm) of CO<sub>2</sub>.
This is then compensated for temperature and pressure for increased accuracy.
+
This is then compensated for temperature (and pressure?) for increased accuracy.
 
See also [https://en.wikipedia.org/wiki/Nondispersive_infrared_sensor wikipedia] for this measurement principle.
 
See also [https://en.wikipedia.org/wiki/Nondispersive_infrared_sensor wikipedia] for this measurement principle.
 
A new measurement is started every 5 seconds, you can actually see a small amount of light coming out of the sensor while it's measuring.
 
A new measurement is started every 5 seconds, you can actually see a small amount of light coming out of the sensor while it's measuring.
  
The MH-Z19 is the cheapest optical CO2 sensor I could find on AliExpress, about E22,-.
+
The MH-Z19 is the cheapest optical CO<sub>2</sub> sensor I could find on AliExpress, about E22,-.
  
 
== Hardware and reference data ==
 
== Hardware and reference data ==
Line 26: Line 26:
 
== Software ==
 
== Software ==
 
See [https://github.com/bertrik/mhz19 this github repo] for code using this sensor with an ESP8266 board (WeMos D1 mini).
 
See [https://github.com/bertrik/mhz19 this github repo] for code using this sensor with an ESP8266 board (WeMos D1 mini).
It publishes the CO2 concentration to topic "bertrik/co2" on test.mosquitto.org every 5 seconds.
+
It publishes the CO<sub>2</sub> concentration to topic "bertrik/co2" on test.mosquitto.org every 5 seconds.
  
 
It seems that support for this sensor was recently added to [https://www.esp8266.nu/index.php/ESPEasy ESPEasy].
 
It seems that support for this sensor was recently added to [https://www.esp8266.nu/index.php/ESPEasy ESPEasy].
  
=== Extended commands ===
+
=== Command 0x86 response frame ===
Normally, this sensor is read out using a command/response sequence over serial.
+
Command 0x86 is the command to send to just read out the most recent ppm value.
  
It appears that there are some additional command beyond just reading the CO2 concentration:
+
A response to command 0x86 typically looks like this:
* some calibration commands, e.g. to let the sensor know when it's breathing pure nitrogen (0 ppm), or some reference gas with a known CO2 concentration (e.g. 400 ppm)
+
<pre>
* command XX, to enable/disable the ABC-algorithm (automatic baseline correction)
+
HH LL TT SS U1 U2
* command YY, to set the measurement range of the sensor in steps of 1000 ppm
+
</pre>
 +
where
 +
* HH/LL is the CO<sub>2</sub> ppm value
 +
* TT is the temperature in degrees Celcius, plus 40
 +
* SS is some kind of status byte, this byte always has only one bit set!
 +
* U1/U2 is some unknown value, perhaps related to pressure? After booting the sensor, it starts out at 15000 exactly, then typically settles to about 10500.
  
Some of these commands appear in the MHZ-19<bold>B</bold> datasheet, but appear to work a little differently for the MH-Z19.
+
=== Command set ===
 +
Normally, this sensor is read out using a command/response sequence over serial (9600,8N1).
 +
The following commands are known:
 +
* 0x86: gas concentration reading
 +
* 0x87: calibrate zero point
 +
* 0x88: calibrate span point
 +
 
 +
The MH-Z19B datasheet additionally mentions to following commands:
 +
* 0x79: ABC logic on/off
 +
* 0x99: Sensor detection range setting, this command can be used to set the measurement range (e.g. 0-2000ppm or 0-5000ppm)
 +
It appears that these commands work on the MH-Z19 too, although with a little different command layout.
 +
 
 +
==== command 0x99 (range) ====
 +
Unlike what the MH-Z19B datasheet says, you can set the range using the following command (2000 ppm in this case):
 +
<pre>
 +
0xFF 0x01 0x99 0x00 0x00 0x00 0x07 0xD0 0x8F
 +
</pre>
 +
The 0x07 0xD0 bytes (index 6 and 7) set the range to 2000 ppm.
 +
 
 +
=== Log of MH-Z19 response at startup ===
 +
Below is a log of the sensor response to the 0x86 measurement command while starting up.
 +
The first couple of measurement seem to be invalid.
 +
 
 +
<pre>
 +
RAW: 00 80 47 01 3A 98
 +
RAW: 07 D0 47 01 3A 98
 +
RAW: 00 05 47 01 3A 98
 +
RAW: 01 2D 47 01 3A 98
 +
RAW: 28 97 47 01 3A 98
 +
RAW: 28 97 47 01 3A 98
 +
RAW: 28 97 47 01 3A 98
 +
RAW: 28 97 47 01 3A 98
 +
RAW: 28 97 47 01 3A 98
 +
RAW: 28 97 47 01 3A 98
 +
RAW: 28 97 47 01 3A 98
 +
RAW: 28 97 47 01 3A 98
 +
RAW: 28 97 47 01 3A 98
 +
RAW: 28 97 47 01 3A 98
 +
RAW: 28 97 47 01 3A 98
 +
RAW: 28 97 47 40 3A 98
 +
RAW: 28 97 47 40 3A 98
 +
RAW: 03 84 47 40 2B 43
 +
RAW: 03 85 47 40 2B 19
 +
RAW: 03 86 47 40 2A F9
 +
RAW: 03 87 47 40 2A E1
 +
</pre>
 +
 
 +
The first measurement shows a ppm value of 128, a temperature of 31 degrees C, a "status" byte of 01 and the "unknown" value of 0x3a98 (= 15000).
 +
The second measurement shows a high ppm value of 2000 ppm (the max value within the ppm range).
 +
The third measurement shows a low ppm value of 5 ppm.
 +
The fourth measurement shows a ppm value of 301 ppm.
 +
The fifth measurement shows a very high ppm value of 10391.
 +
The final measurement shows a realistic indoors ppm value of 0x387 = 903 ppm.
 +
The "unknown value" (byte 4/5) typically settles down to 10500 or so.
 +
 
 +
So, it takes some time before the measurement stabilizes, proposed heuristic for a valid reading:
 +
* "status byte" has to be 0x40
 +
* "unknown value" has to be lower than 15000

Revision as of 18:11, 22 October 2016

Project MHZ19
Mhz19.jpg
Some research into the MH-Z19 CO2 sensor
Status Initializing
Contact bertrik
Last Update 2016-10-22

Introduction

This page is about the MH-Z19 CO2 sensor and some experiments done with it.

This sensor gives a digital (serial) output of the CO2 concentration in air, in parts-per-million (ppm). It uses the optical measurement principle of measuring CO2, which should be much more accurate than the inexpensive electro-chemical sensors you can find. As far as I know, the optical measurement principle uses a broadband light-source to send some light through an air-sample. The sensor then looks at the relative intensity of the light at two different frequencies. The CO2 gas inside the air absorbs light strongly at very specific wavelengths, allowing a determination of the concentration (ppm) of CO2. This is then compensated for temperature (and pressure?) for increased accuracy. See also wikipedia for this measurement principle. A new measurement is started every 5 seconds, you can actually see a small amount of light coming out of the sensor while it's measuring.

The MH-Z19 is the cheapest optical CO2 sensor I could find on AliExpress, about E22,-.

Hardware and reference data

See the manufacturer MH-Z19 page.

Software

See this github repo for code using this sensor with an ESP8266 board (WeMos D1 mini). It publishes the CO2 concentration to topic "bertrik/co2" on test.mosquitto.org every 5 seconds.

It seems that support for this sensor was recently added to ESPEasy.

Command 0x86 response frame

Command 0x86 is the command to send to just read out the most recent ppm value.

A response to command 0x86 typically looks like this:

HH LL TT SS U1 U2

where

  • HH/LL is the CO2 ppm value
  • TT is the temperature in degrees Celcius, plus 40
  • SS is some kind of status byte, this byte always has only one bit set!
  • U1/U2 is some unknown value, perhaps related to pressure? After booting the sensor, it starts out at 15000 exactly, then typically settles to about 10500.

Command set

Normally, this sensor is read out using a command/response sequence over serial (9600,8N1). The following commands are known:

  • 0x86: gas concentration reading
  • 0x87: calibrate zero point
  • 0x88: calibrate span point

The MH-Z19B datasheet additionally mentions to following commands:

  • 0x79: ABC logic on/off
  • 0x99: Sensor detection range setting, this command can be used to set the measurement range (e.g. 0-2000ppm or 0-5000ppm)

It appears that these commands work on the MH-Z19 too, although with a little different command layout.

command 0x99 (range)

Unlike what the MH-Z19B datasheet says, you can set the range using the following command (2000 ppm in this case):

0xFF 0x01 0x99 0x00 0x00 0x00 0x07 0xD0 0x8F

The 0x07 0xD0 bytes (index 6 and 7) set the range to 2000 ppm.

Log of MH-Z19 response at startup

Below is a log of the sensor response to the 0x86 measurement command while starting up. The first couple of measurement seem to be invalid.

RAW: 00 80 47 01 3A 98
RAW: 07 D0 47 01 3A 98
RAW: 00 05 47 01 3A 98
RAW: 01 2D 47 01 3A 98
RAW: 28 97 47 01 3A 98
RAW: 28 97 47 01 3A 98
RAW: 28 97 47 01 3A 98
RAW: 28 97 47 01 3A 98
RAW: 28 97 47 01 3A 98
RAW: 28 97 47 01 3A 98
RAW: 28 97 47 01 3A 98
RAW: 28 97 47 01 3A 98
RAW: 28 97 47 01 3A 98
RAW: 28 97 47 01 3A 98
RAW: 28 97 47 01 3A 98
RAW: 28 97 47 40 3A 98
RAW: 28 97 47 40 3A 98
RAW: 03 84 47 40 2B 43
RAW: 03 85 47 40 2B 19
RAW: 03 86 47 40 2A F9
RAW: 03 87 47 40 2A E1

The first measurement shows a ppm value of 128, a temperature of 31 degrees C, a "status" byte of 01 and the "unknown" value of 0x3a98 (= 15000). The second measurement shows a high ppm value of 2000 ppm (the max value within the ppm range). The third measurement shows a low ppm value of 5 ppm. The fourth measurement shows a ppm value of 301 ppm. The fifth measurement shows a very high ppm value of 10391. The final measurement shows a realistic indoors ppm value of 0x387 = 903 ppm. The "unknown value" (byte 4/5) typically settles down to 10500 or so.

So, it takes some time before the measurement stabilizes, proposed heuristic for a valid reading:

  • "status byte" has to be 0x40
  • "unknown value" has to be lower than 15000