wifwaf / mh-z19 Goto Github PK
View Code? Open in Web Editor NEWFor Arduino Boards (&ESP32). Additional Examples/Commands., Hardware/Software Serial
License: GNU Lesser General Public License v3.0
For Arduino Boards (&ESP32). Additional Examples/Commands., Hardware/Software Serial
License: GNU Lesser General Public License v3.0
This is likely related to #36 but I did not want to hijack that thread.
I have a recent MH-Z19C (plug version). The C02 readings have been ok-ish from the beginning. I compare them to the readings I get out of a Sensirion SCD41 that sits next to it. The temperature was off by roughly +10°C.
However, after a few weeks the CO2 readings started declining gradually until they ended up far below 400ppm (120-300). The reported temperature was constantly around +-32°C.
To see whether this library may be at fault I tried two others for this sensor and got similar results. I concluded my sensor must have failed the test of time. However, after I scanned #36 I'm not so sure anymore.
Tonight I ran the sensor outside for half an hour. Here's what it reports now (inside again).
Device info
21:57:22.753 -> Firmware Version: 05.12
21:57:22.753 -> Range: 2000
21:57:22.787 -> Background CO2: 500
21:57:22.787 -> Temperature Cal: 50
21:57:22.823 -> ABC Status: ON
Basic usage plus background CO2
22:18:26.583 -> CO2 (ppm): 493
22:18:26.583 -> background CO2: 493
22:18:26.654 -> Temperature (C): 33
22:18:28.653 -> CO2 (ppm): 497
22:18:28.653 -> background CO2: 497
22:18:28.725 -> Temperature (C): 33
22:18:30.716 -> CO2 (ppm): 469
22:18:30.716 -> background CO2: 469
22:18:30.782 -> Temperature (C): 33
22:18:32.815 -> CO2 (ppm): 465
22:18:32.815 -> background CO2: 465
22:18:32.850 -> Temperature (C): 33
22:18:34.858 -> CO2 (ppm): 465
22:18:34.858 -> background CO2: 465
22:18:34.895 -> Temperature (C): 33
22:18:36.939 -> CO2 (ppm): 468
22:18:36.939 -> background CO2: 468
22:18:36.976 -> Temperature (C): 33
22:18:38.985 -> CO2 (ppm): 466
22:18:38.985 -> background CO2: 466
22:18:39.056 -> Temperature (C): 33
22:18:41.054 -> CO2 (ppm): 491
22:18:41.054 -> background CO2: 491
22:18:41.126 -> Temperature (C): 33
22:18:43.143 -> CO2 (ppm): 492
22:18:43.143 -> background CO2: 492
22:18:43.181 -> Temperature (C): 33
22:18:45.198 -> CO2 (ppm): 485
22:18:45.198 -> background CO2: 485
22:18:45.232 -> Temperature (C): 33
22:18:47.263 -> CO2 (ppm): 436
22:18:47.263 -> background CO2: 436
22:18:47.299 -> Temperature (C): 33
22:18:49.342 -> CO2 (ppm): 440
22:18:49.342 -> background CO2: 440
22:18:49.380 -> Temperature (C): 33
22:18:51.414 -> CO2 (ppm): 494
22:18:51.414 -> background CO2: 494
22:18:51.450 -> Temperature (C): 33
22:18:53.455 -> CO2 (ppm): 506
22:18:53.455 -> background CO2: 506
22:18:53.529 -> Temperature (C): 33
-> CO2 and background always the same
-> CO2 is off by ~500ppm compared to the SCD41 that I consider accurate
-> CO2 readings are highly volatile, jumping 10% in just a couple of seconds -> appears to be caused by the sensor calibrating
-> temperature is off by 10°C
In MHZ19.cpp, sections such as:
#if defined (ESP32) && (MHZ19_ERRORS)
ESP_LOGE(TAG_MHZ19, "message...");
#elif MHZ19_ERRORS
Serial.println("!ERROR: message...");
#endif
Could be simplified:
#if MHZ19_ERRORS
Serial.println("!ERROR: message...");
#endif
Thank you!
Hello, thank for your library, it's very useful, especially Recovery and Calibrating part.
When i use SoftwareSerial, everything work great, but 3 hours later i don't receive any data from the sensor (i tested it several times). So i read, that using HardwareSerial on ESP gives more stability, and i tried to connect via HardwareSerial, but don't received any data. Maybe something wrong with my sketch, but i tried to minimum change it from original example sketch.
I just change strings
HardwareSerial mySerial(1);
to
HardwareSerial Serial2(2);
and also
mySerial.begin(BAUDRATE, SERIAL_8N1, RX_PIN, TX_PIN);
to
Serial2.begin(BAUDRATE, SERIAL_8N1);
Cause if i try to compile it with original code, i have error:
BasicUsage:21:56: error: invalid conversion from 'int' to 'SerialMode' [-fpermissive]
mySerial.begin(BAUDRATE, SERIAL_8N1, RX_PIN, TX_PIN); // (ESP32 Example) device to MH-Z19 serial start
^
In file included from /Users/ac1d/Library/Arduino15/packages/esp8266/hardware/esp8266/2.6.2/cores/esp8266/Arduino.h:244:0,
from /var/folders/j2/rv6w5j790dq31zz952rgp0j00000gn/T/arduino_modified_sketch_904602/BasicUsage.ino:1:
/Users/ac1d/Library/Arduino15/packages/esp8266/hardware/esp8266/2.6.2/cores/esp8266/HardwareSerial.h:87:10: error: initializing argument 3 of 'void HardwareSerial::begin(long unsigned int, SerialConfig, SerialMode, uint8_t)' [-fpermissive]
void begin(unsigned long baud, SerialConfig config, SerialMode mode, uint8_t tx_pin)
^
exit status 1
invalid conversion from 'int' to 'SerialMode' [-fpermissive]
Connections:
MHZ19 TX -> GPIO13 (D7) (RXD2)
MHZ19 RX -> GPIO15 (D8) (TXD2)
#include <Arduino.h>
#include "MHZ19.h"
//#include <SoftwareSerial.h> // Remove if using HardwareSerial or Arduino package without SoftwareSerial support
#include "HardwareSerial.h"
//#define RX_PIN 10 // Rx pin which the MHZ19 Tx pin is attached to
//#define TX_PIN 11 // Tx pin which the MHZ19 Rx pin is attached to
#define BAUDRATE 9600 // Device to MH-Z19 Serial baudrate (should not be changed)
MHZ19 myMHZ19; // Constructor for library
//SoftwareSerial mySerial(RX_PIN, TX_PIN); // (Uno example) create device to MH-Z19 serial
HardwareSerial Serial2(2); // (ESP32 Example) create device to MH-Z19 serial
unsigned long getDataTimer = 0;
void setup()
{
Serial.begin(9600); // Device to serial monitor feedback
//Serial.swap(); //GPIO15 (TX) and GPIO13 (RX)
//Serial.flush(); //clear serial buffer
//mySerial.begin(BAUDRATE); // (Uno example) device to MH-Z19 serial start
Serial2.begin(BAUDRATE, SERIAL_8N1); // (ESP32 Example) device to MH-Z19 serial start
myMHZ19.begin(Serial2); // *Serial(Stream) refence must be passed to library begin().
myMHZ19.autoCalibration(); // Turn auto calibration ON (OFF autoCalibration(false))
}
void loop()
{
if (millis() - getDataTimer >= 2000)
{
int CO2;
/* note: getCO2() default is command "CO2 Unlimited". This returns the correct CO2 reading even
if below background CO2 levels or above range (useful to validate sensor). You can use the
usual documented command with getCO2(false) */
CO2 = myMHZ19.getCO2(); // Request CO2 (as ppm)
Serial.print("CO2 (ppm): ");
Serial.println(CO2);
int8_t Temp;
Temp = myMHZ19.getTemperature(); // Request Temperature (as Celsius)
Serial.print("Temperature (C): ");
Serial.println(Temp);
getDataTimer = millis();
}
}
hi, i'm receiving RESULT_ERR_MATCH
once at startup when using this code:
void setup()
{
Serial.begin(9600);
mhz_serial.begin(MHZ_BAUDRATE);
mhz.printCommunication(false, true);
mhz.begin(mhz_serial);
mhz.autoCalibration(false);
}
void loop()
{
if (millis() - getDataTimer >= 5000)
{
int CO2 = mhz.getCO2(false, true);
Serial.println(CO2); // <-- zero at first (mhz.errorCode == 3 RESULT_ERR_MATCH)
getDataTimer = millis();
}
}
debug log:
---
request: 0xFF 0x01 0x85 0x00 0x00 0x00 0x00 0x00 0x7A
response: 0xFF 0x85 0x08 0xE5 0x03 0x9E 0x00 0x00 0xED
---
request: 0xFF 0x01 0xA2 0x00 0x00 0x00 0x00 0x00 0x5D
response: 0xFF 0xA2 0x08 0xE5 0x03 0x9E 0x00 0x00 0xD0
---
request: 0xFF 0x01 0x79 0x00 0x00 0x00 0x00 0x00 0x86
response: 0xFF 0x79 0x01 0x00 0x00 0x00 0x00 0x00 0x86
---
request: 0xFF 0x01 0x79 0x00 0x00 0x00 0x00 0x00 0x86
---
request: 0xFF 0x01 0x86 0x00 0x00 0x00 0x00 0x00 0x79
response: 0xFF 0x79 0x01 0x00 0x00 0x00 0x00 0x00 0x86 ERROR Code: 3
0
---
request: 0xFF 0x01 0x86 0x00 0x00 0x00 0x00 0x00 0x79
response: 0xFF 0x86 0x03 0x9F 0x44 0x00 0x00 0x00 0x94
927
---
not sure why 0x79 (ABC turn off) sent twice.
but first 0x86 (CO2 limited) requested before response for second 0x79 is received, so first 0x86 gets failed.
simillar happens with examples/BasicUsage
, where co2 and temperature requests overlapping, resulting in failed response for both. fixed by requesting only one at a time.
Hello,
This is just a quick question:
In the project Readme says "ABC must be disabled each day, however this is handled by the library."
Is this correct? So the MHZ19B re-enables the auto cal every 24h? Could you confirm it, please?
Many thanks.
The library seems to get out of sync sometimes after 2-3 days running without any problems. If such an error occurs i always get the response RESULT_MATCH forever.
I tried to analyze the code of MHZ19::read and what i understand so far is that you wait until you received at least 9 bytes of data. But what happens if you get more than 9 bytes because of an error? It seems that you just read 9 bytes, also if 10 bytes would be available. The next time the read function is called, you would have again 10 and not 9 bytes in your receive buffer (1 old byte from the previous corrupt message and the 9 bytes from the new message). But now everything is out of sync because of the invalid byte in the receive buffer which is never deleted.
Does this make any sense and could this be the reason for my problems?
I added the following patch to give it a try but i dont have any results so far:
while (mySerial->available() < MHZ19_DATA_LEN)
{
...
}
/* try to resync data */
while (mySerial->available() > MHZ19_DATA_LEN && (unsigned char)mySerial->peek() != 0xFF)
{
mySerial->read();
}
/* response recieved, read buffer */
mySerial->readBytes(inBytes, MHZ19_DATA_LEN);
/* clear receive buffer */
while (mySerial->available())
{
mySerial->read();
}
Hi,
is possible to get these two modules working side by side over serial communication with Arduino UNO?
My part of the code:
`
#include <Wire.h>
#include <SoftwareSerial.h> // ESP-01S Wifi modul AT - serial komunikace
#include "Adafruit_BME280.h" // Bosch BME280 I2C (T+RH+P)
#include "MHZ19.h" // MH-Z19B (CO2)
#define MHZ19B_RX 10 // MH-Z19B - RX PIN (CO2 modul RX pin -> Arduino)
#define MHZ19B_TX 11 // MH-Z19B - TX PIN (CO2 modul TX pin -> Arduino)
#define ESP01S_RX 2 // ESP-01S - RX PIN (Wifi modul TX pin -> Arduino)
#define ESP01S_TX 3 // ESP-01S - RX PIN (Wifi modul RX pin -> Arduino)
int CO2ppm; // koncentrace CO2 (ppm)
unsigned long getDataTimer = 0; // MHZ19B timer
// ESP-01S Wifi modul - konfigurace zapojeni PINu - RX/TX
SoftwareSerial espSerial(ESP01S_RX,ESP01S_TX);
// MH-Z19B CO2 senzor - konfigurace zapojeni PINu - RX/TX (UART zapojeni)
MHZ19 myMHZ19; // knihovna
SoftwareSerial mhz19bSerial(MHZ19B_RX,MHZ19B_TX);
void setup()
{
// Arduino - komunikace
Serial.begin(9600); // Komunikace Arduino - 9600 baudrate
// Inicializace senzoru + modulu
// Bosch BME280 senzor (T+RH+P)
Serial.println("Inicializace...");
Serial.println("Detekce BME280 sensoru...");
if(!bme.begin(0x76)) // IC2 adresa pro komunikaci nastavena na 0x76
{
Serial.println("BME280 senzor nebyl detekovan. Zkontrolujte vase zapojení a/nebo IC2 adresu!");
while(1);
}
Serial.println("BME280 senzor uspesne nacten!");
// MH-Z19B CO2 senzor
mhz19bSerial.begin(9600); // Komunikace s CO2 modulem - 9600 baudrate
myMHZ19.begin(mhz19bSerial); // Definovat seriovou komunikaci
myMHZ19.autoCalibration(false); // Vypnout auto-kalibraci CO2
// ESP-01S - komunikace
espSerial.begin(115200); // Komunikace s Wifi modulem - 115200 baudrate
espSerial.flush(); // Vymazat serial monitor
espData("AT+RST", 1000, DEBUG); // Reset ESP-01S modulu
espData("AT+CWMODE=1", 1000, DEBUG); // Nastavit rezim ESP-01S na "station mode"
espData("AT+CWJAP=\""+ AP_SSID +"\",\""+ AP_PASSWORD +"\"", 1000, DEBUG); // Pripojit k Wifi siti
delay(1000);
}
void readSensors(void)
{
// MH-Z19B - koncentrace CO2 (ppm)
if (millis() - getDataTimer >= 2000)
{
CO2ppm = myMHZ19.getCO2(); // Hodnota koncentrace CO2 (ppm)
getDataTimer = millis();
}
...
`
Hello WifWaf,
on https://revspace.nl/ there is a indicator how to change the cycle of MH-Z19b.
Default is 5 seconds which will also be responded by :
int MHZ19::getCycle()
{
/* check get Cycle length (5 Sek default) /
provisioning(GETCYCLE);
if (this->errorCode == RESULT_OK)
/ convert MH-Z19 memory value and return */
return (int)makeInt(this->storage.responses.STAT[2], this->storage.responses.STAT[3]);
else
return 1;
}
But I'm not fine with setting other values.
Did you have checked this register (126) already?
If you like to investigate - I have setup some lines in a fork-version.
Nice to get your ideas and have a nice time . You see I'm a longeterm follower.
Stefan
Hi,
so i have an ATTiny1614 (16kB Flash, 2kB RAM) with megaTinyCore, a 4-digit serial display and the MHZ-19C. I'm using hardware serial to save memory.
When i flash the code everything works as expected but when i power cycle the board i get error 3 "Recieved data does not match the usual syntax expected".
Flash memory is at 31% and global variables consume 10%.
If it is a memory problem, why does it work right after flashing?
#include <Arduino.h>
#include "MHZ19.h"
#include <TM1637Display.h>
//Pins for 7-Segment
#define CLK 7
#define DIO 6
MHZ19 myMHZ19; // Constructor for CO2 Sensor
TM1637Display display(CLK, DIO); // Constructor for 7-Segment
unsigned long getDataTimer = 0;
uint16_t errorCode=0;
void setup()
{
display.setBrightness(0x05);
Serial.begin(9600); // Device to MH-Z19 should not be changed
//mySerial.begin(BAUDRATE); // (Uno example) device to MH-Z19 serial start
myMHZ19.begin(Serial); // *Serial(Stream) refence must be passed to library begin().
myMHZ19.printCommunication();
myMHZ19.autoCalibration(true); // Turn auto calibration ON (OFF autoCalibration(false))
display.showNumberDec(millis(),false);
delay(2000);
display.showNumberDec(0,true);
}
void loop()
{
if (millis() - getDataTimer >= 2000)
{
int CO2;
/* note: getCO2() default is command "CO2 Unlimited". This returns the correct CO2 reading even
if below background CO2 levels or above range (useful to validate sensor). You can use the
usual documented command with getCO2(false) */
CO2 = myMHZ19.getCO2(); // Request CO2 (as ppm)
if(myMHZ19.errorCode == RESULT_OK)
display.showNumberDec(CO2,false);
else{
display.showNumberDec(myMHZ19.errorCode,true);
}
getDataTimer = millis();
}
}
Hi, so I've started playing with this library, and I'm confused a little about range which .getCO2() returns.
My MH-Z19B has a sticker which states 0-5000ppm.
I've called getRange(), it returned 5000. But when I call getCO2 - I get a value between 0-10000ppm, which looks like 0-5000 stretched into 10000, for example I get something like 1100 in fresh air, which should be close to 400-500, and I get 10000 when do a couple of breaths near it for a minute.
Am I missing something? Thanks in advance.
I've ran RetrieveDeviceInfo.ino:
Firmware Version: 04.30
Range: 5000
Background CO2: 400
Temperature Cal: 40
ABC Status: OFF
Hi,
I am usning MH-Z19c sensor on esp8266.
I am getting the same temperature value:
CO2: 672
Temperature: -40
Accuracy: 0
CO2: 675
Temperature: -40
Accuracy: 0
CO2: 682
Temperature: -40
Accuracy: 0
CO2: 684
Temperature: -40
Accuracy: 0
CO2: 689
Temperature: -40
Accuracy: 0
CO2: 691
Temperature: -40
Accuracy: 0
CO2: 693
Temperature: -40
Accuracy: 0
Please help me on this.
Hi, I used your example script on my new (and first) MH-Z19B sensor. I have no experience with this type of Sensor, however i do not trust this temerature measurements:
CO2 (ppm): 1962 Temperature (C): 4
The Co2 could be possible due to an indoor room, but the temp is definitely off. And I guessing this makes the Co2 wrong too? Could this be script side oder is my sensor just broken?
I built 4 devices, all with the same components including a CO2 sensor, all running the same arduino software. I put them side by side and they report wildy different temperature values (14, 24, 38, 45). Have you seen this problem? What should be this value?
Hi! Thanks for the useful library!
I found a small problem: after a reboot on power, the sensor returns falsely large values, which breaks the display of CO2-level charts.
Here is a serial monitor dump after such reboot:
CO2 = 63882 ppm
CO2 = 7011 ppm
CO2 = 4013 ppm
CO2 = 1017 ppm
CO2 = 1016 ppm
CO2 = 1029 ppm
CO2 = 1042 ppm
It would be great to add a filter of values to the library if it's possible.
Kind regards, Max.
Compiling for an esp32c3 board, I have some issues with platfomio, like this:
C:/Users/Usuario/.platformio/packages/framework-arduinoespressif32@src-01b2ee0664276ec022da2783d94579c3/tools/sdk/esp32c3/include/log/include/esp_log.h:351:38: note: in expansion of macro 'ESP_LOG_LEVEL_LOCAL'
#define ESP_LOGE( tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_ERROR, tag, format, ##VA_ARGS)
^~~~~~~~~~~~~~~~~~~
.pio/libdeps/ESP32C3/MH-Z19/src/MHZ19.cpp:51:9: note: in expansion of macro 'ESP_LOGE'
ESP_LOGE(TAG_MHZ19, "Invalid Range value (0 - 65000)");
^~~~~~~~
.pio/libdeps/ESP32C3/MH-Z19/src/MHZ19.cpp:51:18: error: 'TAG_MHZ19' was not declared in this scope
ESP_LOGE(TAG_MHZ19, "Invalid Range value (0 - 65000)");
Hi there,
I don't know if the question is about the library or about the sensor itself. I am using the method calibrate ();
to calibrate the sensor but it does not have the behavior I expect, which is to determine the zero (400 ppm). Instead, other baselines appear. After calibrating, I print the sensor information and get results such as:
Background CO2 seems to have been defined in the calibration process. Does that make sense to you? In that case, how can that Background CO2 be set with such a high value, if the calibration is done outdoors?
Thank you!
Note: By the way, outdoor temperatures were lower, at 7-9 °C.
The library fails when the debug level is increased, when you define CORE_DEBUG_LEVEL=3
for example, its necessary pass the TAG like this: '-D TAG_MHZ19="MHZ19"'
on PlatformIO ini file for example.
.pio/libdeps/M5STICKCPLUS/MH-Z19/src/MHZ19.cpp: In member function 'void MHZ19::begin(Stream&)':
.pio/libdeps/M5STICKCPLUS/MH-Z19/src/MHZ19.cpp:37:18: error: 'TAG_MHZ19' was not declared in this scope
ESP_LOGE(TAG_MHZ19, "Initial communication errorCode recieved");
Using :
#define RX_PIN D5 // Rx pin which the MHZ19 Tx pin is attached to
#define TX_PIN D6 // Tx pin which the MHZ19 Rx pin is attached to
#define BAUDRATE 9600 // Native to the sensor (do not change)
in the basicusage sketch.
Other libraries are able to fetch the temperature and ppm, this library fails.
I hooked up an oscilloscope and can see that the device indeed replies (TX and RX are both active).
Output of the sketch:
!ERROR: Failed to verify connection(1) to sensor. Failed to stablise
!ERROR: Initial communication errorCode recieved
CO2 (ppm): 0
Temperature (C): -17
CO2 (ppm): 0
Temperature (C): -17
CO2 (ppm): 0
Temperature (C): -17
CO2 (ppm): 0
Temperature (C): -17
CO2 (ppm): 0
Temperature (C): -17
CO2 (ppm): 0
Temperature (C): -17
CO2 (ppm): 0
Temperature (C): -17
ErrorCode = 2 meaning timeout
I tried to increase timeout to 5000 but nothing changed...
I am using version 1.5.3
Hi.
I calibrated on a windowsill with an open window, after calibration I upload my sketch and invoke getBackgroundCO2(), it was 500, then I corrected something in the code, upload it again and the value of getBackgroundCO2() became equal to getCO2(), is this correct behavior? I had the idea to calibrate the sensor, and then measure the delta from the background level of CO2, i.e. getCO2() - getBackgroundCO2(). Also, what seemed strange to me, the sensor readings in a ventilated room range from 1500 to 1600 ppm, is this an overestimated value?
I encountered a weird problem and while most likely not related to the library, I wanted to make sure. I use the MH-Z19B with an ESP32. I already tried with an Arduino and an ESP8266 and everything worked fine.
Additionally when I use the sensor with a "LOLIN32" everything works, too.
Now the problem is the board I would like to use "LOLIN D32" has no 5V pin and when I connect the sensor to the 3.3V pin, I always receive 5000ppm as response. I did some research and it seems as if the sensor is getting a brownout and restarts continuosly...
I tried to use an external 5V power source (I connected GND and 5V to Vin and GND and also tried to connect only 5V to Vin) but now I get an error on startup ([E][MHZ19.cpp:44] begin(): Initial communication errorCode recieved) and always receive 0ppm.
Sorry for opening this potential Non-Issue and thanks in advance.
I used these connections on ESP32 / External 5V source.
Vin -> 5V
GND -> GND
17 -> RX
16 -> TX
I used this code:
#include <Arduino.h>
#include "MHZ19.h"
MHZ19 myMHZ19;
unsigned long getDataTimer = 0;
void setup()
{
Serial.begin(9600);
Serial2.begin(9600, SERIAL_8N1);
myMHZ19.begin(Serial2);
myMHZ19.autoCalibration();
}
void loop()
{
if (millis() - getDataTimer >= 5000)
{
int CO2Unlim = myMHZ19.getCO2();
Serial.print("CO2 (ppm): ");
Serial.println(CO2Unlim);
getDataTimer = millis();
}
}
Is using this board not supported yet or am I doing something wrong?
Hi,
I'm I correct to assume that even if my sensors range is between 410 - 2000.
That the raw measurement that goes above 20000 is also correct? (The ppm count in the raw example)
Or is this gibberish data?
I recently ordered 3x MH-Z19 sensors from banggood. Because I wanted to construct 3 supplementary IOT CO2 sensors (refer to my project https://github.com/hixfield/HixCO2TemperatureIRBlaster). However, the readings that they produce are highly unstable and cannot be trusted. I created small YouTube video to show my readings (on request of banggood itself):
Also found this post about it: https://revspace.nl/MH-Z19B#Fake_MH-Z19B_.28black_PCB.29
So nice to see this fantastic library. I struggled a lot 3 years ago, with all those commands...
https://www.hackteria.org/wiki/CO2_Soil_Respiration_Chamber
From my own experiments i started to prefer the MH-Z16, as it can also send ppm values below 400. For some experiments in plant monitoring or microbiological fermentation process we can also eat up more CO2 than we release.
It's quite similar, the library could add it with minor changes.
Whaaddabout those different sensitivities 0-2000, 0-5000, 0-10'000 and even more. How can i set this up using the library?
Good afternoon, I have an MH-Z19B connected to an ESP12, when I connect it to the power supply it works fine for the first 15 minutes, then it stops measuring 0 ppm. Does anyone know how to fix it?
Hi, thank you for this great library.
I've checked and run the calibration example, but it didn't help me.
I was outside and run sketch couple times without any changes in code (except rx/tx). But mh-z19 still returns me values around 720. Did I do it wrong?
I have another CO2 monitor, which shows 460-470 at the same spot, and it seems to be a fair number.
So I noticed that my mh-z19 has wrong delta around 200-300 ppm. Is there a way to make a safe shift for that delta?
I used an Arduino Micro and just used your example code and connected the sensor like this:
Unfortunately, I got this Error:
I changed the value of the rx_pin and tx_pin like this:
#define RX_PIN 10
#define TX_PIN 11
When I look at the Sensor, I can see the IR light turning on every 2 seconds or so. On the arduino, the tx light flashes on and of, but the rx light is permanentely of.
What can I do?
`error: no matching function for call to 'SoftwareSerial::SoftwareSerial(int, int)'
SoftwareSerial mySerial(RX_PIN, TX_PIN); // Uno example`
With ESPSoftwareSerial 5.3.4 from: https://github.com/plerup/espsoftwareserial/
Which version do you recommend?
I have mhz-19b
first measurement is not accurate, it returns always about 450 ppm, but the second if is correct (tested and compared with my second commercial device).
I use delay 60 second before the first read, is there anything what can be done better? Thank you!
According to the MH-Z19's manual, the command to get the co2 reading is 0x86.
Following the basic usage example in this repository, it seems that 0x85 is being sent instead.
Here's a screenshot from a logic analyzer showing Tasmota correctly polling for the reading:
Here's your arduino library:
The code I'm using:
#include <MHZ19.h>
#include <SoftwareSerial.h>
#define RX_PIN 8
#define TX_PIN 9
#define BAUDRATE 9600
MHZ19 myMHZ19;
SoftwareSerial mhzSerial(RX_PIN, TX_PIN);
unsigned long getDataTimer = 0;
void setup() {
mhzSerial.begin(BAUDRATE);
myMHZ19.begin(mhzSerial);
myMHZ19.setRange(2000);
myMHZ19.setSpan(2000);
Serial.begin(115200);
}
void loop() {
if (millis() - getDataTimer >= 2000) // Check if interval has elapsed (non-blocking delay() equivilant)
{
int CO2; // Buffer for CO2
CO2 = myMHZ19.getCO2(); // Request CO2 (as ppm)
Serial.print("CO2 (ppm): ");
Serial.println(CO2);
getDataTimer = millis(); // Update interval
}
}
Am I doing something wrong here?
hi, sometimes (like 10% chance) i'm receiving zeros from getCO2
after following init process:
void init_mhz() {
mhz_serial.begin(MHZ_BAUDRATE);
mhz.begin(mhz_serial);
mhz.setFilter(true, true);
mhz.setRange(2000);
mhz.autoCalibration(true);
// warming up
while (true) {
int co2 = mhz.getCO2(false, true);
if (mhz.errorCode == RESULT_FILTER) {
log_ln("sensors: mhz: warming up...", true);
} else if (mhz.errorCode != RESULT_OK) {
log_ln("sensors: mhz: failed to read CO2 on warmup.", true);
} else {
// warmed up (zeros can slip here)
break;
}
delay(CO2_WARMING_READ_PERIOD);
}
}
i'm using mhz.errorCode
instead of simplier co2 == 0
(as in example), because i want to distinguish normal warming (RESULT_FILTER) and failing on warmup (!RESULT_OK).
maybe this is because i'm using TEMPLIM
instead of TEMPUNLIM
(what's the difference btw? didn't found any info about that. using TEMPLIM
because this one specified in manual).
probably co2 == 0
case should be added to other filtering cases.
v1.4.2
Since baud rate of sensor must always be 9600, it could be hidden inside library, e.g. call stream.begin(9600) inside myMHZ19.begin(stream) or add a separate begin method that takes 2 pins and creates a SoftwareSerial object and opens it.
Hi, thanks for the library, makes life so much easier setting up the device
I tried the basic sketch with both library files inside the same directory and tried to compile it on an arduino pro mini (ATMEGA328 so uno compatible) and im getting the following error
MHZ19.cpp: In member function ‘byte MHZ19::read(byte*, MHZ19::Command_Type)’:
MHZ19.cpp:594:48: error: invalid conversion from ‘byte* {aka unsigned char*}’ to ‘char*’ [-fpermissive]
mySerial->readBytes(inBytes, MHZ19_DATA_LEN);
^
In file included from /usr/share/arduino/hardware/arduino/cores/arduino/HardwareSerial.h:28:0,
from /usr/share/arduino/hardware/arduino/cores/arduino/Arduino.h:193,
from MHZ19.h:6,
from MHZ19.cpp:3:
/usr/share/arduino/hardware/arduino/cores/arduino/Stream.h:76:10: note: initializing argument 1 of ‘size_t Stream::readBytes(char*, size_t)’
size_t readBytes( char *buffer, size_t length); // read chars from stream into buffer
^
have i fucked up something obvious that i can't see?
Hi,
I am trying to use your library. Due to every connection seems okey i am not getting and data from my MHZ-19 sensor.
I constantly get the following error;
CO2 (ppm): 0
!Error: Timed out waiting for response
Temperature (C): -17
Thank you.
I've been using a different MHZ19 library but am having serious bugs with it so I gave yours a try, however, when I upload it the LCD doesn't work. Uploading the old sketch brings it back online. I can't understand how this would affect the screen, but I've changed nothing in my code but what's needed to make each library work.
I'm running a Leonardo, so using hardware serial, if that's relevant.
Edit: Actually it seems like everything stopped working, the relays and the logic controlling them as well.
Any help?
The current license is GPL, which means that you cannot use this library in a project without releasing all of that project's source code under GPL as well.
I don't know if using GPL is a fully thought out choice or not, but it severely restricts where the library can be used.
Please consider releasing changing the license to LGPL (allows linking inside of a program), or to MIT (even better, basically allows all use in a propriety program).
The other 2 libraries I've found for using MH-Z19B are MIT licensed, but one of them only supports PWM (no serial support) and the other one isn't available in Arduino IDE's library manager:
https://github.com/tobiasschuerg/MH-Z-CO2-Sensors
https://github.com/crisap94/MHZ19
Changing the license at this point should be fairly simple, but after you've accepted contributions from other people, they need to agree to the license change as well, as far as I've understood.
The readme says that this library is derived/inspired by another library, which is licensed under GPLv3, so the distinction between derived and inspired is probably important if the license would be changed.
Hello
I use esp32 UART to communication with MH-Z19 MH-Z19C
than, I tried the example ErrorCodes and I got message
Sent << DEC: 255 1 133 0 0 0 0 0 122
Received >> DEC: 66 77 9 129 8 200 3 52 1 ERROR Code: 3
Failed to receive CO2 value - Error
Response Code: 3
Sent << DEC: 255 1 133 0 0 0 0 0 122
Received >> DEC: 66 77 9 129 8 200 3 52 1 ERROR Code: 3
Failed to receive CO2 value - Error
Response Code: 3
Sent << DEC: 255 1 133 0 0 0 0 0 122
Received >> DEC: 66 77 9 130 8 198 3 51 1 ERROR Code: 3
Failed to receive CO2 value - Error
Response Code: 3
Sent << DEC: 255 1 133 0 0 0 0 0 122
Received >> DEC: 66 77 9 130 8 198 3 51 1 ERROR Code: 3
Failed to receive CO2 value - Error
Response Code: 3
Sent << DEC: 255 1 133 0 0 0 0 0 122
Received >> DEC: 66 77 9 130 8 199 3 50 1 ERROR Code: 3
Failed to receive CO2 value - Error
Response Code: 3
Sent << DEC: 255 1 133 0 0 0 0 0 122
Received >> DEC: 66 77 9 131 8 199 3 49 1 ERROR Code: 3
Failed to receive CO2 value - Error
Response Code: 3
Could you help me please?
Thank you @WifWaf
Hello again 👍 ,
New Week, New Problem.. You know that I try to make an battery powered Device for my office.. So I would like to Use an Attiny.. But the Attiny 404 has 4kb of Space.. The Library with the BasicUsage won’t fit on that chip.
The attiny has a real serial connection and don’t need „SoftwareSerial“.. Only for understanding: 8kb Attiny has only 26% free Space for Code. This must be more.
How can I use this Libary without SoftwareSerial?
works perfectly on ARDUINO UNO but on ARDUINO MEGA the probe is not recognized
Now that I finally experiment I have another question.
I did a manual calibration as you suggested in your examples. I left the device outside for 20-30 minutes and then I pulled the DH pin to ground for 7 seconds. The readings calibrated to 400 and then i let it run for another 10 minutes to see if it's stays there.
After that i placed the device inside a closed room to show the higher readings. It did willfully. But then i checked the getBackgroundCO2 commend and I noticed the following.
The getBackgroundCO2 was always printing the same as the CO2 command
Background CO2: 3067
ABC Status: OFF
CO2 (ppm): 3067
Temperature (C): 20
Background CO2: 3100
ABC Status: OFF
CO2 (ppm): 3100
Temperature (C): 20
If I got the documentation correctly the getBackgroundCO2 should have been a constant 400 after the calibration. Have you any idea what am i missing?
File MHZ19.cpp
Lines 736 to746
The variable CRC, written in capital letters collides with a macro defined in CMSIS, resulting in a bunch of compiler errors.
Writing the variable crc in lower case letters solves the issue.
You are welcome
Michael
Error:
Arduino: 1.8.13 (Windows 7), Board: "Generic STM32F1 series, BluePill F103C8, Maple DFU Bootloader original, Enabled (generic 'Serial'), None, Low/Full Speed, Smallest (-Os default), Newlib Standard"
In file included from C:\Users\Michael\AppData\Local\Arduino15\packages\STM32\hardware\stm32\1.9.0\system/Drivers/CMSIS/Device/ST/STM32F1xx/Include/stm32f1xx.h:131,
from C:\Users\Michael\AppData\Local\Arduino15\packages\STM32\hardware\stm32\1.9.0\cores\arduino/stm32/stm32_def.h:28,
from C:\Users\Michael\AppData\Local\Arduino15\packages\STM32\hardware\stm32\1.9.0\cores\arduino/stm32/clock.h:43,
from C:\Users\Michael\AppData\Local\Arduino15\packages\STM32\hardware\stm32\1.9.0\cores\arduino/wiring_time.h:23,
from C:\Users\Michael\AppData\Local\Arduino15\packages\STM32\hardware\stm32\1.9.0\cores\arduino/wiring.h:38,
from C:\Users\Michael\AppData\Local\Arduino15\packages\STM32\hardware\stm32\1.9.0\cores\arduino/Arduino.h:36,
from C:\Users\Michael\Documents\Arduino\libraries\MH-Z19\src\MHZ19.h:14,
from C:\Users\Michael\Documents\Arduino\libraries\MH-Z19\src\MHZ19.cpp:11:
C:\Users\Michael\Documents\Arduino\libraries\MH-Z19\src\MHZ19.cpp: In member function 'byte MHZ19::getCRC(byte*)':
C:\Users\Michael\AppData\Local\Arduino15\packages\STM32\hardware\stm32\1.9.0\system/Drivers/CMSIS/Device/ST/STM32F1xx/Include/stm32f103xb.h:685:43: error: expected ')' before '*' token
685 | #define CRC ((CRC_TypeDef *)CRC_BASE)
| ~ ^
C:\Users\Michael\Documents\Arduino\libraries\MH-Z19\src\MHZ19.cpp:736:17: note: in expansion of macro 'CRC'
736 | byte x = 0, CRC = 0;
| ^~~
C:\Users\Michael\AppData\Local\Arduino15\packages\STM32\hardware\stm32\1.9.0\system/Drivers/CMSIS/Device/ST/STM32F1xx/Include/stm32f103xb.h:685:43: error: expected ')' before '*' token
685 | #define CRC ((CRC_TypeDef *)CRC_BASE)
| ~ ^
C:\Users\Michael\Documents\Arduino\libraries\MH-Z19\src\MHZ19.cpp:736:17: note: in expansion of macro 'CRC'
736 | byte x = 0, CRC = 0;
| ^~~
C:\Users\Michael\Documents\Arduino\libraries\MH-Z19\src\MHZ19.cpp:740:25: error: lvalue required as left operand of assignment
740 | CRC += inBytes[x];
| ^
C:\Users\Michael\Documents\Arduino\libraries\MH-Z19\src\MHZ19.cpp:743:17: error: 'crc' was not declared in this scope
743 | CRC = 255 - crc;
| ^~~
In file included from C:\Users\Michael\AppData\Local\Arduino15\packages\STM32\hardware\stm32\1.9.0\system/Drivers/CMSIS/Device/ST/STM32F1xx/Include/stm32f1xx.h:131,
from C:\Users\Michael\AppData\Local\Arduino15\packages\STM32\hardware\stm32\1.9.0\cores\arduino/stm32/stm32_def.h:28,
from C:\Users\Michael\AppData\Local\Arduino15\packages\STM32\hardware\stm32\1.9.0\cores\arduino/stm32/clock.h:43,
from C:\Users\Michael\AppData\Local\Arduino15\packages\STM32\hardware\stm32\1.9.0\cores\arduino/wiring_time.h:23,
from C:\Users\Michael\AppData\Local\Arduino15\packages\STM32\hardware\stm32\1.9.0\cores\arduino/wiring.h:38,
from C:\Users\Michael\AppData\Local\Arduino15\packages\STM32\hardware\stm32\1.9.0\cores\arduino/Arduino.h:36,
from C:\Users\Michael\Documents\Arduino\libraries\MH-Z19\src\MHZ19.h:14,
from C:\Users\Michael\Documents\Arduino\libraries\MH-Z19\src\MHZ19.cpp:11:
C:\Users\Michael\AppData\Local\Arduino15\packages\STM32\hardware\stm32\1.9.0\system/Drivers/CMSIS/Device/ST/STM32F1xx/Include/stm32f103xb.h:685:30: error: increment of read-only location '(CRC_TypeDef*)((1073741824 + 131072) + 12288)'
685 | #define CRC ((CRC_TypeDef *)CRC_BASE)
| ~^~~~~~~~~~~~~~~~~~~~~~~~
C:\Users\Michael\Documents\Arduino\libraries\MH-Z19\src\MHZ19.cpp:744:5: note: in expansion of macro 'CRC'
744 | CRC++;
| ^~~
C:\Users\Michael\Documents\Arduino\libraries\MH-Z19\src\MHZ19.cpp:744:8: error: lvalue required as increment operand
744 | CRC++;
| ^~
In file included from C:\Users\Michael\AppData\Local\Arduino15\packages\STM32\hardware\stm32\1.9.0\system/Drivers/CMSIS/Device/ST/STM32F1xx/Include/stm32f1xx.h:131,
from C:\Users\Michael\AppData\Local\Arduino15\packages\STM32\hardware\stm32\1.9.0\cores\arduino/stm32/stm32_def.h:28,
from C:\Users\Michael\AppData\Local\Arduino15\packages\STM32\hardware\stm32\1.9.0\cores\arduino/stm32/clock.h:43,
from C:\Users\Michael\AppData\Local\Arduino15\packages\STM32\hardware\stm32\1.9.0\cores\arduino/wiring_time.h:23,
from C:\Users\Michael\AppData\Local\Arduino15\packages\STM32\hardware\stm32\1.9.0\cores\arduino/wiring.h:38,
from C:\Users\Michael\AppData\Local\Arduino15\packages\STM32\hardware\stm32\1.9.0\cores\arduino/Arduino.h:36,
from C:\Users\Michael\Documents\Arduino\libraries\MH-Z19\src\MHZ19.h:14,
from C:\Users\Michael\Documents\Arduino\libraries\MH-Z19\src\MHZ19.cpp:11:
C:\Users\Michael\AppData\Local\Arduino15\packages\STM32\hardware\stm32\1.9.0\system/Drivers/CMSIS/Device/ST/STM32F1xx/Include/stm32f103xb.h:685:30: error: invalid conversion from 'CRC_TypeDef*' to 'byte' {aka 'unsigned char'} [-fpermissive]
685 | #define CRC ((CRC_TypeDef *)CRC_BASE)
| ~^~~~~~~~~~~~~~~~~~~~~~~~
| |
| CRC_TypeDef*
C:\Users\Michael\Documents\Arduino\libraries\MH-Z19\src\MHZ19.cpp:746:12: note: in expansion of macro 'CRC'
746 | return CRC;
| ^~~
exit status 1
Fehler beim Kompilieren für das Board Generic STM32F1 series.
First of all: Thanks for your excellent library!
I observed during each poweroff/warmup:
myMHZ19.getCO2(false) returns 0x184 for some seconds and for the rest of the 3 minutes 0x22B.
Hey,
thank your for your nice Library and your Documentation about it. I bought this Sensor and I want to use it only indoors and my Question is about the Calibration. I thought that I need to turn of the auto-calibration, right?
But how can I calibrate this Sensor to have stable Values for a long time?
Is it possible to use your Calibration code with an simple button? I mean : I pressed the button outside the Sensor calibrates itself and then its done. Or needs the Sensor a longer Calibration Time?
Could you please explain to me if I disable the Auto-Calibration disabled that also the temperature Compensation?
My last question is about the Power-Consumption:
Thank you very much for answering my Questions..
@WifWaf I am interested in downloading the firmware using a ST-Link v2.
I found the SWD ports on the schematics at https://revspace.nl/MH-Z19B
MCU firmware can be easily dumped through SWD pads. Pinout:
Pin | Signal |
---|---|
1 (square) | 3V3 |
2 | GND |
3 | SWDIO |
4 | SWCLK |
5 | RESET (active low) |
Additionally, bootloader asks for a firmware update during the first 20s of startup.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.