Problem with UART reading (MH-Z19B sensor)

RP2040 based microcontroller boards running MicroPython.
Target audience: MicroPython users with an RP2040 boards.
This does not include conventional Linux-based Raspberry Pi boards.
KUMO
Posts: 7
Joined: Sat May 22, 2021 6:25 pm

Problem with UART reading (MH-Z19B sensor)

Post by KUMO » Sat May 22, 2021 6:48 pm

Hello together,

I am a totally new comer for MicroPython.

Recently I connected successfully a MH-Z19B sensor to my PICO via UART. The CO2 level as result will then be displayed on a SSD1306 screen. The codes work fine. So I decided to save the it as main.py to have it running automatically once it is connected to external power source (USB).
Then the strange thing happened. I got no sensor reading. The led in MH-Z19B blinks, no value can be read. I tried everything: change all wires, change pins, use additional 5V power supply for MH-Z19B and also tried it on a ESP32, same results... But once I connect the board via USB to a computer and run main.py in Thonny (IDE which I use) there, it works again....

In order understand what happened to sensor reading, I added a command to print what was read and found out that:
if the program (main.py) was triggered in Thonny manually, I got such reading:
b'\xff\x86\x01\xf4;\x00\x00\x00J', wich is according to MH-Z19B data sheet correct.
If I connected to PICO board to external USB power supply (cell phone charger) and main.py runs automatically by itself, the reading looks so: b'\x00\x00F\xff\x86\x01\xf4?\x00'.

For any hints or suggestions I'd really appreciate!

Regards,
Kumo

Below my codes:

Code: Select all

import machine
import time
import ssd1306

tx_pin=machine.Pin(4)
rx_pin=machine.Pin(5)

sensor=machine.UART(1, baudrate=9600, bits=8, parity=None,stop=1,tx=tx_pin, rx=rx_pin)

i2c = machine.I2C(1,scl=machine.Pin(19), sda=machine.Pin(18))
oled_width = 128
oled_height = 64
oled = ssd1306.SSD1306_I2C(oled_width, oled_height, i2c)

def is_valid(buf):
        if buf is None or buf[0] != 0xFF or buf[1] != 0x86:
            return False
        i = 1
        checksum = 0x00
        while i < 8:
            checksum += buf[i] % 256
            i += 1
        checksum = ~checksum & 0xFF
        checksum += 1

while True:
    sensor.write(b'\xff\x01\x86\x00\x00\x00\x00\x00\x79')
    time.sleep(2)
    buf = sensor.read(9)
    if is_valid(buf) == False:
        oled.text("Wrong sensor value!", 0, 10)
        oled.show()
        break
    else:
        co2 = buf[2] * 256 + buf[3]
        text1="CO2 level:"
        text2=str(co2) + " PPM"
        oled.text(text1, 0, 20)
        oled.text(text2, 0, 40)
        oled.show()
        time.sleep(5)
        oled.fill(0)
        oled.show()
 

User avatar
Roberthh
Posts: 2759
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Problem with UART reading (MH-Z19B sensor)

Post by Roberthh » Sun May 23, 2021 6:16 am

If you look at your own post you can tell, that the sensor actually responds with the proper message. Only there are some other bytes upfront. That is "noise", cause the the power up of the board. You have to get rid of that at the start of your coding.
So, at the startup of your code, before sending a command to the sensor, you should simply read all available data from the UART, e.g. with a simple sensor.read().

KUMO
Posts: 7
Joined: Sat May 22, 2021 6:25 pm

Re: Problem with UART reading (MH-Z19B sensor)

Post by KUMO » Sun May 23, 2021 11:40 am

Dear Robert,

thanks for your reply! I tried your suggestion and added sensor.read() in the beginning and print the result.
It shows that it is always None at the very beginning once the board is connected to power.
But after that the reading has the pattern b'\x00\x00F\...., no matter how long I wait and how many time it repeats.
I also tried to remote the first two bytes, which look like "noise"and calculate the co2 value, it is more than 40000 ppm, which can't be true. The the whole reading is totally useless, not just have a "noisy" prefix.

Since the results are repeatable and my another ESP32 board gets the same results with this code. I doubt if it is really noise issue. Or maybe an issue linked to MicroPython UART.

Regards,
KUMO

User avatar
Roberthh
Posts: 2759
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Problem with UART reading (MH-Z19B sensor)

Post by Roberthh » Sun May 23, 2021 12:05 pm

You have to add the read best immediately before you send the command to the sensor. There is no difference to the UART behavior between running code from the IDE or from Flash. If you say: Remove the first two bytes: did you still process the whole 9 bytes you expect from the sensor? Or was the message then shortened to 7 bytes?

Christian Walther
Posts: 152
Joined: Fri Aug 19, 2016 11:55 am

Re: Problem with UART reading (MH-Z19B sensor)

Post by Christian Walther » Sun May 23, 2021 12:50 pm

Also, in your original example, it looked like there were 3 extra bytes, not 2. (len(b'\x00\x00F') == 3, the F is not a hex digit but the ASCII character b'F' == b'\x46')

fdufnews
Posts: 63
Joined: Mon Jul 25, 2016 11:31 am

Re: Problem with UART reading (MH-Z19B sensor)

Post by fdufnews » Sun May 23, 2021 1:49 pm

Well, that not a secure way of coding.
It is always possible that there is garbage sent on the line while the sensor is initializing itself.
Maybe you can add a short piece of code in order to flush the RX buffer before talking to your sensor. Insert this before entering your infinite loop

Code: Select all

while (sensor.any()):
	sensor.read()

KUMO
Posts: 7
Joined: Sat May 22, 2021 6:25 pm

Re: Problem with UART reading (MH-Z19B sensor)

Post by KUMO » Sun May 23, 2021 7:03 pm

Roberthh wrote:
Sun May 23, 2021 12:05 pm
You have to add the read best immediately before you send the command to the sensor. There is no difference to the UART behavior between running code from the IDE or from Flash. If you say: Remove the first two bytes: did you still process the whole 9 bytes you expect from the sensor? Or was the message then shortened to 7 bytes?
The message has in total 9 bytes. So if I cut off the first "noisy" bytes. The rest won't be enough for checksum (9th bytes).
So I gave up this work around.

KUMO
Posts: 7
Joined: Sat May 22, 2021 6:25 pm

Re: Problem with UART reading (MH-Z19B sensor)

Post by KUMO » Sun May 23, 2021 7:21 pm

fdufnews wrote:
Sun May 23, 2021 1:49 pm
Well, that not a secure way of coding.
It is always possible that there is garbage sent on the line while the sensor is initializing itself.
Maybe you can add a short piece of code in order to flush the RX buffer before talking to your sensor. Insert this before entering your infinite loop

Code: Select all

while (sensor.any()):
	sensor.read()
Thanks for your suggestion! I tried it.
Unfortunately I still get sensor reading with totally unusable bytes (the length of 9 bytes is correct), if I connect the board to external USB power source.

I added a print command to print out the raw sensor reading and added two screenshots. The first one shows the results by running the program in IDE. The second one shows the results if I just connect the board to computer USB to trigger automatic run of main.py. You can see the difference of sensor reading pattern.
01.png
01.png (218.84 KiB) Viewed 741 times
02.png
02.png (252.84 KiB) Viewed 741 times

User avatar
Roberthh
Posts: 2759
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Problem with UART reading (MH-Z19B sensor)

Post by Roberthh » Sun May 23, 2021 8:02 pm

Thats' strange. If you are always have three extra bytes upfront, you could try for read 12 byte and discard the first three.
B.T.W.: Which version of the firmware do you use?
Edit: I would move the clearing of the input buffer INTO the loop before you send a command. Then any remainder of a previous possibly failed transmission is gone.

KUMO
Posts: 7
Joined: Sat May 22, 2021 6:25 pm

Re: Problem with UART reading (MH-Z19B sensor)

Post by KUMO » Sun May 23, 2021 9:01 pm

Roberthh wrote:
Sun May 23, 2021 8:02 pm
Thats' strange. If you are always have three extra bytes upfront, you could try for read 12 byte and discard the first three.
B.T.W.: Which version of the firmware do you use?
Edit: I would move the clearing of the input buffer INTO the loop before you send a command. Then any remainder of a previous possibly failed transmission is gone.
Dear Robert,

it is version 1.15.

Regards

Post Reply