Read from serial in Python - python

I have a weight scale
Which is connected to the serial port, and I'm trying to know the weight is currently reading.
This is the code I'm using in Python.
import serial
s = serial.Serial(port="COM3")
s.read(10)
It makes the connection but it just keeps loading and doesn't give any output.
I also Tried:
ser = serial.Serial()
ser.baudrate = 9600
ser.port = 'COM3'
print(ser)
and this is the output:
Serial<id=0x192eaed4c40, open=True>(port='COM3', baudrate=9600, bytesize=8, parity='N',
stopbits=1, timeout=None, xonxoff=False, rtscts=False, dsrdtr=False)
Thank you.

If the device you are connected to, doesn't write 10 bytes, your read call will block until it has gotten all those 10 bytes.
Typically, you as a reader have to say to the device that "hey, im here, could you give me data", and only then they will return you something. Also, you can check ser.in_waiting property to see if there is any data that can be read (and how much of data there is)

import serial
ser = serial.Serial(
port = "COM2",
timeout = 1,
baudrate=9600,
parity=serial.PARITY_EVEN,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.SEVENBITS,
)
ser.write(str.encode("W"))
weight = ser.read(8)
print(weight.decode('ascii'), weight)

You want to get the input from the weight scale device. You should follow the following steps:
Firstly, check the connection between the device and computer is normal (cable, USB port, computer). You can use the terminal software.
If the connection is ok. Now let's start with the following code:
port='COM8',
baudrate = 2400,
parity=serial.PARITY_EVEN,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.SEVENBITS,
timeout=None
)
while 1:
x = ser.readline()
print(x)

Related

How to solve Pymodbus exception when Master requests for holding registry values of the Arduino Slave

I currently trying to receive data from my Arduino slave to my computer. I am successful in creating an Arduino slave. However, when I am trying to receive the data from my computer using the Pymodbus library, my code fails to receive the data from the Arduino and raises a ModbusIOException. For the specifications of my project, I am trying to build a Modbus RTU with the Arduino to simulate a sensor with random numbers as readings. The Arduino code uses the Modbus-Arduino library of Andre Sarmento.
https://github.com/andresarmento/modbus-arduino
I already checked my Arduino slave if it is working. I tried reading the data through a Modbus Master emulator (QModMaster), and it worked just fine. This might prove that the problem itself is from the code for the Master. Furthermore, the serial connection seems to work fine, since the self.client.connect() returns True.
These are the screenshots of the QModMaster configurations.
Slave configurations
Serial Port configurations
Python code for the master:
class ModbusRTU:
def __init__(self, graph_name, port, baudrate=9600,
stopbits=1, bytesize=8, parity='N',
timeout=1):
self.graph_name = graph_name
self.client = ModbusSerialClient(method='rtu',
port=port,
baudrate=baudrate,
parity=parity,
timeout=timeout)
self.connection = self.client.connect()
result = self.client.read_holding_registers(address=0,
count=2,
unit=1)
print(result.registers)
if __name__ == '__main__':
modbus = ModbusRTU(graph_name='/dev/ttyACM0',
port='/dev/ttyACM0', baudrate=9600,
stopbits=1, bytesize=8, parity='N',
timeout=1)
print(modbus.check_connection())
Arduino code for the simulated slave and sensor:
#include <Modbus.h>
#include <ModbusSerial.h>
ModbusSerial mb;
const int READING = 0;
const int DECIMAL = 1;
void setup() {
mb.config(&Serial, 9600, SERIAL_8N1);
mb.setSlaveId(1);
mb.addHreg(READING);
mb.addHreg(DECIMAL);
}
void loop() {
mb.task();
mb.Hreg(READING, random(1, 201));
mb.Hreg(DECIMAL, random(0, 4));
}
Upon printing the results.registers, it is supposedly a list of integers. However, it just raises a ModbusIOException with a message of:
'ModbusIOException' object has no attribute 'registers'
File "/home/kebaranas/PythonProjects/ThirsyWell/tools/utilities.py", line 21, in __init__
print(result.registers)
File "/home/kebaranas/PythonProjects/ThirsyWell/tools/utilities.py", line 29, in <module>
timeout=1)
It also gives this message as well.
Modbus Error: [Input/Output] Modbus Error: [Invalid Message] Incomplete message received, expected at least 2 bytes (0 received)
Before print(result.registers) try the following code snippet:
if not result.isError():
print(result.registers)
else:
print("error: {}".format(result))
Also, fill in other ModbusSerialClient() argument.
Here is updated of your code snippet:
from pymodbus.client.sync import ModbusSerialClient
class ModbusRTU:
def __init__(self, graph_name, port, baudrate=9600,
stopbits=1, bytesize=8, parity='N',
timeout=1):
self.graph_name = graph_name
self.client = ModbusSerialClient(
method='rtu',
port=port,
baudrate=baudrate,
parity=parity,
timeout=timeout,
stopbits=stopbits,
bytesize=bytesize
)
self.connection = self.client.connect()
result = self.client.read_input_registers(address=1,
count=2,
unit=1)
if not result.isError():
print(result.registers)
else:
print("error: {}".format(result))
if __name__ == '__main__':
modbus = ModbusRTU(
graph_name='/dev/ttyACM0',
port='/dev/ttyACM0', baudrate=9600,
stopbits=1, bytesize=8, parity='N',
timeout=1
)
You're defining holding registers in your slave but you're trying to read them as input registers, try changing this line:
result = self.client.read_input_registers(address=1, count=2, unit=1)
To:
result = self.client.read_holding_registers(address=1, count=2, unit=1)
Be aware that the Modbus spec defines this two different types of registers: holding and input, depending on the memory region they are placed in.
I already found out the solution for this thanks for the help of few people. The QModMaster uses a library called libmodbus. Since the Arduino simulated slave and sensor worked with QModMaster, it would be easier to change the previous library and instead use libmodbus. Luckily, there is a python equivalent for libmodbus which is pylibmodbus. This is the link for the library https://github.com/stephane/pylibmodbus.
from pylibmodbus import ModbusRtu
class ModbusRTU:
def __init__(self, port, baudrate=9600, databit=8, parity='None',
stopbit=1, timeout=1000):
self.parity = {'Odd': 'O', 'Even': 'E', 'None': 'N'}
self.modbus = ModbusRtu(device=port.encode('ascii'),
data_bit=databit, baud=baudrate,
parity=self.parity[parity] \
.encode('ascii'),
stop_bit=stopbit)
self.modbus.set_response_timeout(timeout/1000)
self.modbus.connect()
self.modbus.set_slave(1)
result = self.modbus.read_registers(0, 2)
print(result)
self.modbus.close()
if __name__ == '__main__':
main = ModbusRTU('/dev/ttyACM0', baudrate=9600, databit=8,
parity='None', stopbit=1)

how to read and write with different scripts to a serial port same tim?

I currently have two scripts one to write to the serial port and another one to read from the serial port, both are working fine with the individual jobs. What I also wanted to try is running both the scripts at the same time and I would like to see the write input to the serial port as an output from the read script. I am missing something in between, this particular case is not working.
ser = serial.Serial()
ser.baudrate = baudrate
ser.port = port
ser.timeout = timeout
A sample of read:
while True:
line = ser.readline().encode('hex')
print line
I have also tried with
While True:
bytesToRead = ser.inWaiting()
ser.read(bytesToRead)
I write to the serial port using ser.write(command)

pySerial: how to check the current baud rate

I have a device (GT511C3 fingerprint scanner) that I am connecting to Raspberry Pi and programming it using Python Serial module. The GT511 device has a default baud rate of 9600, and there is capability of changing the it. Once you change the GT511 baudrate, it keeps this setting until next restart.
The question is if there is a way for me to check the current baud rate of the connected device (in case the device was already programmed, and connected by a different host). I know it is possible to do it using stty:
$> stty < /dev/ttyAMA0
speed 57600 bud; line = 0
...
Is there a way to do it using Python serial or any other module, or do I have to write an iterative checking procedure to find it out?
UPDATE 1:
Current solution I use to find the accepted baud rate:
ser = serial.Serial('/dev/ttyAMA0')
ser.timeout = 0.5
for baudrate in ser.BAUDRATES:
if 9600 <= baudrate <= 115200:
ser.baudrate = baudrate
ser.write(packet)
resp = ser.read()
if resp != '':
break
if ser.baudrate > 115200:
raise RuntimeError("Couldn't find appropriate baud rate!")
UPDATE 2:
Please, stop suggesting serial.baudrate - this is NOT what I am asking.
Maybe you shoul use stty until you find a better alternative.
You can call it from Python code and parse the result to obtain what you need.
Here is a basic example (not tested):
import subprocess
import shlex
def get_baudrate(device):
command = 'stty < {0}'.format(device)
proc_retval = subprocess.check_output(shlex.split(command))
baudrate = int(proc_retval.split()[1])
return baudrate
Found your question while searching, and this is working great for me:
import serial
def baud_rate_test(serial_port, packet = b' '):
ser = serial.Serial(serial_port)
ser.timeout = 0.5
for baudrate in ser.BAUDRATES:
if 300 <= baudrate <= 57600:
ser.baudrate = baudrate
ser.write(packet)
resp = ser.readall()
if resp == packet:
return baudrate
return 'Unknown'
a = baud_rate_test('/dev/ttyUSB1')
print(a)
The devices I have checked it with to this point echo back the "b' '" with no issue. I do plan on testing it on more devices as time goes on, and I'm thinking I may need to change the "test packet" and the response criteria.
The resp != '': line didn't work for me -- because different "weird" characters are returned at different baud rates.

How do I get my GPIB interface to communicate correct values with python?

I have gotten the Simulator to finally start communicating back to me (see past question); however, I do not know what it is saying to me. Here is a simple code that sends a message to the simulator.
`import serial
port = '/dev/tty.usbserial-PXFO5L2L'
baudrate = 9600
timeout = 1
ser = serial.Serial(port = port, baudrate = baudrate, timeout = timeout)
ser.write('VOLT:LEVEL 4')
`
This is supposed to set the voltage 4, but all it returns is 12. Along with other commands, they all return ints. Can anyone tell me what this means? Or if I am using the write command correctly?

python3 sending serial data to Nextion Display

I'm trying to control a Nextion Display via a Python3 script.
Using Windows Terminal I'm able to control it.
For example to change the text of a control I send the following:
t0.txt="test" followed by 3 time 0xFF via "send hex"
My Python3 script using PySerial is the following:
import serial
s = serial.Serial(port='COM5',baudrate=9600)
escape='\xff'.encode('iso-8859-1')
test=b't0.txt="test"'
s.write(test)
s.write(escape)
s.write(escape)
s.write(escape)
s.close()
but it is not working.
Any ideas?
Thank you so much
Read bytes from nextion EEPROM on raspberry pi3 on gpiopins.
#import time
import serial
ser = serial.Serial(
port='/dev/ttyS0',
baudrate =9600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS,
timeout=1)
commandToSend = b'rept 0,32\xff\xff\xff' #read 32 bytes of hex data from EEPROM to UART, start address is 0
while True:
ser.write(commandToSend)
#time.sleep(0.5)
x=ser.readline()
print (x)
You may try the following code below:
import serial
import time
import struct
ser = serial.Serial("/dev/ttyAMA0")
print ser
time.sleep(1)
i=1
k=struct.pack('B', 0xff)
while True:
ser.write(b"n0.val=")
ser.write(str(i))
ser.write(k)
ser.write(k)
ser.write(k)
print " NEXT"
time.sleep(1)
i=i+1
import time
import serial
ser = serial.Serial(
port='/dev/ttyAMA0',
baudrate = 9600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS,
timeout=1
)
while 1:
EndCom = "\xff\xff\xff"
write('t0.txt="Hello World"'+EndCom)

Categories