tobiasschuerg / MH-Z-CO2-Sensors

Arduino imeplementation for CO2 sensors of the MH-Z series (Intelligent Infrared CO2 Module)
MIT License
75 stars 40 forks source link

Documentation about how to change from MH-Z19B to MH-Z14A module is missing #21

Open StefanL38 opened 3 years ago

StefanL38 commented 3 years ago

tested this library with a MH-Z14A module.

comment about how to change from MZ-H19B to MH-Z14A module is missing.

delays hided away in a library are bad coding practice!!

To the author: If your library is even available through the arduino-library-manager you should add INTENSIVE DOCUMENTAION

and having done a lot of tests including all kinds of extraordinary circumstances to make your library HIGH-reliable

GRRRR!!!!

 It did not work reliable. After a few answers  no more responds from the module shown in the serial monitor

So I used this code for testing (pre-heating and calibrating are disabled through commenting out

Anyway this code is aber to display the answer of the module on eah request

I uploaded this code new to my ESP8266 nodeMCU for re-checking if the code is working directly before copy & pasting this code here. So there is a high chance that this code will work `/*** Sample sketch for using a mh-z14a co2 with a ESP8266 for TESTING a MH_Z14A-sensor

Written by Erik Lemcke, combined out of the following samples:

https://www.letscontrolit.com/forum/viewtopic.php?f=2&t=1785&start=40, calibration sample by s3030150 https://www.home-assistant.io/blog/2015/10/11/measure-temperature-with-esp8266-and-report-to-mqtt/, home assistant mqqt by Paulus Schoutsen

modified by Stefan Ludwig (StefanL38) wiring: nodeMCU mh-z14a D7(GPIO13)--> Rx D6(GPIO12)<-- Tx GND GND

use the nodeMCU-Vin pin to supply with 5V, the mh-z14a needs 5v ***/

include

include

include

define INTERVAL 5000

//Tx_pin of MH_Z is connected to nodeMCU-RX-pin D6 (GPIO12)

define nodeMCU_D6_GPIO12 12

define MH_Z14_TX nodeMCU_D6_GPIO12

//Rx_pin of MH_Z is connected to nodeMCU-TX-pin D7 (GPIO13)

define nodeMCU_D7_GPIO13 13

define MH_Z14_R_Pin nodeMCU_D7_GPIO13

byte mhzResp[9]; // 9 bytes bytes response byte mhzCmdReadPPM[9] = {0xFF,0x01,0x86,0x00,0x00,0x00,0x00,0x00,0x79}; byte mhzCmdCalibrateZero[9] = {0xFF,0x01,0x87,0x00,0x00,0x00,0x00,0x00,0x78}; byte mhzCmdABCEnable[9] = {0xFF,0x01,0x79,0xA0,0x00,0x00,0x00,0x00,0xE6}; byte mhzCmdABCDisable[9] = {0xFF,0x01,0x79,0x00,0x00,0x00,0x00,0x00,0x86}; byte mhzCmdReset[9] = {0xFF,0x01,0x8d,0x00,0x00,0x00,0x00,0x00,0x72}; byte mhzCmdMeasurementRange1000[9] = {0xFF,0x01,0x99,0x00,0x00,0x00,0x03,0xE8,0x7B}; byte mhzCmdMeasurementRange2000[9] = {0xFF,0x01,0x99,0x00,0x00,0x00,0x07,0xD0,0x8F}; byte mhzCmdMeasurementRange3000[9] = {0xFF,0x01,0x99,0x00,0x00,0x00,0x0B,0xB8,0xA3}; byte mhzCmdMeasurementRange5000[9] = {0xFF,0x01,0x99,0x00,0x00,0x00,0x13,0x88,0xCB};

int shifts = 0 ; int co2ppm;

long previousMillis = 0;

// the softwareserial interface is defined from the view of the nodeMCU // nodeMCUs Rx is MH_Zs Tx and vice versa nodeMCUs Tx is MH_Zs Rx

//basic definition of Software-serial is SoftwareSerial MySerial(Rx,Tx)

// from the nodeMCUs view using nodeMCU-pins SoftwareSerial co2Serial(nodeMCU_D6_GPIO12, nodeMCU_D7_GPIO13); // define MH-Z14A

// from the MH_Zs view using the MH_Z-pins //SoftwareSerial co2Serial(MH_Z14_TX, MH_Z14_R_Pin); // define MH-Z14A

byte checksum(byte response[9]){ byte crc = 0; for (int i = 1; i < 8; i++) { crc += response[i]; } crc = 255 - crc + 1; return crc; }

void disableABC() { co2Serial.write(mhzCmdABCDisable, 9); }

void enableABC() { co2Serial.write(mhzCmdABCEnable, 9); }

void setRange5000() { co2Serial.write(mhzCmdMeasurementRange5000, 9); }

void calibrateZero(){ co2Serial.write(mhzCmdCalibrateZero, 9); }

int readCO2() { byte cmd[9] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79}; byte response[9]; co2Serial.write(cmd, 9); // The serial stream can get out of sync. The response starts with 0xff, try to resync. while (co2Serial.available() > 0 && (unsigned char)co2Serial.peek() != 0xFF) { co2Serial.read(); yield(); shifts++; }

memset(response, 0, 9); co2Serial.readBytes(response, 9);

for (int i = 0; i < 9; i++) { Serial.print(" 0x"); Serial.print(response[i], HEX); } Serial.println(" Response OK. Shifts=" + String(shifts));

if (response[1] != 0x86) { Serial.println(" Invalid response from co2 sensor!"); delay(1000); return -1; }

if (response[8] == checksum(response)) { int responseHigh = (int) response[2]; int responseLow = (int) response[3]; int ppm = (256 * responseHigh) + responseLow; return ppm; } else { Serial.println("CRC error!"); return -1; } }

void setup() {

Serial.begin(115200); Serial.println("Startup"); co2Serial.begin(9600); Serial.println("co2Serial.begin(9600);");

unsigned long previousMillis = millis(); delay(500); / Serial.println("Disabling ABC"); disableABC(); / Serial.println("Setting range to 5000"); setRange5000(); /
Serial.println("Waiting half an hour before calibrating zero"); delay(1800000); calibrateZero(); Serial.println("Zero was calibrated");
/
Serial.println("leaving Setup");

}

long lastMsg = 0;

void loop() { unsigned long now = millis(); //send a meaage every minute if (now - lastMsg > 5 * 1000) { lastMsg = now; unsigned long currentMillis = millis(); if (abs(currentMillis - previousMillis) > INTERVAL) { previousMillis = currentMillis; Serial.print("Requesting CO2 concentration..."); co2ppm = -999; co2ppm = readCO2();

  //If no proper co2 value is returned, try again
  while (co2ppm == -1){
    yield();
    Serial.print("re-Requesting CO2 concentration...");
    co2ppm = readCO2();  
  }

  Serial.println("  PPM = " + String(co2ppm));
}

} }`

tobiasschuerg commented 3 years ago

Hi @StefanL38,

sorry to hear that it did not work for you out of the box. I have a sensor running with that code for months without problems (and others do as well). With the missing documentation you are right. Howver my time is limited, so feel free to help - PRs are welcome!

some comments about commenting out, the preheat time: the MHZ-141 has a preheat time of 3 minutes, see sensor specification: https://www.winsen-sensor.com/d/files/infrared-gas-sensor/mh-z14a_co2-manual-v1_01.pdf So this is nothing that needs to be customized as it will lead to false readings instead. Still it's clearly mentioned where all other constants are defined and can be edited https://github.com/tobiasschuerg/MH-Z-CO2-Sensors/blob/d2dbf58947def2f7c4c03e2926d19dd34091e789/MHZ.cpp#L8-L25

Also notice that the sensor has a response time of T90 < 120s so you really need to wait between readings. In the beginning I also did just wait one or two seconds between readings, which led to the sensor stop to respond after a few days.