MH-Z19B problem!

Good morning everyone!

Recently, I´ve been dealing with a problem that I cannot work out.

I’m using a WIFI LoRa 32 V2.1 alongside a Co2 sensor, specifically the MH-Z19B.

This sensor use is connected to the ESP32 through UART via Serial Port.

I’ve been using this sketch but it doesn´t work. All the co2 values that I get are 0, always :frowning:

#include <Arduino.h>
#include “MHZ19.h”
#include <SoftwareSerial.h> // Remove if using HardwareSerial
#include <Wire.h>

#define RX_PIN 4 // Rx pin which the MHZ19 Tx pin is attached to (SCL)
#define TX_PIN 15 // Tx pin which the MHZ19 Rx pin is attached to (SDA)
#define BAUDRATE 9600 // Device to MH-Z19 Serial baudrate (should not be changed)

MHZ19 myMHZ19; // Constructor for library
SoftwareSerial mySerial(RX_PIN, TX_PIN);

unsigned long getDataTimer = 0;

void setup()
{
Serial.begin(115200);

Wire.begin(4, 15);

mySerial.begin(BAUDRATE);                                  
myMHZ19.begin(mySerial);                                 

myMHZ19.autoCalibration();                              

}

void loop()
{
if (millis() - getDataTimer >= 5000)
{
int CO2;

    CO2 = myMHZ19.getCO2();                             
    
    Serial.print("CO2 (ppm): ");                      
    Serial.println(CO2);                                

    int8_t Temp;
    Temp = myMHZ19.getTemperature();                     
    Serial.print("Temperature (C): ");                  
    Serial.println(Temp);                               

    getDataTimer = millis();
}

}

I tried to modified each parameter, changing the RX and TX pins, trying with different cables and even using another sensor but I don’t know which is the issue.

Besides, I used a ESP8266 with the MH-Z19B and it works perfectly. Therefore, I assume that is an issue related to the WIFI LoRa 32 V2.1.

It might be a matter of incompatibility with some pin. I don’t really know…

Has anyone used this sensor with WIFI LoRa 32 V2.1 and did it work?

I am open to any suggestions.

Thak you very much in advance.

i have same problem with 1/2aa lora node, and it can be beause of power problems, your co2 sensor can only work from 3.6v maybe you use 3.3 pin or something that gives you les voltage

1 Like

But if you look the satasheet, it says that it works from 4.5 to 5.5V…

1 Like

i took my data from online shop in my contry, so its not so true, but i use MH-Z16, and datasheet says 4.5~5.5, so like yours, but it works 3.0 and more, so i think the accuracy might be not so good, but it works, and i recomend you to try use external battery just for power the sensor, to check the problem is in voltag or no, exactly now im building fire sensor, and cant solve power problems

I’ve tried with 3’3V as well as 5V and I always get the same value: 0
:pensive::pensive:

1 Like

check 5v pin by voltmeter, and you connect the esp by usb or use battery?

I checked 5V with a voltmeter and it’s okay. So I believe it isn`t a matter of voltage.

I connect the esp via USB

ok, so i dont have any ideas, sorry for useless info

No worries, thank you anyway for helping me!

I appreciate indeed!

Are you sure 1115200 instead of 115200? I’ve never seen 1115200.

OMG haha i’m sorry, it was just a mistake while writing. In my code it is written properly

Thanks!

Well, after spendig hours and hours in front of my computer… EUREKA!

I found the right library and sketch for me!

If anyone want to get the code, just let me know.

Thanks everyone!

Hello Delarcus, i am very interested in the code for heltec esp32 lora and mh-z19c. would help me a lot with a similar project!

Hi Delarkus, me too, please! Would be highly interested in both sketch and link to the library.

This is the sketch i’ve been using:

#include <arduino_lmic.h>
#include <arduino_lmic_hal_boards.h>
#include <arduino_lmic_hal_configuration.h>
#include <arduino_lmic_lorawan_compliance.h>
#include <arduino_lmic_user_configuration.h>

#include <lmic.h>
#include <hal/hal.h>
#include <SPI.h>

#include <MHZ19.h>
#include <SoftwareSerial.h>

#include “heltec.h”
#include “DHT.h”

#define DHTTYPE DHT22
#define DHTPIN 13

#define RXPin 22 // para MH-Z19B
#define TXPin 21 // para MH-Z19B

SoftwareSerial ss(RXPin, TXPin);// RX, TX

MHZ19 mhz(&ss);

DHT dht(DHTPIN, DHTTYPE);

/long val_CO2 = 0; // valor CO2
float val_tempC = 0.0; // valor Temperatura
float val_accCO2 = 0.0; // valor accuracy
long val_minCO2 = 0.0; // valor min CO2
/

unsigned long getDataTimer;
unsigned long counter;
unsigned long paquete;

float h;
float t;
float CO2;

long val_CO2 = 0; // valor CO2
float val_tempC = 0.0; // valor Temperatura
float val_accCO2 = 0.0; // valor accuracy

unsigned long MHZ19B_PREHEATING_TIME = 180000; // Por especificaciones tiene un PREHEATING Time de 3 minutos… pero pongo 1…
const int OFFSET_TEMP = -1; // Valor obtenido de comparar con un termometro.
const int OFFSET_CO2 = +18; // Valor de 400 al arranque +18 que se supone media anual al nivel del mar en 2020

/*#ifdef COMPILE_REGRESSION_TEST

define FILLMEIN 0

#else

warning “You must replace the values marked FILLMEIN with real values from the TTN control panel!”

define FILLMEIN (#dont edit this, edit the lines that use FILLMEIN)

#endif*/

// lsb
static const u1_t PROGMEM APPEUI[8] = { 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX };
void os_getArtEui (u1_t* buf) {
memcpy_P(buf, APPEUI, 8);
}

// lsb
static const u1_t PROGMEM DEVEUI[8] = { 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX };

void os_getDevEui (u1_t* buf) {
memcpy_P(buf, DEVEUI, 8);
}

// msb
static const u1_t PROGMEM APPKEY[16] = { 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX };
void os_getDevKey (u1_t* buf) {
memcpy_P(buf, APPKEY, 16);
}

// payload to send to TTN gateway

static uint8_t payload[8];
static osjob_t sendjob;

// Schedule TX every this many seconds (might become longer due to duty
// cycle limitations).
const unsigned TX_INTERVAL = 60;

// Pin mapping
const lmic_pinmap lmic_pins = {
.nss = 18,
.rxtx = LMIC_UNUSED_PIN,
.rst = 14, // reset pinPreformatted text
.dio = {/dio0/ 26, /dio1/ 35, /dio2/ 33}
};

void printHex2(unsigned v) {
v &= 0xff;
if (v < 16)
Serial.print(‘0’);
Serial.print(v, HEX);
}

void onEvent (ev_t ev) {
Serial.print(os_getTime());
Serial.print(": ");
switch (ev) {
case EV_SCAN_TIMEOUT:
Serial.println(F(“EV_SCAN_TIMEOUT”));
break;
case EV_BEACON_FOUND:
Serial.println(F(“EV_BEACON_FOUND”));
break;
case EV_BEACON_MISSED:
Serial.println(F(“EV_BEACON_MISSED”));
break;
case EV_BEACON_TRACKED:
Serial.println(F(“EV_BEACON_TRACKED”));
break;
case EV_JOINING:
Serial.println(F(“EV_JOINING”));
break;
case EV_JOINED:
Serial.println(F(“EV_JOINED”));
{
u4_t netid = 0;
devaddr_t devaddr = 0;
u1_t nwkKey[16];
u1_t artKey[16];
LMIC_getSessionKeys(&netid, &devaddr, nwkKey, artKey);
Serial.print("netid: ");
Serial.println(netid, DEC);
Serial.print(“devaddr: “);
Serial.println(devaddr, HEX);
Serial.print(“AppSKey: “);
for (size_t i = 0; i < sizeof(artKey); ++i) {
if (i != 0)
Serial.print(”-”);
printHex2(artKey[i]);
}
Serial.println(””);
Serial.print(“NwkSKey: “);
for (size_t i = 0; i < sizeof(nwkKey); ++i) {
if (i != 0)
Serial.print(”-”);
printHex2(nwkKey[i]);
}
Serial.println();
}
// Disable link check validation (automatically enabled
// during join, but because slow data rates change max TX
// size, we don’t use it in this example.
LMIC_setLinkCheckMode(0);
break;
/*
|| This event is defined but not used in the code. No
|| point in wasting codespace on it.
||
|| case EV_RFU1:
|| Serial.println(F(“EV_RFU1”));
|| break;
*/
case EV_JOIN_FAILED:
Serial.println(F(“EV_JOIN_FAILED”));
break;
case EV_REJOIN_FAILED:
Serial.println(F(“EV_REJOIN_FAILED”));
break;
case EV_TXCOMPLETE:
Serial.println(F(“EV_TXCOMPLETE (includes waiting for RX windows)”));
if (LMIC.txrxFlags & TXRX_ACK)
Serial.println(F(“Received ack”));
if (LMIC.dataLen) {
Serial.print(F(“Received “));
Serial.print(LMIC.dataLen);
Serial.println(F(” bytes of payload”));
}
// Schedule next transmission
os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send);

  Serial.println("\n PAQUETE ENVIADO ");
  paquete++;

  break;
case EV_LOST_TSYNC:
  Serial.println(F("EV_LOST_TSYNC"));
  break;
case EV_RESET:
  Serial.println(F("EV_RESET"));
  break;
case EV_RXCOMPLETE:
  // data received in ping slot
  Serial.println(F("EV_RXCOMPLETE"));
  break;
case EV_LINK_DEAD:
  Serial.println(F("EV_LINK_DEAD"));
  break;
case EV_LINK_ALIVE:
  Serial.println(F("EV_LINK_ALIVE"));
  break;
/*
  || This event is defined but not used in the code. No
  || point in wasting codespace on it.
  ||
  || case EV_SCAN_FOUND:
  ||    Serial.println(F("EV_SCAN_FOUND"));
  ||    break;
*/
case EV_TXSTART:
  Serial.println(F("EV_TXSTART"));
  break;
case EV_TXCANCELED:
  Serial.println(F("EV_TXCANCELED"));
  break;
case EV_RXSTART:
  /* do not print anything -- it wrecks timing */
  break;
case EV_JOIN_TXCOMPLETE:
  Serial.println(F("EV_JOIN_TXCOMPLETE: no JoinAccept"));
  break;

default:
  Serial.print(F("Unknown event: "));
  Serial.println((unsigned) ev);
  break;

}
}

void do_send(osjob_t* j) {
// Check if there is not a current TX/RX job running
if (LMIC.opmode & OP_TXRXPEND) {
Serial.println(F(“OP_TXRXPEND, not sending”));
} else {

// CO2 //
CO2 = mhz.getCO2();
Serial.print("Co2 ");
Serial.println(CO2);

// TEMPERATURE //
t = dht.readTemperature();
Serial.print("Temperatura: ");
Serial.println(t);

// HUMIDITY //
h = dht.readHumidity();
Serial.print("Humedad: ");
Serial.println(h);


if (isnan(h) || isnan(t)) {
  Serial.println(F("Failed to read from DHT sensor!"));
  return;
}

uint16_t ft = (uint16_t)(t * 100);
uint16_t fh = (uint16_t)(h * 100);
uint32_t fco2 = (uint32_t)((CO2 + OFFSET_CO2) * 100);


payload[0] = ft >> 8;
payload[1] = ft % 0xFF;
payload[2] = fh >> 8;
payload[3] = fh & 0xFF;
payload[4] = fco2 & 0xFF;
payload[5] = (fco2 >> 8) & 0xFF;
payload[6] = (fco2 >> 16) & 0xFF;
payload[7] = (fco2 >> 24) & 0xFF;


// Prepare upstream data transmission at the next possible time.
LMIC_setTxData2(1, payload, sizeof(payload) - 1, 0);
Serial.println(F("Packet queued"));

}
// Next TX is scheduled after TX_COMPLETE event.
}

void setup() {

Heltec.begin(true /DisplayEnable Enable/, true /LoRa Enable/, true /Serial Enable/, true /LoRa use PABOOST/, 868E6 /LoRa RF working band/);

Serial.begin(115200);
delay(1000);
ss.begin(9600); // Software Serial

Serial.println(F(“Starting\n”));

dht.begin();
mhz.setAutoCalibration(true); // default settings - off autocalibration

// LMIC init
os_init();
// Reset the MAC state. Session and pending data transfers will be discarded.
LMIC_reset();

// Start job (sending automatically starts OTAA too)
do_send(&sendjob);
}

void loop() {
os_runloop_once();

if (millis() - getDataTimer >= 3000) {

val_tempC = mhz.getTemperature() + OFFSET_TEMP;
val_CO2 = mhz.getCO2() + OFFSET_CO2;
val_accCO2 = mhz.getAccuracy();



MHZ19_RESULT response = mhz.retrieveData();

if (response == MHZ19_RESULT_OK) {
  Serial.print(F("\n\nCO2: "));
  Serial.println(val_CO2);

  Heltec.display -> clear();
  Heltec.display -> drawString(0, 0, "Co2: " + String(val_CO2) + " ppm");
  Heltec.display -> drawString(0, 10, "Nº de medidas: " + String(counter));
  Heltec.display -> drawString(0, 20, "Paquetes enviados: " + String(paquete));
  Heltec.display -> display();
}
else {
  Serial.print( "Error Reading MH-Z19B Module" );
  Serial.print(F("Error, code: "));
  Serial.println(response);


  Heltec.display -> clear();
  Heltec.display -> drawString(0, 0, "ERROR en medición: " + String(response));
  Heltec.display -> drawString(0, 10, "Nº de medidas: " + String(counter));
  Heltec.display -> drawString(0, 20, "Paquetes enviados: " + String(paquete));
  Heltec.display -> display();
}
counter++;

recogerTemp();

getDataTimer = millis();
}
}

void recogerTemp() {
h = dht.readHumidity();
t = dht.readTemperature();

if (isnan(h) || isnan(t)) {
Serial.println(F(“Failed to read from DHT sensor!”));
return;
}

Serial.print(F("\n\nHumedad: “));
Serial.print(h);
Serial.print(F(”% Temperatura: "));
Serial.print(t);
Serial.println(F("°C "));

Heltec.display -> drawString(0, 30, “Temperatura: " + String(t) + " ºC”);
Heltec.display -> drawString(0, 40, “Humedad: " + String(h) + " %”);
Heltec.display -> display();
}

It works perfectly, any questions you may have, don’t hesitate to ask!

@omb @njotha