Fipy issues with IF statements



  • I'm working on reading data from an Honeywell dust sensor, HPMA115S0 following the initial lead from another user.
    Using a Unbuntu 18.04 laptop with vsCode and pymakr plugin installed. USB connection to my Fipy thru an Arduino PCB with the Atmel IC removed and power, RX/TX tied to the correct pins on the Fipy. I used the Pycom FWtools in Linux to verify I had the latest firmware in my Fipy. The Fipy FW is 1.18.1 r9.

    The initial code segment I found works fine

    from machine import UART
    
    uart = UART(1,9600)
    uart.init(9600, bits=8, parity=None, stop=1)
    while True:
         Datain=uart.readall()
         if data is not None:
             print(data)
    

    running this code segment gets me the correct 32 byte stream output by the Honeywell sensor, output once every second.

    b'BM\x00\x1C\x00\x00\x00\x04\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Q\x00\x01\x05 
    

    I wanted to do sanity checks on the data to ensure I wasn't parsing a partial byte stream, so I modified it to something like this:(I've been hacking around on the code so much trying to figure out my issue, most of my original is gone..)

    from machine import UART
    
    uart = UART(1,9600)
    uart.init(9600, bits=8, parity=None, stop=1)
    while 1:
         data=uart.readall()
         headerbyte=data[0:2]
         if(headerbyte=='bm'):
              print("got header")
    
    

    but pretty much no matter what I've tried to do with the IF statement results in a runtime error.
    Sometimes, it faults on the IF statement with "Nonetype" object not subscriptable
    Othertimes, it seems to indicate there's an error with the following print() statement.
    I even tried things like this:
    if (headerbyte==b'BM'):
    if (1==1):
    if 1==1:
    if L==L:
    if 'L'=='L': and nothing seems to work
    also tried tweaking the print statements. Doesn't matter if I use single or double-quotes.
    Can anyone point to my coding error?



  • @dnear1 said in Fipy issues with IF statements:

    ')

    Cleaned up and comments added

    import os
    import math
    from machine import UART
    
    uart = UART(1, 9600)                         # init with given baudrate
    uart.init(9600, bits=8, parity=None, stop=1) # init with given parameters
    #while True:
    #    data = uart.readall()
    #    if data is not None:
    #       print(data)
    while 1:
        data = uart.readall()# get everything from the serial buffer
        if data is not None:#make sure it's not an empty buffer
            bytestream=data.split(b'BM')[1][0:31]# HPMA sends 32 byte packets that start with \x42\x4D ('BM')
            if len(bytestream)==30:#check that we actually got 30 bytes (excluding the data we split out)
                if bytestream[0:2]==b'\x00\x1c':#HPMA packet is always 28 data bytes(excluding start header and checksum)
                    checksum=143#since split command removed the \x42\x4D, add them back to get correct checksum
                    validated=0
                    for i in range(0,28):
                        checksum+=bytestream[i]#cycle thru the data values and add them up
                    validated=int(bytestream[28])*256+int(bytestream[29])#read checksum bytes from packet and make them a 2-byte integer
                    if checksum==validated:# both values should match, else we have a corrupt packet
                        pm25=int(bytestream[4])*256+int(bytestream[5])#these two bytes represent the particulate detected that's 2.5um large
                        pm10=int(bytestream[6])*256+int(bytestream[7])#these two bytes represent the particulate detected that's 10um large
                        print('pm2.5 = ',pm25)
                        print('pm10 = ',pm10)
                    else:
                        print('checksum failed')
                else:
                    print('invalid packet length')
            else:
                print('incomplete packet')
    
    


  • This is what ultimately worked after getting your pointers.

    import os
    import math
    from machine import UART
    
    uart = UART(1, 9600)                         # init with given baudrate
    uart.init(9600, bits=8, parity=None, stop=1) # init with given parameters
    #while True:
    #    data = uart.readall()
    #    if data is not None:
    #       print(data)
    print ("A")
    
    while 1:
        data = uart.readall()# get everything from the serial buffer
        if data is not None:#make sure it's not an empty buffer
            bytestream=data.split(b'BM')[1][0:31]
            if len(bytestream)==30:
                if bytestream[0:2]==b'\x00\x1c':
                    checksum=143
                    validated=0
                    for i in range(0,28):
                        checksum+=bytestream[i]
                    validated=int(bytestream[28])*256+int(bytestream[29])
                    print('checksum test')
                    if checksum==validated:
                        print('data = ')
                        print(bytestream)
                        pm25=bytestream[4:6]
                        pm10=bytestream[6:8]
                        print('pm2.5 = ')
                        print(pm25)
                        print('\n')
                        print('pm10 = ')
                        print(pm10)
                    else:
                        print('checksum failed')
                        print('data = ')
                        print(bytestream)
                        print('checksum = ')
                        print(checksum)
                        print('validated = ')
                        print(validated)
                        print('bytecheck')
                        print(bytestream[28:30])
                else:
                    print('invalid packet string')
                    print('\n')
                    print(bytestream[0:2])
            else:
                print('invalid packet length')
    


  • @dnear1 If you can accept to see only every second message, you can try the following approach:

    from machine import UART
    
    uart=UART(1)
    
    while True:
        uart.init(timeout_chars=400)  # about 400 ms timeout
        data=b'xx'
        while data is not None:
            data = uart.readall()
        uart.init(timeout_chars=1000)  # about 1 second timeout
        data = uart.readall()
        if data is None:
            print("Oops, no one there?")
        elif data[0:2] == b'BM':
            print("found header")
        else:
            print("messed up, try again")
    

    The code first waits for a timeout of 400ms, at which time the code knows that it's a gap, and then reads a message with a timeout of 1 second, retrieving the full message at once.
    I tried that code with two Pycom device. One as the transmitter, sending your test message once per second, the other with the code above.



  • @dnear1 Sometime MicroPython flags the error at the next line. So it may well be that the line:
    headerdata=data[0:2]
    was failing all the time, because data was None.



  • @robert-hh I'll test your console test tonight or next chance I get to fire everything up.

    Initially, I was trying to use something like header=data.split('bm')[1] to start parsing but I think I was over my skill level. it was halting with syntax errors on that statement, too so I tried to simplify things. I expected that at worse, the if statement should return false and keep looping - but it was halting with errors on the if statements.



  • @dnear1 That's more than strange. Trying the code below works as expected, both on a LoPy4 with v1.18.1.r4 and a Fipy with 1.20.0.rc3.

    >>> b=b'BM\x00\x1C\x00\x00\x00\x04\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Q\x00\x01\x05'
    >>> b[0:2]
    b'BM'
    >>> b[0:2] == b'BM'
    True
    >>> if b[0:2] == b'BM':
    ...     print("True")
    ... 
    True
    >>> 
    

    Besides that, the if statement in your code should be:

        if headerbyte == b'BM:
    

    The real reason for your problem might be, that readall() returns what is there at the time it is called. That may be nothing or any fraction of the message you are expecting. So more likely the if statement works as expected, but data does not contain what you expect.


 

Pycom on Twitter