Recognition of a specific USB device in python - python

I am making app in python, that connects with Arduino. I want this app to work on different computers, when arduino is connected to any port. I was trying to do a function that checks to which port is arduino connected to:
def arduinoConnect():
t=0
temp = 0;
while 1:
i = str(t)
try:
temp = serial.Serial('com'+i, 9600)
if temp:
print("COM" + i + " Connected")
break
except:
print("COM" + i + " Empty")
t = t + 1
if t == 41:
break
return temp
But this code only sees if anything is connected, so when i am also using some bluetooth devices, or other microcontrolers, it takes the device that is connected to the com port with the lowest number.
Next idea was to take PID and VID number:
import serial
import serial.tools.list_ports
for port in serial.tools.list_ports.comports():
print(port.hwid)
But i have one more device connected to COM Port, that gives exactly the same numbers, only different location:
USB VID:PID=1A86:7523 SER= LOCATION=1-4
USB VID:PID=1A86:7523 SER= LOCATION=1-5
I also tried to get a specific id of a connected USB device:
import serial
def serial_ports():
ports = ['COM%s' % (i + 1) for i in range(256)]
result = []
for port in ports:
try:
s = serial.Serial(port)
s.close()
result.append(port)
print(s)
except (OSError, serial.SerialException):
pass
return result
if __name__ == '__main__':
print(serial_ports())
And it returns the ID of a device, which is unique to every device, but changes every time i disconnect and connect again the device.
My question is how to let my code recognize and connect one and only device I want? On any computer, connected to any port.

I understand your problem as such that you wish to have python code that can connect to an arduino device which is connected to any port, on any computer.
So the solution is to uniquely identify the arduino device even when other devices are plugged in.
It should work when you get the device serial number:
import serial
import serial.tools.list_ports
def get_arduino_serial_number():
for port in serial.tools.list_ports.comports():
if 'Arduino' in port.description:
return port.serial_number
return None
whether this works or not is dependent on port.description.
Change USB COM port description
Get ports by description
With the serial number of the Arduino device, you can then connect to it using:
ser = serial.Serial(port='COMx', baudrate=9600, timeout=1,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS)
Opening serial ports | pySerial

Related

Trying to connect Cobright DX4 laser to computer using Pyvisa

I am trying to connect a Cobright DX4 laser to my computer to control it from my computer. However I am unable to do so. I have tried using both rm.openresource() and through pyserial. However neither seem to work.
#import visa
import serial
import numpy as np
#rm = visa.ResourceManager() #checks devices that are
rm = visa.ResourceManager('#py') #to take the python backend
#rm = visa.ResourceManager('#sim')
print(rm.list_resources())
inst1 = rm.list_resources()
The output is ('ASRL5::INSTR')
However when I query the ID:
inst2 = rm.open_resource("ASRL5::INSTR",read_termination = '\n', write_termination="\r\n")
print(inst2.query("*IDN?"))
I get a timeout error
"VisaIOError: VI_ERROR_TMO (-1073807339): Timeout expired before operation completed."
I have also tried to connect using pyserial.
import pyvisa as visa # note the recommended way to import pyvisa changed as there is an unrelated visa module
#import visa
import serial
import numpy as np
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))
Connected COM ports: ['COM5']
Availible COM Ports: ['COM5']
ser = serial.Serial(
port="COM5", # assumes pyserial 3.x, for 2.x use integer values
baudrate=9600,
bytesize=8,
parity="E", # options are: {N,E,O,S,M}
stopbits=1,
timeout=1)
print(ser)
Serial<id=0x243e051beb0, open=True>(port='COM5', baudrate=9600, bytesize=8, parity='E', stopbits=1, timeout=1, xonxoff=False, rtscts=False, dsrdtr=False)
ser.isOpen()
True
Now when I try to send a command eg
ser.write(str.encode('*IDN?'))
5
is the output. I am unsure as to what the issue. I cannot decode having encoded.
Any help appreciated, and sorry for the long post! I have also connected a power meter which worked fine.

Setting a default "SERIAL PORT" for a serial port device in "LINUX"

I am Using a Python to access a serial port from ubuntu 20.4. I send and read data from the Connected serial port.
The code looks like :
import time
import serial
ser=serial.Serial("/dev/ttyACM0",115200)
ser.write(b'\xFA\x0B\x1B\x00\x00\x00\x00\x00\x00\xFB')
while True:
try:
#ser.write(command)
s2=ser.read(10).hex()
print(s2)
except KeyboardInterrupt:
ser.flushInput()
ser.flushOutput()
ser.close()
break
The issue is, whenever I try resetting the hardware device the "COM Port" Jumps to a new "port". So I need to manually change the port in the code frequently.
Is there a way to set a default "COM PORT" in Ubuntu for a serial port device (or) is there a way to automatically detect the "COM PORT" by my program!?
The thing I tried is:
import serial.tools.list_ports
import serial
print('Searching for ports...')
ports=serial.tools.list_ports.comports(include_links=False)
for port in ports:
if port.device=="/dev/ttyACM0" or port.device=="/dev/ttyACM1" or port.device=="/dev/ttyACM2":
ser=serial.Serial(port.device)
break
if ser.isOpen():
ser.close()
ser=serial.Serial(port.device,115200)
ser.flushInput()
ser.flushOutput()
print('Connected to :'+ser.name)
But this code doesn't provide the required output. The code sometimes doesn't select the correct "COM PORT".

How to setup a raspberry pi as server and client at the same time?

I am using my Raspberry as a server and client at the same time.
However, my RPI don't enable the connection as server after it connecting to another device as a client. The requirement is, the RPI has to connect to several devices at once.
The minimal example with ethernet cable would be:
Device A <-----ETH-----> RPI <-----ETH-----> Device B
So in the above configuration, first connecting it to Device B as a client, Device A can not be connected to the RPI. If I use it as a standalone server/client it works perfectly but as parallel functionality it doesnt work. There is no error message, Device A just doesnt connect to the Raspberry.
Note that, I am connecting device A via Ethernet-to-USB adapter and it works perfectly as standalone server. I am using multiprocessing for each device on the raspberry.
Any help is appreciated.
I note that in that configuration the raspberry acts as access point (?).
The functionality of the raspberry is, that it has to forward the incoming messages to another device, so that each device doesn't know the port or IP address of each other, only the PI does.
So my simplified code for the raspberry is:
walkie_talkie.py
import socket
# socket.socket(socket.AF_INET, socket.SOCK_STREAM)
class walkie_talkie(socket.socket):
'''Inherits all functionalities of sockets.sockets
Use this class for connection using TCP/IP e.g. internet/ethernet
Example usage:
>>> from walkie_talkie import walkie_talkie
>>> wt = walkie_talkie()
>>> wt.BUFFERSIZE = 8
...
'''
def __init__(self):
self.BUFFERSIZE = 8192
self.STATE = None
self.IP = None # Server IP
self.PORT = 5000
self.NUMBER_OF_UNACCEPTED_CONNECTIONS = 1
self.bytestream = None
self.PROTOCOL = socket.SOCK_STREAM # Using UDP: socket.SOCK_DGRAM
super().__init__(socket.AF_INET, self.PROTOCOL)
def setup_server(self):
print('****** SERVER SETUP ******\n'
'TCP/IP: {}\n'
'PORT: {}\n'
'BUFFERSIZE: {}\n'
'Acc. conn.: {}\n'
'****** SERVER SETUP ******\n'.format(self.IP,
self.PORT,
self.BUFFERSIZE,
self.NUMBER_OF_UNACCEPTED_CONNECTIONS))
self.STATE = 'SERVER'
self.bind((self.IP, self.PORT))
self.listen(self.NUMBER_OF_UNACCEPTED_CONNECTIONS)
self.CONN, self.ADDRESS = self.accept()
def setup_client(self):
print('****** CLIENT SETUP ******\n'
'TCP/IP: {}\n'
'PORT: {}\n'
'BUFFERSIZE: {}\n'
'Acc. conn.: {}\n'
'****** CLIENT SETUP ******\n'.format(self.IP,
self.PORT,
self.BUFFERSIZE,
self.NUMBER_OF_UNACCEPTED_CONNECTIONS))
self.STATE = 'CLIENT'
#self.settimeout(10.0)
self.connect((self.IP, self.PORT))
#self.settimeout(None)
print('Connected.')
Since I also have to stream the data through multiple ports of the same devices, I am using multiprocessing for each communication tunnel.
multiprocessing_rpi.py
import socket
from walkie_talkie import walkie_talkie
import multiprocessing
import time
def setup_alpha_watchdog(IP, PORT):
''' Creates an alpha watchdog
:param str IP: Server IP on Raspberry to listen to
:param int PORT: Server Port to open for Device A
'''
global BUFFERSIZE
print('alpha Watchdog >> {} # {}'.format(IP, PORT))
alpha_watchdog = walkie_talkie()
alpha_watchdog.IP = IP
alpha_watchdog.PORT = PORT
alpha_watchdog.BUFFERSIZE = BUFFERSIZE
try:
# Setup alpha watchdog and omega watchdog right afterwards
alpha_watchdog.setup_server()
omega_watchdog = setup_omega_watchdog(DEVICE_B_IP, PORT) # returns a walkie_talkie object as client
superstream(alpha=alpha_watchdog,
omega=omega_watchdog)
except Exception as watchdog_error:
print('Error: ' + str(watchdog_error))
exit()
pass
def setup_omega_watchdog(IP, PORT):
''' Creates an omega watchdog
Description:
omega watchdog takes data from alpha watchdog and pass them to the specified device
If the connection is denied, abort both watchdogs.
:param str IP: Server IP of Device B to connect to
:param int PORT: Server Port on Device B to send data to
'''
global BUFFERSIZE
print('omega Watchdog >> {} # {}'.format(IP, PORT))
watchdog = walkie_talkie()
watchdog.IP = IP
watchdog.PORT = PORT
watchdog.BUFFERSIZE = BUFFERSIZE
try:
watchdog.setup_client()
except Exception as watchdog_error:
print('Error: ' + str(watchdog_error))
exit()
return watchdog
def superstream(alpha, omega):
'''Streams data between the watchdogs on Request-Response scheme
Description:
After setting alpha & omega watchdogs, the communication takes place after incoming signal from alpha passed to omega.
For example, the byte b'\x02\x00\x00\x00\xff\x00' coming from Device A will be passed to alpha watchdog
and the raspberry will then pass this byte to the omega watchdog and finally to the Device B.
:param object alpha: An alpha watchdog
:param object omega: An omega watchdog
'''
while 1:
try:
# Get data coming from Device A and send it directly to Device B
data_from_Device_A = alpha.CONN.recv(alpha.BUFFERSIZE)
omega.send(data_from_Device_A )
# Get response from Device B and send back to Device A
RESPONSE= omega.recv(omega.BUFFERSIZE)
alpha.CONN.send(RESPONSE)
except Exception as e1:
print('Error: ' + str(e1))
break
alpha.shutdown(2)
alpha.close()
omega.shutdown(2)
omega.close()
if __name__ == '__main__':
THIS_RPI_IP= '169.254.244.192' # IP of raspberry, so Device A can connect to it
DEVICE_B_IP = '192.xxx.....' # Device B IP
# Reserve ports correlating number of devices
SERVER_PORTS = [5000,
# 5001,
# 5002,
# 5003,
# 5004,
5005]
SERVER_IP = THIS_RPI_IP
BUFFERSIZE = 8192
PROCESS_LIST = []
#For each port, setup a socket for clients
for PORT in SERVER_PORTS:
p = multiprocessing.Process(target=setup_alpha_watchdog, args=(THIS_RPI_IP, PORT,))
PROCESS_LIST.append(p)
p.start()
for _ in PROCESS_LIST:
_.join()
In setup_alpha_watchdog I can swap the line, where I first connect as client to device B (Successfully!) and then listen to device A, however I am not able to establish a connection as server to device A.

Error in Python code in controlling servo motor using Raspberry Pi 3 B+

I am currently building an automated trash bin using Raspberry Pi 3 B+ with Android application support where I would use a servo motor as an actuator for the lid and the Android application as a form of wireless remote control. Everything went on smoothly until I've encountered a problem that whenever I attempt to press a button on my Android application, the Python shell program has errors during testing. I've used a reference video (https://www.youtube.com/watch?v=t8THp3mhbdA&t=1s) and followed everything thoroughly until I've hit this roadblock.
The results to me that keeps appearing are:
Waiting for connection
...connected from :
Where the supposed result, according to the reference video, is:
Waiting for connection
...connected from : ('192.168.1.70', 11937)
Increase: 2.5
As you can see, the IP address, the port, and 'Increase' text doesn't appear, meaning there is something wrong with the code.
According to some comments that was made by the people who watched the video, this code is outdated, using Python 2, and the latest version we have now is Python 3, and that we need to use a ".encode()" line in a condition. However, as someone who is still new to Python, I'm afraid that I still don't have the knowledge to apply this on the code.
Here is the code that was used in the video:
import Servomotor
from socket import *
from time import ctime
import RPi.GPIO as GPIO
Servomotor.setup()
ctrCmd = ['Up','Down']
HOST = ''
PORT = 21567
BUFSIZE = 1024
ADDR = (HOST,PORT)
tcpSerSock = socket(AF_INET, SOCK_STREAM)
tcpSerSock.bind(ADDR)
tcpSerSock.listen(5)
while True:
print 'Waiting for connection'
tcpCliSock,addr = tcpSerSock.accept()
print '...connected from :', addr
try:
while True:
data = ''
data = tcpCliSock.recv(BUFSIZE)
if not data:
break
if data == ctrCmd[0]:
Servomotor.ServoUp()
print 'Increase: ',Servomotor.cur_X
if data == ctrCmd[1]:
Servomotor.ServoDown()
print 'Decrease: ',Servomotor.cur_X
except KeyboardInterrupt:
Servomotor.close()
GPIO.cleanup()
tcpSerSock.close();
I have already changed the text strings that used the ' ' format into the (" ") format since it also produced some errors in the code which I corrected immediately.
Any help will be greatly appreciated and thank you in advance!
Here's a Python3 version, edited a tiny bit for better clarity and good practice:
import Servomotor
import RPi.GPIO as GPIO
import socket
# Setup the motor
Servomotor.setup()
# Declare the host address constant - this will be used to connect to Raspberry Pi
# First values is IP - here localhost, second value is the port
HOST_ADDRESS = ('0.0.0.0', 21567)
# Declare the buffer constant to control receiving the data
BUFFER_SIZE = 4096
# Declare possible commands
commands = 'Up', 'Down'
# Create a socket (pair of IP and port) object and bind it to the Raspberry Pi address
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(HOST_ADDRESS)
# Set the socket to listen to an incoming connection (1 at a time)
server_socket.listen(1)
# Never stop the server once it's running
while True:
# Inform that the server is waiting for a connection
print("Waiting for connection to the following address: {}...".format(HOST_ADDRESS))
# Perform a blocking accept operation to wait for a client connection
client_socket, client_address = server_socket.accept()
# Inform that the client is connected
print("Client with an address {} connected".format(client_address))
# Keep exchanging data
while True:
try:
# Receive the data (blocking receive)
data = client_socket.recv(BUFFER_SIZE)
# If 0-byte was received, close the connection
if not data:
break
# Attempt to decode the data received (decode bytes into utf-8 formatted string)
try:
data = data.decode("utf-8").strip()
except UnicodeDecodeError:
# Ignore data that is not unicode-encoded
data = None
# At this stage data is correctly received and formatted, so check if a command was received
if data == commands[0]:
Servomotor.ServoUp()
print("Increase: {}".format(Servomotor.cur_X))
elif data == commands[1]:
Servomotor.ServoDown()
print("Decrease: {}".format(Servomotor.cur_X))
elif data:
print("Received invalid data: {}".format(data))
# Handle possible errors
except ConnectionResetError:
break
except ConnectionAbortedError:
break
except KeyboardInterrupt:
break
# Cleanup
Servomotor.close()
GPIO.cleanup()
client_socket.close()
# Inform that the connection is closed
print("Client with an address {} disconnected.".format(client_address))
To show you the code in action, I have hosted a local server on my machine and connected to it using Putty. Here are the commands I have entered:
Here is the output of the server (I have swapped the Servo-related functions to print statements):
Waiting for connection to the following address: ('0.0.0.0', 21567)...
Client with an address ('127.0.0.1', 61563) connected.
Received invalid data: Hello
Received invalid data: Let's try a command next
Running ServoUp
Increase: 2.5
Running ServoDown
Decrease: 2.5
Received invalid data: Nice!
Client with an address ('127.0.0.1', 61563) disconnected.
Waiting for connection to the following address: ('0.0.0.0', 21567)...

Python: Binding a socket to /dev/rfcommX

I have a script that loads a Firmware on an embedded device over a serial port. The script takes the /dev/xxx adress of the serial port as an argument.
I have a special setup, where I do this over Bluetooth.
I managed to connect via bluetooth to the module in python. However I just can't find any example/information on how to register the local socket in a serial device like /dev/rfcomm0.
####### ORCA Bluetooth uploader Script #######
#As an input argument the script needs the BT Adress of the racer.
#if none is given, the script looks for nearby devices.
import bluetooth
import subprocess
import sys
import os
#Check if we received a BT ADDR
if sys.argv[-1] != 'bt_comm.py':
#Define the Pin for binding and the connection Port
#Our Pin is 0000
pin = "0000"
#The Bootoader is listening on Port 1 for a connection
port = 1
rfcomm_port = 0
#The BT Addr we get from the command line input
#TAG:TODO:Check the input for sanity
addr = sys.argv[-1]
#Build the Firmware image
subprocess.call("python ./px_mkfw.py --image ../../Firmware_orca/Images/px4fmu.bin > orca_fw",shell=True)
#Create an RFCOMM Socket
server_sock=bluetooth.BluetoothSocket( bluetooth.RFCOMM )
#Connect to the device
server_sock.connect((addr, port))
print "Connected to ",addr
Here I need some way to register server_sock at /dev/rfcomm0
#Call the px_uploader script
subprocess.call("python ./px_uploader.py --port /dev/rfcomm%d orca_fw" % rfcomm_port,shell=True)
#Close the connection
server_sock.close()
else:
#Look for BT Devices and print them
discovered_devices = bluetooth.discover_devices(lookup_names = True, flush_cache = True, duration = 20)
if discovered_devices is not None:
for addr in discovered_devices:
print "Found bluetooth device: ", addr
else:
print "Could not find any bluetooth device nearby"

Categories

Resources