Communicating with air-conditioner controller using pyserial - python

I am trying to the first time to send and receive information through serial port. The manual for the device with which I am trying to talk can be found here. I am trying for a start to send a set of hexadecimals to ask about the condition of the system and my purpose is to ask in real time about the temperature and store it. Until now my code is this:
import serial
import time
#import serial.tools.list_ports
#ports = list(serial.tools.list_ports.comports())
#for p in ports:
# print p
ser = serial.Serial(port= '/dev/ttyUSB0',
baudrate=9600,
parity=serial.PARITY_EVEN,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS, timeout=0, xonxoff=1, rtscts=1, dsrdtr=1)
command = "\x10\xFF\x29\x2C\x16"
command = command.decode("hex")
ser.write(command)
print command
#time.sleep(10)
ReceivedData = "\n nothing"
while ser.inWaiting() > 0:
ReceivedData = ser.read()
print ReceivedData
The problem is that I cannot get any response.
EDIT:
So I solved the communication problem. It turned out I was using an extension cable so the T and R channels were not correctly connected. Now The response that I receive is "\x00\x10\xFF\x29\x2C\x16" which is the same that I put in only with a \x00 in the front. Does this mean it is an error message? How do I calculate the 4th bit? Until now I am using an example from the manual.

dont use command = command.decode("hex")
just
command = "\x10\xFF\x29\x2C\x16"
ser.write(command)
should work i am sure it expects bytes like this
to put it differently
START_BYTE = "\x10"
ADDR_BYTE = "\xff"
FN_BYTE = "\x29"
CS_BYTE = "\x2C" # We assume you have calculated this right
END_BYTE = "\x16"
msg = START_BYTE+ADDR_BYTE+FN_BYTE+CS_BYTE+END_BYTE
ser.write(msg)
you can abstract this out since start and end and address are always the same
def send_fn(ser,FN_CMD):
START_BYTE = "\x10"
ADDR_BYTE = "\xff"
END_BYTE = "\x16"
CS_BYTE = chr((ord(ADDR_BYTE) + ord(FN_CMD))&0xFF)
msg = START_BYTE+ADDR_BYTE+FN_CMD+CS_BYTE+END_BYTE
ser.write(msg)

Related

After changing from Python 2.7 to Python 3.7 data getting an additional letter?

I'm working on a program that receives a string from an Android app sent through WiFi, the program was originally written for Python 2.7, but after adding some additional functionalities I changed it to Python 3.7. However, after making that change, my data had an extra letter at the front and for the life of me I can't figure out why that is.
Here's a snippet of my code, it's a really simple if statement to see which command was sent from the Android app and controls Raspberry Pi (4) cam (v.2) with the command.
This part sets up the connections and wait to see which command I send.
isoCmd = ['auto','100','200','300','400','500','640','800']
HOST = ''
PORT = 21567
BUFSIZE = 1024
ADDR = (HOST,PORT)
brightness = 50
timelapse = 0
tcpSerSock = socket(AF_INET, SOCK_STREAM)
tcpSerSock.bind(ADDR)
tcpSerSock.listen(5)
while True:
print ('Waiting for connection')
tcpCliSock,addr = tcpSerSock.accept()
try:
while True:
data = ''
brightness = ' '
data = tcpCliSock.recv(BUFSIZE)
dataStr = str(data[1:])
print ("Here's data ",dataStr)
if not data:
break
if data in isoCmd:
if data == "auto":
camera.iso = 0
print ('ISO: Auto')
else:
camera.iso = int(data)
print ('ISO: '), data
When I start the program this is what I see:
Waiting for connection
#If I send command '300'
Here's data b'300'
Here's data b''
Waiting for connection
I'm not sure why there's the extra b'' is coming from. I have tested the code by just adding the "b" at the beginning of each items in the array which worked for any commands that I defined, not for any commands to control the Pi camera since well, there's no extra b at the beginning. (Did that make sense?) My point is, I know I'm able to send commands no problem, just not sure how to get rid of the extra letter. If anyone could give me some advice that would be great. Thanks for helping.
Byte strings are represented by the b-prefix.
Although you can see the string in output on printing, inherently they are bytes.
To get a normal string out of it, decode function can help.
dataStr.decode("utf-8")
b'data' simply means the data inside quotes has been received in bytes form, as mentioned in other answers also, you have to decode that with decode('utf-8') to get it in string form.
I have updated your program below, to be compatible for v3.7+
from socket import *
isoCmd = ['auto','100','200','300','400','500','640','800']
HOST = ''
PORT = 21567
BUFSIZE = 1024
ADDR = (HOST,PORT)
brightness = 50
timelapse = 0
tcpSerSock = socket(AF_INET, SOCK_STREAM)
tcpSerSock.bind(ADDR)
tcpSerSock.listen(5)
while True:
print ('Waiting for connection')
tcpCliSock,addr = tcpSerSock.accept()
try:
while True:
data = ''
brightness = ' '
data = tcpCliSock.recv(BUFSIZE).decode('utf-8')
print ("Here's data "+data)
if not data:
break
if data in isoCmd:
if data == "auto":
camera.iso = 0
print ('ISO: Auto')
else:
camera.iso = int(data)
print ('ISO: '+ data)
except Exception as e:
print(e)

Python xbee library no output for incoming frames

I am using 2 XBee pro S1, I want to read the packets received by the co-ordinator on my PC , it is enabled with API_2 and all other connections are done properly, I can see the packets with XCTU, I am using the python xbee library , but it gives no output :
The Code :
import serial.tools.list_ports
from xbee import XBee
import serial
ports = list(serial.tools.list_ports.comports())
for p in ports: #print the list of ports
print p
def toHex(s):
lst = []
for ch in s:
hv = hex(ord(ch)).replace('0x', '')
if len(hv) == 1:
hv = '0'+hv
hv = '0x' + hv
lst.append(hv)
def decodeReceivedFrame(data):
source_addr_long = toHex(data['source_addr_long'])
source_addr = toHex(data['source_addr'])
id = data['id']
samples = data['samples']
options = toHex(data['options'])
return [source_addr_long, source_addr, id, samples]
PORT = '/dev/ttyUSB0'
BAUD_RATE = 9600
ser = serial.Serial(PORT, BAUD_RATE)
print "Serial ports initialised...."
xbee = XBee(ser,escaped=True)
print "XBee object created"
while True:
try:
response = xbee.wait_read_frame()
sleep(0.5)
decodedData = decodeReceivedFrame(response)
print decodedData
print "data decoded"
except KeyboardInterrupt:
break
ser.close()
The port number and baudrate are connect, I change it to the appropriate portnumber every time I replug the coordinator to my PC.
My output looks like :
Serial ports initialised....
XBee object created
It stays like that and gives no output, even if I see the RX led blinking.
Below is the code written with only pyserial :
import serial
from time import sleep
port = '/dev/ttyUSB0'
baud = 9600
ser = serial.Serial(port, baud)
data = ""
while True:
try:
while ser.in_waiting:
sleep(1)
data = ser.read()
print data
except KeyboardInterrupt:
break
ser.close()
It gives the following output.
Could someone kindly help.
Are you sure you have the correct serial port and baud rate? Does the xbee package support API mode 2? It might only work with API mode 1.
Does that package have methods for accessing the raw byte stream instead of trying to read frames? Can you configure it to throw exceptions on parsing errors?
I would start with just printing response until you see that you're receiving data. And why include the sleep() call in that loop?
I'm not sure what you're trying to accomplish in toHex() but you might want to look at the Python method struct.unpack() or replace all of the work you do on hv with '0x%02X' % ord(ch).

PySerial receive unknown amount of data

Hi I'm working with Python 2 and I'm trying to receive data from an Arduino via Serial Port.
I'm using PySerial to collect the data but I get it chopped and I can't use readline. The size of the array send via serial changes along time.
When I put a very large value to read, it doesn't return a value. I think it keeps waiting until that number of bytes is received.
I would like to know if is a way to get the array complete each time I execute the script.
The code:
class SerialReceiver(serial.Serial):
def __init__(self, portName):
super(SerialReceiver, self).__init__()
self.port = portName
self.baudrate = 115200
self.timeout = None
self.xonxoff = 1
try:
self.open()
except serial.SerialException:
sys.stderr.write("Could not open serial port %s\n" % (portName))
sys.exit(1)
if __name__ == '__main__':
serialReceiver = SerialReceiver('COM3')
while True:
sended = raw_input("Pulsar 'O' para recibir data:")
serialReceiver.write(sended)
data = serialReceiver.read(2048*2)
print data

Reading bytes with PySerial: Empty results (Java works)

I am trying to read bytes from a digital meter via PySerial. It all works with Processing/Java. But i need it to port to Raspberry Pi.
While Java receives the correct bytes, Python does not receive anything at all. The digital meter simply sends 16 bytes delimited by 13.
Working Java / Processing code (receives byte array):
import processing.serial.*;
String portName = "/dev/tty.PL2303-00001004";
myPort = new Serial(this, portName, 9600);
...
if ( myPort.available() > 0)
{
byte[] inBuffer = new byte[16];
myPort.readBytesUntil(13, inBuffer);
println("Buffer: " + inBuffer.length);
}
Not working Python code (receives nothing / ''):
import serial
import time
ser = serial.Serial('/dev/tty.PL2303-00001004', 9600, timeout=None) # tried different timeout
print(ser.isOpen())
while True:
tmp = ser.read()
print tmp
print tmp.__len__()
time.sleep(1)
Reading an Arduino Board with this Python code works fine.
Solution: ser.setDTR(1) got it working!
ser.setDTR(1) got it working! Thanks!
import serial
import time
ser = serial.Serial('/dev/tty.PL2303-00001004', 9600, timeout=None) # tried different timeout
ser.setDTR(1)
print(ser.isOpen())
while True:
tmp = ser.read()
print tmp
print tmp.__len__()
time.sleep(1)

pyserial readline() : SerialException

I'm writing a code used to send order to an avr. I send several information but between each write, I have to wait for an answer (I have to wait for the robot to reach a point on the coordinate system). As I read in the documentation, readline() should at least read until the timeout but as soon as I send the first coordinate, the readline() automatically return :
SerialException: device reports readiness to read but returned no data (device disconnected?)
When I put a sleep() between each write() in the for loop, everything works fine. I tried to use inWaiting() but it still does not work. Here is an example of how I used it:
for i in chemin_python:
self.serieInstance.ecrire("goto\n" + str(float(i.x)) + '\n' + str(float(-i.y)) + '\n')
while self.serieInstance.inWaiting():
pass
lu = self.serieInstance.readline()
lu = lu.split("\r\n")[0]
reponse = self.serieInstance.file_attente.get(lu)
if reponse != "FIN_GOTO":
log.logger.debug("Erreur asservissement (goto) : " + reponse)
Here an snipet how to use serial in python
s.write(command);
st = ''
initTime = time.time()
while True:
st += s.readline()
if timeout and (time.time() - initTime > t) : return TIMEOUT
if st != ERROR: return OK
else: return ERROR
This method allows you to separately control the timeout for gathering all the data for each line, and a different timeout for waiting on additional lines.
def serial_com(self, cmd):
'''Serial communications: send a command; get a response'''
# open serial port
try:
serial_port = serial.Serial(com_port, baudrate=115200, timeout=1)
except serial.SerialException as e:
print("could not open serial port '{}': {}".format(com_port, e))
# write to serial port
cmd += '\r'
serial_port.write(cmd.encode('utf-8'))
# read response from serial port
lines = []
while True:
line = serial_port.readline()
lines.append(line.decode('utf-8').rstrip())
# wait for new data after each line
timeout = time.time() + 0.1
while not serial_port.inWaiting() and timeout > time.time():
pass
if not serial_port.inWaiting():
break
#close the serial port
serial_port.close()
return lines

Categories