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.