Converting a bytearray from a serial port to a float - python

I am writing a python script that will communicate to a Fluke meter over a COM port. I am able to receive the data but want to parse it into a usable float. The code looks like this:
import serial
ser = serial.Serial('COM3', 115200, timeout=1)
#Decalring some variables
FlukeID = b'ID\r'
FlukeQM = b'QM\r'
#Requesting the meters ID to verify connection on terminal
ser.writelines(FlukeID)
line = ser.readline()
print(line)
#Declaring variables for my while loop
thermdata = 0
t=1
ser.writelines(FlukeQM)
thermdata = ser.readline()
while(t < 5):
ser.writelines(FlukeQM)
#thermdata = (thermdata + ser.readline()) /2
thermdata = ser.readline()
print(thermdata)
t+=1
The data returned by the device looks like this on the console:
8.597E3,OHM,NORMAL,NONE INCORRECT
EDIT: The data actually appears like this over the terminal:
b'0\r8.597E3,OHM,NORMAL,NONE\r'
I just want to be able to use the numerical value at the beginning so I can do some calculations over time. I also need to be able to use the scientific notion portion in my number as I will not know the range of my measurements before hand. I know there must be a simple way to do this and would greatly appreciate any help.
On a side note, I would also like to be able to graph these values or place them into some kind of .csv file. If you have any comments on where to look to learn how to do this also that would be great, but I am mostly concerned with the handling of the bytearray.

Use split() to break your string into the comma separated parts. Then the first part is the string '8.597E3', which you convert using the float() function.
s = '8.597E3,OHM,NORMAL,NONE'.split(',')
value = float(s[0])

How about something like:
def atof(text):
try:
return float(text)
except ValueError:
return text
thermdata = b'0\r8.597E3,OHM,NORMAL,NONE\r'
for line in thermdata.strip().split(b'\r'):
print(list(map(atof, line.split(b','))))
# [0.0]
# [8597.0, b'OHM', b'NORMAL', b'NONE']

Related

Combinding serial events into a signal string

I wonder if someone can help me out?
I am reading one line at a time from the serial data on a pi in python.
while True:
try:
ser_bytes= ser.readline()
event = (ser_bytes[0:len(ser_bytes)-2].decode("utf-8"))
print(event)
except Exception as ex:
print(ex)
The data comes in the following format.
Initialize (one time event)
Name
Location
Type
Time/date
Name
Location
Type
Time/date
Name
Location
Type
Time/date
I would like to combine all 4 into a single string (Name-Location-Type-Time/date).
What would be the neatest way of achieving this?
Can't test this since there's no minimal reproducible example, but it should work fine:
ser.readline() # toss out the "initialize" event
lines = []
while True:
for _ in range(4):
new_event = []
try:
ser_bytes = ser.readline()
new_event.append(ser_bytes[0:len(ser_bytes)-2].decode("utf-8"))
except Exception as ex:
print(ex)
lines.append("-".join(new_event))
Basically just running a for loop which reads every four lines, joins them in the Name-Location-Type-Time/date format specified in the question, then adds that new string to an accumulator.

start reading incoming data from a serial port, using pyserial, when a specific character appears

I'm trying to read incoming data from a weight scale (Lexus Matrix One). I want the code to start reading the 8 characters after = appears.
The problem is that sometimes the code does that, and other times it starts reading the data at the middle of the measurement sent by the scale, making it impossible to read properly. I'm using the pyserial module on python 3 on windows.
import serial
ser=serial.Serial("COM4", baudrate=9600)
a=0
while a<10:
b=ser.read(8)
a=a+1
print(b)
the expected result is: b'= 0004.0'
but sometimes I get: b'4.0= 000'
I think we would need a little more information on the format of data coming from your weight scale to provide a complete answer. But your current code only reads the first 80 bytes from the stream, 8 bytes at a time.
If you want to read the next 8 bytes following any equals sign, you could try something like this:
import serial
ser = serial.Serial("COM4", baudrate=9600)
readings = []
done = False
while not done:
current_char = ser.read()
# check for equals sign
if current_char == b'=':
reading = ser.read(8)
readings.append(reading)
# this part will depend on your specific needs.
# in this example, we stop after 10 readings
# check for stopping condition and set done = True
if len(readings) >= 10:
done = True

Arduino to Python - is serial input from readline() an integer or an actual string?

So I'm sending a bunch of serial data from my Arduino 2560 Mega to my Python program, where I will be acting on integer data only. Initially, my Arduino calibrates a bunch of things, serially-printing confirmation information...then it starts to take temperature values from an LM35. Those temperature values then get serially printed.
I either:
a) Want to know how to use Python's readline() function when an integer is received starting when the temperature readings start getting printed serially.
OR
b) Test the incoming string from readline() from the start, determining when the numbers I care about start getting received.
And yes, treat these temperature values as integers not floats.
Right now, here's what I'm doing:
while(1==1):
if (s.inWaiting() > 0):
myData = s.readline()
time = myData
value = int(time.strip('\0'))
if (time.isDigit()):
# do stuff
I receive the error:
value = int(time.strip('\0'))
ValueError: invalid literal for int() with base 10: 'Obtaining color values for: Saline/Air\r\n'
Which makes sense because the string literal 'Obtaining color values for:Saline/Air\r\n', even after stripping, would never convert via the int() function.
Also let me know if .isDigit() is even necessary (or for that matter, being used correctly). I just started working with Python a couple weeks ago so it's all up in the air from my perspective.
You can do the following to convert a string to an integer:
while(1==1):
if (s.inWaiting() > 0):
myData = s.readline()
try:
# This will make it an integer, if the string is not an integer it will throw an error
myData = int(myData)
except ValueError: # this deals will the error
pass # if we don't change the value of myData it stays a string
Example
Here is an example you can try.
In Python:
import serial
# Converts to an integer if it is an integer, or it returns it as a string
def try_parse_int(s):
try:
return int(s)
except ValueError:
return s
ser = serial.Serial('/dev/ttyACM0', 115200)
while True:
data = ser.readline().decode("utf-8").strip('\n').strip('\r') # remove newline and carriage return characters
print("We got: '{}'".format(data))
data = try_parse_int(data)
print(type(data))
On my Arduino:
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
}
void loop() {
// put your main code here, to run repeatedly:
Serial.println(1);
delay(1000);
Serial.println("test");
delay(1000);
}
This will produce:
We got: 'test'
<class 'str'>
We got: '1'
<class 'int'>
You should catch the exception.
while True:
if s.inWaiting() > 0:
myData = s.readline()
try:
value = int(mydata.strip('\0'))
except ValueError:
# handle string data (in mydata)
else:
# handle temperature reading (in value)
So if the value can be converted to an int, the else block runs. If the value is a string, the except block runs.

Barometer data from Adruino to RPi. Python error with readline()

Been trying to fix this. The barometer data on the Adruino looks like this:
1008.94
1008.95
1008.94
Which I'm happy with. These get "read" every 10 second for now.
The problem is with my python script. I can read and write all the data to my mySQLdb. But the the data is not always good. It will go like something like:
1008.94
108.95
108.94
1008.96
The "lost zero" or other value always appears on the Adruino's serial monitor.
How can I get the python script to read the whole xxxx.xx line? Just thought even at times of low pressure xxx.xx.
Here is my python code:
import MySQLdb
import serial
import time
ser = serial.Serial('/dev/ttyACM0', 9600)
db = MySQLdb.connect("localhost", "root", "pword","weather")
cursor = db.cursor()
while 1:
# print ("Waiting for data...")
# print("")
x = ser.readline()
clock = (time.strftime("%H:%M:%S"))
print x
# print ("Collecting data...")
x = x
# print ("Inserting to database...")
# print ("")
sql = ("""INSERT INTO WeatherP (pres, Time) VALUES (%s, %s)""", (x, clock,))
cursor.execute(*sql)
db.commit()
#
Thank you.
Tinus
I found the following here:
ser.read(ser.inWaiting())
According to the pySerial documentation inWaiting() does return the size of the received data in the buffer. This could solve your problem because the read function has a size of data it takes given by a parameter (in your case 1 byte since you haven't specified) if the received data is larger it might cause such problems.

sending and recieving through serial

I have got a simple program running in the uno that measures the distance using ping sensor and now i am trying to control some servos based on the distance in python but the conditional thingy is not working even in a simple code like this
import serial
data = serial.Serial('COM7',9600)
while(1):
if(data.inWaiting()>0):
dist = data.readline()
if(dist>100):
print("dist is greater than 100")
else:
print("this shit does not work")
It is always the if that works, I am a noob please help me!
Data from serial port type is str
You are trying to read the data and use if .... > 100 this will never work.
You need to read the data to a buffer and then check it, Also you need some sync frame to know you have got all the data(it's not a must but its much eaiser)
for example let say the read data is 100! and ! is your sync frame.
import serial
my_serial = serial.Serial('COM7',9600)
my_data = ""
while(1):
if(my_serial.inWaiting()>0):
my_data = my_serial.readline()
if '!' in my_data:
break
my_data = [:my_data.find("!")]
if int(my_data) > 100:
print("dist is greater than 100")
else:
print("this shit does not work")

Categories