I am trying to use a variable to pass a string to the serial.Serial function in python. The following works the way I want it to:
port = serial.Serial("/dev/ttyAMA0", baudrate=9600,bytesize=serial.SEVENBITS,stopbits=serial.STOPBITS_ONE,parity=serial.PARITY_EVEN,timeout=3.0)
However if I try to put the string into a variable like so and then call the function with the variable I get an error.
serialString = '"/dev/ttyAMA0",baudrate=9600,bytesize=serial.SEVENBITS,stopbits=serial.STOPBITS_ONE,parity=serial.PARITY_EVEN,timeout=3.0'
port = serial.Serial(serialString)
Here is the error:
Traceback (most recent call last): File "./cncserver.py", line 34,
in
port = serial.Serial(serialString) File "/usr/lib/python2.7/dist-packages/serial/serialutil.py", line 260, in
init
self.open() File "/usr/lib/python2.7/dist-packages/serial/serialposix.py", line 276, in
open
raise SerialException("could not open port %s: %s" % (self._port, msg)) serial.serialutil.SerialException: could not open port
"/dev/ttyAMA0",baudrate=9600,bytesize=serial.SEVENBITS,stopbits=serial.STOPBITS_ONE,parity=serial.PARITY_EVEN,timeout=3.0:
[Errno 2] No such file or directory:
'"/dev/ttyAMA0",baudrate=9600,bytesize=serial.SEVENBITS,stopbits=serial.STOPBITS_ONE,parity=serial.PARITY_EVEN,timeout=3.0'
I'm guessing it's something to do with the filepath in the string not being quoted properly but I've spent enough time trying to figure it out, can somebody help me here please?
Thanks,
Lorne
Here is my revised code:
#parameter settings of the serial port on the PI must match the control
serialPort = "/dev/ttyAMA0"
serialBaudRate = 9600
serialByteSize = serial.SEVENBITS
serialStopBits = serial.STOPBITS_ONE
serialParity = serial.PARITY_EVEN
serialTimeout = 3.0
port = serial.Serial(serialPort,serialBaudRate,serialByteSize,serialStopBits,serialParity,serialTimeout)
Here is the new error:
Traceback (most recent call last): File "./cncserver.py", line 39,
in
port = serial.Serial(serialPort,serialBaudRate,serialByteSize,serialStopBits,serialParity,serialTimeout)
File "/usr/lib/python2.7/dist-packages/serial/serialutil.py", line
250, in init
self.parity = parity File "/usr/lib/python2.7/dist-packages/serial/serialutil.py", line 344, in
setParity
if parity not in self.PARITIES: raise ValueError("Not a valid parity: %r" % (parity,)) ValueError: Not a valid parity: 1
port = serial.Serial("/dev/ttyAMA0", baudrate=9600,bytesize=serial.SEVENBITS,stopbits=serial.STOPBITS_ONE,parity=serial.PARITY_EVEN,timeout=3.0)
is not the same as
port = serial.Serial('"/dev/ttyAMA0",baudrate=9600,bytesize=serial.SEVENBITS,stopbits=serial.STOPBITS_ONE,parity=serial.PARITY_EVEN,timeout=3.0')
This is not a string, but function parameters that have been passed as key_pair values.
"/dev/ttyAMA0", baudrate=9600,bytesize=serial.SEVENBITS,stopbits=serial.STOPBITS_ONE,parity=serial.PARITY_EVEN,timeout=3.0
sends 6 different parameters to the function, :-
/dev/ttyAMA0
baudrate as 9600
bytesize as serial.SEVENBITS
stopbits as serial.STOPBITS_ONE
parity as serial.PARITY_EVEN
timeout as 3.0
'"/dev/ttyAMA0",baudrate=9600,bytesize=serial.SEVENBITS,stopbits=serial.STOPBITS_ONE,parity=serial.PARITY_EVEN,timeout=3.0'
sends only one parameter as
'"/dev/ttyAMA0",baudrate=9600,bytesize=serial.SEVENBITS,stopbits=serial.STOPBITS_ONE,parity=serial.PARITY_EVEN,timeout=3.0'
as for what you are trying to do,
initialize :
args = ("/dev/ttyAMA0",)
kwargs= {'baudrate':9600,'bytesize':serial.SEVENBITS,'stopbits':serial.STOPBITS_ONE,'parity':serial.PARITY_EVEN,'timeout':3.0}
and call them wherever you want
port = serial.Serial(*args, **kwargs)
Related
I have a RPI with a USB CH340 dongle connected to a EM340 energy meter. It works fine with the code below.
When I connect 2 x EM340 energy meters I get the following error:
pi#raspberrypi:~ $ python3 modbus_test.py
Traceback (most recent call last):
File "modbus_test.py", line 21, in <module>
freq2 = instrument.read_register(0x0033,1) # Registernumber, number of decimals
File "/home/pi/.local/lib/python3.7/site-packages/minimalmodbus.py", line 486, in read_register
payloadformat=_Payloadformat.REGISTER,
File "/home/pi/.local/lib/python3.7/site-packages/minimalmodbus.py", line 1245, in _generic_command
payload_from_slave = self._perform_command(functioncode, payload_to_slave)
File "/home/pi/.local/lib/python3.7/site-packages/minimalmodbus.py", line 1330, in _perform_command
response, self.address, self.mode, functioncode
File "/home/pi/.local/lib/python3.7/site-packages/minimalmodbus.py", line 1867, in _extract_payload
raise InvalidResponseError(text)
minimalmodbus.InvalidResponseError: Checksum error in rtu mode: '6ý' instead of '\x99ò' . The response is: '\x01\x01\x00\x00\x166ý' (plain response: '\x01\x01\x00\x00\x166ý')
My code:
import minimalmodbus
import serial
instrument = minimalmodbus.Instrument('/dev/ttyUSB0', 1) # port name, slave address (in decimal)
#instrument.serial.port # this is the serial port name
instrument.serial.baudrate = 9600 # Baud
instrument.serial.bytesize = 8
#instrument.serial.parity = serial.PARITY_NONE
instrument.serial.stopbits = 1
instrument.serial.timeout = 0.2 # seconds
instrument.address = 1 # this is the slave address number
#instrument.mode = minimalmodbus.MODE_ASCII # rtu or ascii mode
instrument.mode = minimalmodbus.MODE_RTU
instrument.clear_buffers_before_each_transaction = True
instrument.close_port_after_each_call = True
## Read temperature (PV = ProcessValue) ##
freq2 = instrument.read_register(0x0033,1) # Registernumber, number of decimals
txt = "Frekvens: {} Hz".format(freq2)
#0x0034
kwh_total = instrument.read_register(0x0400)
kwh_total_2 = instrument.read_register(0x0402)
txt2 = "Total forbrug: {0}.{1} kWh".format(kwh_total,kwh_total_2)
w_l1 = instrument.read_register(0x0012,1) # Registernumber, number of decimals
txt3 = "Nuværende forbrug: {} W".format(w_l1)
print(txt)
print(txt2)
print(txt3)
I have wired the 2xEM340 according to the https://web.evishine.dk/wp-content/uploads/2019/11/EM340-ENG.pdf page 3.
Any idea why I get Checksum error in rtu mode ?
As per the comments if you attach two Modbus RTU devices with the same ID in parallel then they will both respond to any request addressed to that Slave ID. The responses will probably collide which means your code will receive a garbled response (detected via the CRC).
The solution is to change the ID of one of the devices.
I am having issues with the socket only recieving data, but not the address so I cannot send packets such as an acknowledgement to the original sender. I am implementing a go-back-N with a sender and receiver.
Here is the error:
Traceback (most recent call last):
File "./netster.py", line 128, in <module>
main()
File "./netster.py", line 120, in main
run_server(args.host, int(args.port), udp=args.udp, rudp = args.rudp, filename=f)
File "./netster.py", line 27, in run_server
rudp_gobackn_recv(port, kwargs['filename'])
File "/Users/a3.py", line 352, in rudp_gobackn_recv
data, client_address = serversocket.recv(1500)
ValueError: too many values to unpack (expected 2)
Here is the receiver side of things, a code snippet showing how I initalize the packet and receive the data.
serversocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
serversocket.bind(('localhost', port))
...
data, client_address = serversocket.recv(1500)
This is how I set up the sender socket:
clientsocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_address = (host, port)
Both the sender and receiver have the address and port as
('localhost', 1234)
1234 is an arbitrary port number.
Here is how I set up the packets to send, just in case it matters, and how I send it.
for x in range(len(window), window_size):
data = file.read(data_size)
if not data:
end_bit = '1'
decoded_data = data.decode('utf-8')
packet = str(nextseqnum) + "##" + str(end_bit) + "##" + str(decoded_data)
nextseqnum = str(int(nextseqnum) + 1)
window.append(packet)
if not data:
break
Here is how I send it:
for y in range(0, len(window)):
print("Window: ", window)
print("PACKET!!!!", window[y])
packet = window[y]
p = packet.encode('utf-8')
print("Socket ouput: ", clientsocket.sendto(p, server_address))
if(y == 0):
oldest_time = time.time()
If I change the receiver code so it can compile to this:
data = serversocket.recv(1500)
The sender side of things prints out:
Window: ['1##0##abcdefghijklmnopqrstuvwxyz\n', '2##1##']
PACKET!!!! 1##0##abcdefghijklmnopqrstuvwxyz
Socket ouput: 33
Window: ['1##0##abcdefghijklmnopqrstuvwxyz\n', '2##1##']
PACKET!!!! 2##1##
Socket ouput: 6
Any thoughts on why it sends only the data, but not the server address? I've researched the issue but have had no success, as well as debugging it for awhile.
serversocket.recv(1500) only returns bytes, not data, client_address. You're looking for recvfrom.
And this should enlighten you as to why you get the error you do:
>>> data, client_address = b"hello"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 2)
>>> a, b, c, d, e = b"hello"
>>> a, b, c, d, e
(104, 101, 108, 108, 111)
I would like to control an actuator with a python script in MODBUS RTU
master. I tried to use the library minimalmodbus to communicate (write
bit, write & read registers) with my slave.
When I start my code, I have some errors. So, someone can I help me to find a solution?
My code:
import minimalmodbus
import os
import struct
import sys
import serial
import time
instrument = minimalmodbus.Instrument('/dev/ttyRS485', 1)
instrument.serial.port
instrument.serial.baudrate = 9600
instrument.serial.parity = serial.PARITY_NONE
instrument.serial.bytesize = 8
instrument.serial.stopbits = 1
instrument.mode = minimalmodbus.MODE_RTU
instrument.serial.timeout = 0.05
modbus = instrument.write_bit(0x0427, 1)
print (modbus)
alarme = instrument.write_bit(0x0404, 1)
print (alarme)
alarme = instrument.write_bit(0x0404, 0)
print (alarme)
on = instrument.write_bit(0x0403, 1)
print (on)
home = instrument.write_bit(0x040B, 1)
print (home)
position = instrument.write_register(0x9900, 0, number_of_decimals=2,functioncode=16, signed=False)
print (position)
posi = instrument.write_register(0x9901, 6000, number_of_decimals=2,functioncode=16, signed=False)
print (posi)
Errors:
========================= RESTART: /home/pi/test.py =========================
None
None
None
None
None
None
Traceback (most recent call last):
File "/home/pi/.local/lib/python3.5/site-packages/minimalmodbus.py", line 2448, in _pack
result = struct.pack(formatstring, value)
struct.error: 'H' format requires 0 <= number <= 65535
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/pi/test.py", line 36, in <module>
posi = instrument.write_register(0x9901, 6000, number_of_decimals=2, functioncode=16, signed=False)
File "/home/pi/.local/lib/python3.5/site-packages/minimalmodbus.py",line 518, in write_register
payloadformat=_PAYLOADFORMAT_REGISTER,
File "/home/pi/.local/lib/python3.5/site-packages/minimalmodbus.py",line 1166, in _generic_command
payloadformat,
File "/home/pi/.local/lib/python3.5/site-packages/minimalmodbus.py",line 1514, in _create_payload
value, number_of_decimals, signed=signed
File "/home/pi/.local/lib/python3.5/site-packages/minimalmodbus.py", line 1991, in
_num_to_twobyte_string outstring = _pack(formatcode, integer)
File "/home/pi/.local/lib/python3.5/site-packages/minimalmodbus.py", line 2454, in _pack
raise ValueError(errortext.format(value, formatstring))
ValueError: The value to send is probably out of range, as the num-to-bytestring conversion failed.
Value: 600000 Struct format code is: >H
In response to your request in the comments for an alternative library, here is what I use to read modbus with the pymodbus library:
import pymodbus
from pymodbus.pdu import ModbusRequest
from pymodbus.client.sync import ModbusSerialClient as ModbusClient
from pymodbus.transaction import ModbusRtuFramer
client = ModbusClient(
method = 'rtu'
,port='/dev/tty.usbserial-AQ00BYCR'
,baudrate=38400
,parity = 'O'
,timeout=1
)
connection = client.connect()
registers = client.read_holding_registers(0,100,unit=1)# start_address, count, slave_id
print (registers.registers)
Note that in the above, the reading begins from address 0 and continues to address 100, for slave_id 1.
To write registers, do the following:
write = client.write_register(1,425,unit=1)# address = 1, value to set = 425, slave ID = 1
I am writing a multi-threaded client/server program. It splits a large file into smaller files in its client side and sends the smaller files to the server concurrently.
The problem is that in every run, the server can only receive two of the smaller files (the first one and another random one). Meanwhile, I encounter the error: "[Errno 32] Broken pipe" in client side of the program in s.sendall(part). The error arises in every thread that starts to send one of the smaller files before reception of the first file (on the server). In other words, every thread that starts to send after the reception the first file (on the server) can complete its task.
I run each of the client and server codes on different computers (both have the following specification: Ubuntu 14.04 desktop, 64 bit, 16GiB ram)
Client side Error:
Traceback (most recent call last):
File "Desktop/File_transmission/Client.py", line 56, in sendSplittedFile
s.sendall(part)
File "/usr/lib/python2.7/socket.py", line 224, in meth
return getattr(self._sock,name)(*args)
error: [Errno 32] Broken pipe
Client.py:
import random
import socket
import time
import threading
import errno
import select
import File_manipulation
import sys, traceback
class Client:
nodesIpAddr = ["....", "...."] #Server = ....
dataPort = 45678
delay = 2
inputFileAddress = 'tosend.dat'
fileOutputPrefix = 'output'
fileOutputSuffix = ".dat"
bufferSize = 2048
max_size_splitted_file = 10*(2**20) # 10 MiB
def __init__ (self, my_ip):
self.ip = my_ip
def send(self, ip_toSend, dataPort):
print "\tSend function is runing."
totalNumSplittedFile = File_manipulation.split_file(Client.inputFileAddress, Client.fileOutputPrefix, Client.max_size_splitted_file , Client.bufferSize)
for i in range(0, totalNumSplittedFile):
thread_send = threading.Thread(target = self.sendSplittedFile, args = (ip_toSend, dataPort, Client.bufferSize, i, Client.fileOutputPrefix, totalNumSplittedFile))
thread_send.start()
def sendSplittedFile(self, ip_toSend, dataPort, bufferSize, fileNumber, fileNamePrefix, totalNumSplittedFile):
# Create a socket (SOCK_STREAM means a TCP socket)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
BUFFER_SIZE = bufferSize
try:
s.connect((ip_toSend, dataPort))
f = open(fileNamePrefix + '.%s' % fileNumber,'rb')
s.send(str(fileNumber) + " " + str(totalNumSplittedFile))
part = f.read(BUFFER_SIZE)
while (part):
s.sendall(part)
part = f.read(BUFFER_SIZE)
f.close()
s.sendall(part)
time.sleep(Client.delay)
s.sendall('EOF')
print "Done Sending."
print s.recv(BUFFER_SIZE)
s.close()
print "\tData is sent to ", ip_toSend,
except socket.error, v:
traceback.print_exception(*sys.exc_info())
s.close()
nodeIP = [(s.connect(('8.8.8.8', 80)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]
n = Client(nodeIP)
n.send(n.nodesIpAddr[0], n.dataPort)
Server Side Error:
Traceback (most recent call last):
File "/usr/lib/python2.7/SocketServer.py", line 295, in _handle_request_noblock
self.process_request(request, client_address)
File "/usr/lib/python2.7/SocketServer.py", line 321, in process_request
self.finish_request(request, client_address)
File "/usr/lib/python2.7/SocketServer.py", line 334, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "/usr/lib/python2.7/SocketServer.py", line 649, in __init__
self.handle()
File "Desktop/File_transmissionServer.py", line 37, in handle
totalFileNumber = int(details[1])
ValueError: null byte in argument for int()
Server.py
import socket
import time
import threading
import errno
import select
import SocketServer
import File_manipulation
class ServerThreadHandler(SocketServer.BaseRequestHandler):
nodesIpAddr = ["....", "...."] #Server = ....
fileOutputPrefix = 'torec '
fileOutputSuffix = '.dat'
dataPort = 45678
delay = 3
maxNumClientListenedTo = 200
timeout_in_seconds = 5
bufferSize = 2048
totalFileNumber = 0 #Total number of splitted files. It should be set by the incoming packets
def handle(self):
BUFFER_SIZE = ServerThreadHandler.bufferSize # Normally 1024, but we want fast response
# self.request is the TCP socket connected to the client
data = self.request.recv(BUFFER_SIZE)
addr = self.client_address[0]
details = str(data).split()
currentFileNum = int(details[0])
totalFileNumber = int(details[1])
print '\tReceive: Connection address:', addr,'Current File Number: ', currentFileNum, 'Total Number of splitted files: ', totalFileNumber
f = open(ServerThreadHandler.fileOutputPrefix + '_Received.%s' % currentFileNum, 'wb')
data = self.request.recv(BUFFER_SIZE)
while (data and data != 'EOF'):
f.write(data)
data = self.request.recv(BUFFER_SIZE)
f.close()
print "Done Receiving." ," File Number: ", currentFileNum
self.request.sendall('\tThank you for data. File Number: ' + str(currentFileNum))
if __name__ == "__main__":
HOST, PORT = ServerThreadHandler.nodesIpAddr[0], ServerThreadHandler.dataPort # HOST = "localhost"
server = SocketServer.TCPServer((HOST, PORT), ServerThreadHandler)
# Activate the server; this will keep running until you interrupt the program with Ctrl-C
server.serve_forever()
Research:
Getting a "TypeError: an integer is required" in my script
https://github.com/faucamp/python-gsmmodem/issues/39
https://docs.python.org/2/howto/sockets.html
Here is my complete error output:
Traceback (most recent call last):
File "/home/promitheas/Desktop/virus/socket1/socket1.py", line 20, in <module>
createSocket()
File "/home/promitheas/Desktop/virus/socket1/socket1.py", line 15, in createSocket
ServerSock.bind((socket.gethostname(), servPort))
File "/usr/lib/python2.7/socket.py", line 224, in meth
return getattr(self._sock,name)(*args)
TypeError: an integer is required
Code:
import socket
# Acquiring the local public IP address
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('8.8.8.8', 0))
# Defining some variables
servIpAddr = s.getsockname()[0]
servPort = ''
while ((len(servPort) < 4)): # and (len(servPort) > 65535)
servPort = raw_input("Enter server port. Must be at least 4 digits.\n> ")
# Creating a socket to wait for a connection
def createSocket():
ServerSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ServerSock.bind((socket.gethostname(), servPort)) # This is where the error occurs
ServerSock.listen(5)
(clientsocket, address) = ServerSock.accept()
if __name__ == "__main__":
createSocket()
I'm not sure if there are any other errors, but I'm really stumped on this one. Please ask if you need any other info, and thanks in advance!
It looks like the second element of the address tuple needs to be an integer. From the documentation:
A pair (host, port) is used for the AF_INET address family, where host is a string representing either a hostname in Internet domain notation like 'daring.cwi.nl' or an IPv4 address like '100.50.200.5', and port is an integer.
Try converting servPort to an integer before using it in bind.
servPort = ''
while ((len(servPort) < 4)): # and (len(servPort) > 65535)
servPort = raw_input("Enter server port. Must be at least 4 digits.\n> ")
servPort = int(servPort)
servPort must be an integer. You currently have it set to a string the user enters. Try casting the raw_input to an int using int(servPort).