Error: PySerial Communication with MKS647C Mass Flow Controller on Linux - python

I'm trying to communicate with the 647C Gas Delivery with PySerial and Linux. The manual is this.
Here's the code that I'm running:
import io
import time
SerialObj=serial.Serial('/dev/ttyUSB0', parity='O') #Odd parity
SerialObj.baudrate = 9600 # set Baud rate to 9600
SerialObj.bytesize = 8 # Number of data bits = 8
SerialObj.stopbits = 1 # Number of Stop bits = 1
SerialObj.timeout=10
if SerialObj.isOpen(): # make sure port is open
print(SerialObj)
print("CONNECTED! :)")
cmd="ID\r\n"
SerialObj.write(cmd.encode())
time.sleep(.2)
msg=SerialObj.read(128)
print(msg.decode("utf-8"))
However, I'm encountering the following error: "E2" which indicates according to the manual that Only one character has been sent instead of the expected 2 byte command.
Any ideas what might be causing this?

Related

PySerial: writing to microcontroller using a while loop adds 100ms to the loop time

I'm trying to do actuator control with values calculated from Python. I am at a point where I want to send the calculated data to a microcontroller in an infinite loop. It seems like ser.write() adds 100ms (total loop execution time of 120ms)
Right now I'm sending the value obtained by my Python code to a microcontroller using PySerial.
Python's data processing side isn't the problem because I checked that the data was being calculated every 20ms.
Below is the code I am using.
import serial as ser
COM = 'COM4'
brate = 115200
ser = ser.Serial()
ser.baudrate=brate
ser.port = COM
while(1):
##Data Calculation Code###
ser.open()
send = bytearray([int(calculated_data)])
ser.write(send)
if(i !=0):
ser.close()
Thank you for your time
I just figured it out after searching a little bit more.
Seems like the serial port doesn't have to be opened and closed everytime.
from serial import Serial
ser = ser.Serial(COM, brate)
Did the trick.

Python Serial not outputting full string

I have the following code running on one computer, and another computer with RS232 DataLogger by Eltima Software reading the serial connection.
When I run the python file on the one computer, only a few characters show up on the other computer, not the full "hellobob"
I have the monitoring computer set at 9600 baud rate, 8 data bits, no parity, one stop bit.
The monitoring computer only picks up "he". I have monitored lots of other devices with the same software, so I know that is working.
This is the python code.
import serial
import io
from time import sleep
ser = serial.Serial('/dev/tty.usbserial-A505VSLL')
sio = io.TextIOWrapper(io.BufferedRWPair(ser, ser))
sio.write(unicode("hellobob\n"))
sleep(5)
sio.flush()
ser.close()
It may be encoding issue. You may simply try following without io module:
import serial
ser = serial.Serial('/dev/tty.usbserial-A505VSLL')
ser.write(b"hellobob\n") # send bytes
ser.close()

Handling time-out for Python-script with RS485 & minimalmodbus

Presently have a read-out on an RS485-bus of 1 (one) RS485 kWh-meter, type DDS238-1ZN by means of a Python-script 'assisted' by module minimalmodbus.
Adding more kWh-meters means that (prior or during installation) the Slave-Adress of the added kWh-meter has to be shifted from the initial '1'.
Such shift-action starts with scanning the RS485-bus to determine where kWh-meter(s) are actually located.
First step is the following simple Python-script
import serial
import minimalmodbus
# Check address 00 = broadcast
instrument = minimalmodbus.Instrument('/dev/ttyAMA0',0) # port name, slave address
instrument.serial.baudrate = 9600
instrument.serial.timeout = 0.5
instrument.debug = True
print instrument
print instrument.read_register(21,0) # registernumber, number of decimals
# Check address 01 = slave 01
instrument = minimalmodbus.Instrument('/dev/ttyAMA0',1) # port name, slave address
print instrument
print instrument.read_register(21,0) # registernumber, number of decimals
# Check address 02 = slave02
instrument = minimalmodbus.Instrument('/dev/ttyAMA0',2) # port name, slave address
print instrument
print instrument.read_register(21,0) # registernumber, number of decimals
The check on Slave-addresses 00 and 01 produces the result (257) as expected, but (due to absence of a device) obviously response on Slave-adress 02 is failing with a time-out.
For further problem-description see http://www.domoticz.com/forum/viewtopic.php?f=31&t=13592#p102901
From test runs, I can see that a time-out occurs.
A time-out-signal could be trigger to step-over to check for next slave-address, if I knew the layout of such time-out-signal for a Python-script with minimalmodbus ....
Searching the internet for an alternative, I see all kind of 'wonderful &elaborate' solutions to trap a time-out, but in the perspective of my simple script I am looking for something very basic (preferably a 'one-liner') to enable stepping out of the time-out to check the next slave-address 3, etc.
Looking at those solutions mentioned above, could perhaps the following setup with semi-code be a simple/basic solution? [for which I have been looking in direction of the C-function fread() ]
start of loop
start time-counter
read register from slave address x
N = number of characters received
if time-counter at value t, then
look if N > 0
if N == 0 then
x = x + 1
jump to start of loop
Any hint for a script using Python or MinimalModbus to perform the semi-code, compatible with the first script?
No working solution found/received in this Forum, but a pragmatic, simple remedy has been developed, tested and put in action, as described at http://www.domoticz.com/forum/viewtopic.php?f=14&t=5808&start=20#p113697
Due to the characteristics of it's data-protocol, the remedy is specific for kWh-meter type DDS238-1ZN, but the idea can possibly be applied for other, comparable kWh-meters with RS485-interface.

Python - multithreading with sockets gives random results

I am really confused about my problem right now. I want to discover an open port over a list of hosts (or subnet).
So first let's show what I've done so far..
from multiprocessing.dummy import Pool as ThreadPool
from netaddr import IPNetwork as getAddrList
import socket, sys
this = sys.modules[__name__]
def threading(ip):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.settimeout(this.timeout)
failCode = 0
try:
if sock.connect_ex((str(ip), this.port)) == 0:
#port open
this.count += 1
else:
#port closed/filtered
failCode = 1
pass
except Exception:
#host unreachable
failCode = 2
pass
finally:
sock.close()
#set thread num
threads = 64
#set socket timeout
this.timeout = 1
#set ip list
ipList = getAddrList('8.8.8.0/24')
#set port
this.port = 53
#set count
this.count = 0
#threading
Pool = ThreadPool(threads)
Pool.map_async(threading, ipList).get(9999999)
Pool.close()
Pool.join()
#result
print str(this.count)
The Script works fine without any error. But I'm struggling about what it prints out..
So if I want to scan for example the subnet 8.8.8.0/24 and discover port 53. I know the only server that has an open dns port is 8.8.8.8 (google-dns).
But when I run my script serveral times the print str(this.count) will randomly (as it seems to me..) return 0 or 1.
What I also know:
Scan only 8.8.8.8 prints always 1
Use only 1 thread for /24 prints always 1
Use 256 threads for /24 prints randomly 0 and 1
changing the timeout doesn't help
So it seems like it has to do with the threading option that causes lags on my computer. But note that my CPU usage is <10% and the network usage is <50%!
But there is also another thing I don't understand..
If print str(this.count) returns 0 I would normally think it is because the threads are in conflict with each other and the socket doesn't get a connection.. but that isn't true because if this.count equals 0, the failCode is set to 1 (on 8.8.8.8)! Which means the port is closed.. but that must be also a bug of my script. I cannot think that this is caused by a lag of the server.. it's google there are no lags..
So additionally we know:
output of 0 is because the server respond that the port is closed
and we are sure the port is definitely open
So I also think about that if I have many threads that run if sock.connect_ex((str(ip), this.port)) == 0: at the same time maybe the host 8.8.8.8 looks in the wrong answer value. Maybe it struggles and look in the response of 8.8.8.7. ..hope you know what I mean.
**max_socket_connections is set to 512 on my linux distribution
Anybody experienced with socket threading and can explain me the situation or give me an answer how to prevent this?
Solved:
.. look at the answer ..
The first mistake was:
But note that my CPU usage is <10% and the
network usage is <50%!
Actually it was a 400 % network usage. I expected bits instead of bytes.
Very embrassing..
And the second mistake was:
and we are sure the port is definitely open
Google does actually block the port after ~5 attempts in a short period of time. They release the restriction after a few seconds or minutes.

Pyserial can't read device

I'm trying to read data off of a sensor that I bought, using a conversion module (SSI to RS232). I have the module plugged into my Windows laptop via USB/serial converter.
When I use Putty in Serial mode, I can send the command $2RD and receive the appropriate response from the sensor unit. When I run a script to try to do the same thing, the unit returns: ''
Here is the code I am using:
import sys
import serial
import time
ser = serial.Serial(
port='COM4',
baudrate=9600,
timeout=1,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS,
)
while True:
ser.write('$2RD'.encode())
#time.sleep(1)
s = ser.read(26)
print s
A few other notes:
I've tried some variations using flushInput, flushOutput, sleeping, waiting, etc...nothing seems to help.
I know I have the COM ports right/the hardware all works in Putty, so pretty sure this is something with my code.
I've also tries 13,400 BAUD with no difference in outcome.
If I connect the TX and RX lines from the USB, I can read the command I'm sending...so it should be at least getting to the RS232/SSI conversion device.
s = ser.read(26) should probably be ser.read(size=26) since it takes keyword argument and not positional argument.
Also, you can try to set a timeout to see what was sent after a specific time because otherwise the function can block if 26 bytes aren't sent as specified in the read docs of pyserial :
Read size bytes from the serial port. If a timeout is set it may return less characters as requested. With no timeout it will block until the requested number of bytes is read.

Categories