Welcome to the Pycom forum Forum
    • \[\[global:header.categories\]\]
    • \[\[global:header.recent\]\]
    • \[\[global:header.tags\]\]
    • \[\[global:header.popular\]\]
    • Login

    Explore Pybytes | Official Documentation | Report a Firmware Bug/Issue | GitHub

    [SOLVED] UART and MH-Z16 CO2 sensor

    Scheduled Pinned Locked Moved MicroPython
    uartmicropythonmh-z16
    15 Posts 3 Posters 911 Views 3 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • T Offline
      tttadam
      last edited by tttadam

      Hello there! :)

      I am having some trouble communicating with this CO2 sensor.
      This it's wiki with sample code, and this is the datasheet.

      Okay so I think my issue is related to byte conversion but not sure.

      from machine import UART
      uart = UART(1, 9600) 
      uart.write(b'\xFF\x01\x86\x00\x00\x00\x00\x00\x79') # This is what should trigger the measure 
      uart.read(9) #b'\xff\x86\x01\xecF\x00\x00\x00G' #This is the answer
      

      I am not sure how to process the read value.. The first 2 number is always ff and 86 the next is always small, then the 4th is something weird.. then always 2 zero, and zero with a letter in the and.
      So do you have any idea how can I get proper measurment out of it? Thank you!

      robert-hhR 1 Reply Last reply Reply Quote 0
      • robert-hhR Offline
        robert-hh @tttadam
        last edited by robert-hh

        @tttadam Look at the struct module. It allows to unpack a bytearray into individual data elements. You can also make it simpler,. just following the manual:

        from machine import UART
        uart = UART(1, 9600) 
        uart.write(b'\xFF\x01\x86\x00\x00\x00\x00\x00\x79') # This is what should trigger the measure 
        response = bytearray(uart.read(9)) #
        concentration = response[2] * 256 + response[3]
        checksum = (256 - sum(response[1:-1])) % 256
        print(concentration)
        

        The last byte is the checksum. It looks as if the sample C code in the data sheet is wrong. The variable checksum is not initialized to 0.
        Edit: Checksum simplified

        T 1 Reply Last reply Reply Quote 1
        • T Offline
          tttadam @robert-hh
          last edited by

          @robert-hh Thank you. The code is working, but the values seems to be off, and I am not sure how should I understood the checksum. Should I calibrate the sensor somehow?
          response: 586
          checksum: -29

          response: 590
          checksum: -33

          response: 667
          checksum: -112

          robert-hhR 2 Replies Last reply Reply Quote 0
          • robert-hhR Offline
            robert-hh @tttadam
            last edited by

            @tttadam The checksum is just to be used to verify, that the data was received correctly. The calculated value should be identical to response[8]. Note that I changed the code, such that the checksum is always positive.

            T 1 Reply Last reply Reply Quote 1
            • robert-hhR Offline
              robert-hh @tttadam
              last edited by

              @tttadam Using struct.unpack, you can also use:

              from machine import UART
              from struct import unpack
              uart = UART(1, 9600) 
              uart.write(b'\xFF\x01\x86\x00\x00\x00\x00\x00\x79') # This is what should trigger the measure 
              response = uart.read(9)
              cmd, concentration, check = unpack(">xBh4xB", response)
              checksum = (256 - sum(response[1:-1])) % 256
              print(concentration, checksum == check)
              
              T S 2 Replies Last reply Reply Quote 1
              • T Offline
                tttadam @robert-hh
                last edited by

                @robert-hh Thank you! :)
                I got it now. It's work like it's should.
                Maybe I should to open the window :D

                1 Reply Last reply Reply Quote 0
                • T Offline
                  tttadam @robert-hh
                  last edited by

                  @robert-hh said in [SOLVED] UART and MH-Z16 CO2 sensor:

                  @tttadam Using struct.unpack, you can also use:

                  from machine import UART
                  from struct import unpack
                  uart = UART(1, 9600) 
                  uart.write(b'\xFF\x01\x86\x00\x00\x00\x00\x00\x79') # This is what should trigger the measure 
                  response = uart.read(9)
                  cmd, concentration, check = unpack(">xBh4xB", response)
                  checksum = (256 - sum(response[1:-1])) % 256
                  print(concentration, checksum == check)
                  

                  FYI, nowadays when I try this code I got ValueError: bad typecode error. I am not sure if this was the case back in May.

                  robert-hhR 1 Reply Last reply Reply Quote 0
                  • robert-hhR Offline
                    robert-hh @tttadam
                    last edited by robert-hh

                    @tttadam It looks like the x type code is not supported by MicroPython. Use:

                    d1, cmd, concentration, d2, check = unpack(">bBhiB", s)
                    

                    d1 and d2 are dummy values, which can be ignored.

                    T 1 Reply Last reply Reply Quote 0
                    • T Offline
                      tttadam @robert-hh
                      last edited by

                      @robert-hh Yep, Thank You! :)

                      1 Reply Last reply Reply Quote 0
                      • T Offline
                        tttadam
                        last edited by

                        I found an interesting bug/glitch today. The sensor only works one time after I upload the code.
                        When I plug it out, and hook it to a power brick, or back to the computer it does not work. sends back false data. every other uart and I2c sensor is OK, but not this.

                        Any tipp how this is possible? It is so weird I don't even know how to start the investigation :D

                        robert-hhR 1 Reply Last reply Reply Quote 0
                        • robert-hhR Offline
                          robert-hh @tttadam
                          last edited by

                          @tttadam Is there a difference in how you start the code?
                          a) After uploading. How do you upload? And how do you start the code? Do you for instance push reset?
                          b) After reset: The code should be executed normally. Can you verify after reset, that the code is really loaded permanently to the device. For verification, do not use the tools you used for uploading. Use something different. If you uploaded for instance with pymakr, use ftp/Filezilla for verification.

                          T 1 Reply Last reply Reply Quote 0
                          • T Offline
                            tttadam @robert-hh
                            last edited by

                            @robert-hh Well, I hit upload in pymakr, and then the code start by itself. Or when I plug in to the usb, or to a powerbrick then it's also start by itself.
                            The device sends data over mqtt, so even when it's not connected to the pc I have some sense what's going on. (That how I realised that the data what goes to the server is corrupted)

                            T 1 Reply Last reply Reply Quote 0
                            • T Offline
                              tttadam @tttadam
                              last edited by

                              @tttadam I think I find the issue.
                              If I shut the pycom down by pluging it out (like the 99,9% of the cases) the sensor wont work.
                              But if I reboot it after I pluged-in then it does work.
                              So my "solution"/workaround is that I check in the boot.py if the checksum is false, if it is, then I do a machine.reset() . Any more elegant solution is welcomed :D

                              1 Reply Last reply Reply Quote 0
                              • S Offline
                                saman naz @robert-hh
                                last edited by

                                @robert-hh I have run your code in rpi 3B but it causes an error as the machine is not found what should we write instead?

                                robert-hhR 1 Reply Last reply Reply Quote 0
                                • robert-hhR Offline
                                  robert-hh @saman naz
                                  last edited by

                                  @saman-naz This code is not made for a linux based RPI.

                                  1 Reply Last reply Reply Quote 0

                                  Hello! It looks like you're interested in this conversation, but you don't have an account yet.

                                  Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

                                  With your input, this post could be even better 💗

                                  Register Login
                                  • 1 / 1
                                  • First post
                                    Last post

                                  Pycom on Twitter

                                  Pycom