I'm working on a FTDI chip and want to connect this chip to the operating system Windows 10 via a serial port. I'm using this code below and the results show me the all visible ports what I don't want. what I need is to detect only the port which the chip is connected to and ignore the rest. for example Com 4, so I just want my program written in Python to detect Com4 ONLY.
I'm using Pyserial by the way.
I'm pretty thankful and grateful for your help in advance
def serial_ports():
if sys.platform.startswith('win'):
ports = ['COM%s' % (i + 1) for i in range(256)]
print ports
elif sys.platform.startswith('linux') or sys.platform.startswith('cygwin'):
# this excludes your current terminal "/dev/tty"
ports = glob.glob('/dev/tty[A-Za-z]*')
elif sys.platform.startswith('darwin'):
ports = glob.glob('/dev/tty.*')
else:
raise EnvironmentError('Unsupported platform')
result = []
print ports
for port in ports:
try:
s = serial.Serial(port)
s.close()
result.append(port)
except (OSError, serial.SerialException):
pass
return result
Read about
serial.tools.list_ports
This module can be executed to get a list of ports (python -m serial.tools.list_ports).
It also contains the following functions.
serial.tools.list_ports.comports()
Returns: an iterable that yields ListPortInfo objects.
The function returns an iterable that yields tuples of three strings:
port name as it can be passed to serial.Serial or serial.serial_for_url()
description in human readable form
sort of hardware ID. E.g. may contain VID:PID of USB-serial adapters.
Related
In windows 10 I am trying to read the output of an attached serial device.
Using hterm I am able to see the data on serial port COM5. So the serial port works fine.
Now using WSL2 (Ubuntu 20.04.3) I am running the following python script
import serial
ser = serial.Serial("COM5", baudrate=115200)
which fails with the error
Traceback (most recent call last):
File "test1.py", line 6, in <module>
ser = serial.Serial("COM5", baudrate=115200)
File "/usr/lib/python3/dist-packages/serial/serialutil.py", line 240, in __init__
self.open()
File "/usr/lib/python3/dist-packages/serial/serialposix.py", line 268, in open
raise SerialException(msg.errno, "could not open port {}: {}".format(self._port, msg))
serial.serialutil.SerialException: [Errno 2] could not open port COM5: [Errno 2] No such file or directory: 'COM5'
I also tried to use the suggestions posted in this article at attach the USB port on which the serial device is connected to, to WSL.
The command usbipd wsl list in a windows powershell shows then
8-3 0403:6001 USB Serial Converter Attached - Ubuntu-20.04
But when then running the same python code in WSL2 gives the same error.
So how to fix this problem so I am able to just read all data from the serial port with python?
You could try using the following script.
import serial
ser = serial.Serial("COM5", baudrate=115200, timeout=1)`
while True:
data = ser.readline()
print(data)
[EDIT] Code updated and tested as per locking remarks[/EDIT]
I generally use a solution where I just identify the port name from USB VID:PID data.
This allows me to not hard code any com port name.
You must begin searching for the port name corresponding to your USB device (see find_device() below).
You should also use locks on your serial port while reading so you don't get multiple concurrent accesses, which especially on Windows will create permission errors. See with LOCK context manager for locking the serial reads.
Code has been tested from Python 2.7 to 3.11 on both Windows and Linux.
Of course you can adapt the serial port settings and perhaps the size of read bytes and/or timeout.
import serial.tools.list_ports
import serial
from threading import Lock
# Your USB SERIAL DEVICE identification
USB_VID = "0x0403"
USB_PID = "0x6001"
SERIAL_SETTINGS = {
"baudrate": 115200,
"bytesize": 8,
"parity": "N",
"stopbits": 1,
}
LOCK = Lock()
def find_devices():
# type: () -> List[str]
"""
Find all COM ports corresponding to your USB device
"""
_device_ports = []
for port in serial.tools.list_ports.comports():
if port.vid == int(USB_VID, 16) and port.pid == int(USB_PID, 16):
_device_ports.append(port.device)
return _device_ports
def read_device(device) -> str:
# type: (str) -> str
try:
with LOCK:
with serial.Serial(device_port, timeout=1, **SERIAL_SETTINGS) as ser:
result = ser.read(size=64).decode('utf-8')
if len(result) == 0:
return None
else:
return result.strip("\r\n")
return result
except serial.SerialException as exc:
error_message = "Cannot read serial port {}: {}".format(device_port, exc)
print(error_message) # or log it
raise OSerror(error_message)
for port in find_devices():
data = read_device(port)
print(data)
Hope this helps.
More examples of serial reading can be found in a library I wrote for reading USB temperature sensors, see this
I personally would get this to work in Ubuntu 20.04.3 first.
Just download a Virtual Machine of Ubuntu, install it (in a VM environment (or real machine if you have one spare) ) and test.
WSLx is really good but it still has some teething problems.
If you know it passes in a real (or VM) Ubuntu install then you are most of the way there.
I always do this as WSLx can have some weird quirks I have found. It shouldn't for note but it does, especially when it comes down to external hardware.
Since you are using Ubuntu, you can't use the Port-Names used by Windows. In Ubuntu Port names usually are in the format of dev/ttyUSB followed by the number of the port (dev/ttyUSB0).
I am trying to build a python program that ties a GUI to a serial interface to talk to a nordic nrf52 DK. It I can open and close the port fine, but I when I send data the first byte that is received by the dev kit (which i have running in debug mode to monitor what data is rx'd) is always the last byte that was transmitted in the previous write cycle of the python script. This is true not only between opening and closing the COM port but even between different debug sessions and resets of the DK. The only time I am able to get the correct first byte to send is the first time I write data after having unplugged and re-plugged the peripheral back into my machine.
Has anyone seen this before? I have tried resetting the output buffer via the different methods afforded by the pyserial module but nothing has worked so far. I think this is some kind of windows issue, but in case its not, here is some relevant code:
COM port settings (port property is set dynamically according to the available devices and thus is not part of this block)
serial_client.baudrate = 38400
serial_client.bytesize = cli.EIGHTBITS
serial_client.stopbits = cli.STOPBITS_ONE
serial_client.parity = cli.PARITY_NONE
serial_client.xonxoff = False
serial_client.dsrdtr = False
serial_client.inter_byte_timeout = None
serial_client.exclusive = True
serial_client.rtscts = False
serial_client.timeout = 1
opening the serial port
serial_client.port = port_struct.device
try:
serial_client.open()
except cli.SerialException:
window[serial_conn_status_key].update(value="Serial Exception raised when opening port")
else:
window[serial_conn_status_key].update(value="{} Open".format(port_struct.device))
time.sleep(0.1)
closing the port
try:
serial_client.flushOutput()
except cli.SerialException:
window[output_buffer].print("**Exception when flushing output**")
try:
serial_client.close()
except cli.SerialException:
window[serial_conn_status_key].update(value="Serial Exception raised when closing port")
else:
window[serial_conn_status_key].update(value="COM unconnected")
function to write out data
def write_port(msg):
if serial_client.is_open:
serial_client.write(msg)
serial_client.reset_output_buffer()
else:
print("serial port not open")
Relevant Specs:
Machine OS: Windows 10
python version: 3.8.4
pyserial version: 3.4
Driver File: JINKCDC.sys
Driver Version: 1.34.0.44950
I'm running a port scanner on my home network. If I run it against devices on my home network, it only works on other Linux machines (physical machines not VMs). By "works" I mean it finds what few ports are actually open (ssh, mysql, sunrpc, and a couple others).
When scanning Windows and other miscellaneous iot devices it just hangs and never finishes. I can't seem to figure out where it gets stuck.
I think this might be the most relevant part of the code:
for port in range(begin, end):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
status = s.connect_ex((self.target_ip, port))
except Exception:
continue
finally:
s.close()
if status != 0:
continue
try:
service = socket.getservbyport(port)
except Exception:
service = "unknown"
print("SERVICE: %-15s\tPORT: %-8d" % (service, port))
I modified your code so that I could simulate a run on my machine and it seems like it hangs because that very last print statement is not reached. But this is because your continue line within the if status != 0 always comes back as "not 0", at least on my Windows 10 Pro machine.
for port in range(begin, end):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
status = s.connect_ex((self.target_ip, port))
print("DEBUG: ", status) # add this
except Exception as err:
print("Error: ", err) # add this
continue
finally:
s.close()
if status != 0:
print("DEBUG: status was not 0") # add this
# if this line is reached, we start at the top of the loop
# skipping the try except and print below entirely.
continue
try:
service = socket.getservbyport(port)
except Exception:
service = "unknown"
print("SERVICE: %-15s\tPORT: %-8d" % (service, port))
Could you give this a shot and see if will shine some light on what might be wrong or let us know what kind of output you get. I was not able to currently run this on any Linux machine or IoT devices. I assume you are able to read the console output on each of your devices to have determined that it seemed like it was "hanging".
Edit 1: More context for the hanging issue
Let me give you some examples of what happens with this script on my network.
CASE 1: '192.168.1.0'
This address exists, but generally isn't used or assigned to anything. Hangs for about 20 seconds per port for me.
CASE 2: '192.168.1.1'
This is usually the router on the network. Responds immediately. Hangs for about 1 second per port that is scanned.
CASE 3: '192.168.1.3'
This device is in the network range, but no device is actively using it. Hangs for about 20 seconds per port (just like case 1).
So the long "hang" isn't that it is not working. It can basically mean the IP is wrong or there is no device being reached so the timeout limit is being reached for that socket connection attempt instead of raising an exception it just moves on.
Edit 2
Before iterating over a huge range of IP addresses and a wide range of ports per each IP address being tested. Sometimes it can be helpful to test assumptions 1 at a time by defining more control over a few ports and a specific IP address.
This is what I converted your code into to do that. If the conn is not 0 I am just considering that port closed no matter which error code came back for this case. We only care about the ones that respond with 0 because that indicates the operation succeeded.
import socket
# Lets test just a few custom ports.
ports = [21, 22, 80, 8080]
# And test a specific IP address to test, 1 at a time.
ip = '192.168.1.1' # change this if needed
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
for port in ports:
# loop through our small custom port range.
try:
conn = sock.connect_ex((ip, port))
if conn == 0:
print("Port [{}] open.".format(port))
else:
print("Port [{}] closed.".format(port))
except Exception as err:
print(err)
continue
try:
service = socket.getservbyport(port)
except Exception:
service = "unknown"
print("SERVICE: %-15s\tPORT: %-8d" % (service, port))
sock.close()
So I have a network scanner, but its not working. It's showing that every ip on the network from 127.0.0.1 to 127.0.0.254 is down. I know for sure that's not the case. Does anyone know what the problem is?
import socket, ping
from struct import unpack, pack
my_ip = socket.gethostbyname(socket.gethostname())
print "My computer IP address:", my_ip
my_deets = socket.gethostbyname_ex(socket.gethostname())
print "My computer details:", my_deets
subnet_mask = "255.255.255.0"
def ip2long(ip):
"""7
Convert an IP string to long
"""
return unpack(">L", socket.inet_aton(ip))[0]
def long2ip(ip):
"""
Convert a long to IP string
"""
return socket.inet_ntoa(pack('!L', ip))
# Applying the subnet mask to IP
addr = ip2long(my_ip)
mask = ip2long("255.255.255.0")
prefix = addr & mask
print "Base address for network", long2ip(prefix)
# Get the number of possible computers on our network
all_computers = ip2long("255.255.255.255")
num_computers = all_computers ^ mask
# Go through each computer
for ip_suffix in range(num_computers):
# Try to ping a computer on the network
test_ip = long2ip(prefix + ip_suffix)
try:
print "[*] Checking to see if host is up..."
timeout = ping.do_one(test_ip, 1)
print timeout
if timeout != None:
print "[+] Host is there:", test_ip
print "-"*100
except socket.error, e:
print "[-] Host not there:", test_ip
Your script does work (and it's kind of fun, though I'll prefer nmap ;) ).
However
do_one takes a third argument, psize don't know how it works on your side.
You need to be root (e.g. administrator). And your script mixes up the "failure" and "host down" cases. When a host is down, the function will return None. When an error occurs, it means that the ping could not be sent. So the fact that "It's showing that every ip on the network from 127.0.0.1 to 127.0.0.254 is down", means actually that no packets could be sent.
127.0.0.1 is the loopback interface. There will be no other computer than yours on that network. The fact that socket.gethostbyname(socket.gethostname()) returns that address could mean that your network is improperly set. In some old days, the 127.0.0.1 address was hardlinked to the localhost hostname in the /etc/hosts file in order for some badly written programs (like Gnome apps at that time), who would wait for the IP associated with the hostname to respond or timeout before continuing with the start up, leading to extremely long delay to start the application each time the computer wasn't connected to any network. That workaround is no longer necessary IIRC.
I'm trying to use PySerial to accept inputs from an RFID Reader. As per the answers here: I've tried using WinObj and found something odd: there is no COM3 port in the GLOBAL??? folder pointing to something "more driver specific." However, when I run the command python -m serial.tools.list_ports, it does throw up COM3. When I try a simple program like:
import serial
ser = serial.Serial()
ser.port = 2
print(ser)
ser.open()
I get the following output:
Serial<id=0x45e8198, open=False>(port='COM3', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=False, rtscts=False, dsrdtr=False)
serial.serialutil.SerialException: could not open port 'COM3': FileNotFoundError(2, 'The system cannot find the file specified.', None, 2)
So, I know that PySerial is looking for my reader in the right place, and, according to two different sources (the device manager and the command line), the device is registering. And yet I'm still getting this error. What is going on? I'm using Python 3.3 on Windows 8.1.
EDIT: That error is actually what I get from python's command line. The one I get from making and running a program like the one above is:
AttributeError: 'function' object has no attribute 'Serial.'
I'd appreciate thoughts on that too.
First thing I would check is what you have for com ports attached and what's currently in use:
import serial.tools.list_ports
import sys
list = serial.tools.list_ports.comports()
connected = []
for element in list:
connected.append(element.device)
print("Connected COM ports: " + str(connected))
# compliments of https://stackoverflow.com/questions/12090503/listing-available-com-ports-with-python#14224477
""" Lists serial port names
:raises EnvironmentError:
On unsupported or unknown platforms
:returns:
A list of the serial ports available on the system
"""
if sys.platform.startswith('win'):
# !attention assumes pyserial 3.x
ports = ['COM%s' % (i + 1) for i in range(256)]
elif sys.platform.startswith('linux') or sys.platform.startswith('cygwin'):
# this excludes your current terminal "/dev/tty"
ports = glob.glob('/dev/tty[A-Za-z]*')
elif sys.platform.startswith('darwin'):
ports = glob.glob('/dev/tty.*')
else:
raise EnvironmentError('Unsupported platform')
result = []
for port in ports:
try:
s = serial.Serial(port)
s.close()
result.append(port)
except (OSError, serial.SerialException):
pass
print("Availible COM Ports: " + str(result))
Then, make sure you are calling the serial port constructor with the parameters you want:
ser = serial.Serial(
port="com2", # assumes pyserial 3.x, for 2.x use integer values
baudrate=19200,
bytesize=8,
parity="E", # options are: {N,E,O,S,M}
stopbits=1,
timeout=0.05)
When you call "serial.Serial()" without any parameters and then add the port ID, I'm not entirely sure what it's going to do, I've always explicitly referenced the port I want to use there.
Your issue lies in the fact that the serial object is looking for a string "COMXX" or else it won't work. I don't know if it need to be capitalized or not.
make sure you configure it like this.
serial.Serial(port = "COM2")