IoT Bytes

Bits and Bytes of IoT

Python Script to Autodetect Modem COM Port on Raspberry Pi

Pradeep Singh | 1st Dec 2017

com_port

If you are writing an application that interacts with the analog modem connected to the USB port of the Raspberry Pi; you would realize that the first thing that you need in your application is the name of the COM Port. Unfortunately, it’s not very straightforward to locate the COM port associated with a Serial or USB device on Linux based operating systems.

Recently when I was writing an IVR Application using a USB analog modem connected to the Raspberry Pi, I came across the same requirement. To make it easy for the app user, I wrote a Python Script that will locate the COM port associated with the Modem connected with Raspberry Pi.

Theoretically, this script can be tweaked to detect other types of serial port (other than analog modems), but for now, here you have the code that will get you started.  If you face issues with the copy paste of the code, you can download it from my GitHub Repo Octocat

##--------------------
##--- Author: Pradeep Singh
##--- Blog: https://iotbytes.wordpress.com/
##--- Date: 1st Dec 2017
##--- Version: 1.0
##--- Python Ver: 2.7
##--- Description: This python code will find the COM port associated with an analog Modem connected with Raspberry Pi
##--------------------


import serial
from datetime import datetime
import subprocess


# Global Modem Object
analog_modem = serial.Serial()
#Time in Seconds (Default 120 Seconds)
MODEM_RESPONSE_READ_TIMEOUT = 10
# Modem Manufacturer, For Ex: 'U.S. Robotics' if the 'lsusb' cmd output is similar to "Bus 001 Device 004: ID 0baf:0303 U.S. Robotics"
MODEM_NAME = 'U.S. Robotics'    


#==========================
# Set COM Port settings
#==========================
def set_COM_port_settings(com_port):
	analog_modem.port = com_port
	analog_modem.baudrate = 9600
	analog_modem.bytesize = serial.EIGHTBITS 	#number of bits per bytes
	analog_modem.parity = serial.PARITY_NONE 	#set parity check: no parity
	analog_modem.stopbits = serial.STOPBITS_ONE #number of stop bits
	analog_modem.timeout = 3            		#non-block read
	analog_modem.xonxoff = False     			#disable software flow control
	analog_modem.rtscts = False     			#disable hardware (RTS/CTS) flow control
	analog_modem.dsrdtr = False      			#disable hardware (DSR/DTR) flow control
	analog_modem.writeTimeout = 3     			#timeout for write
#==========================


#==========================
# Detect Modem COM Port
#==========================
def detect_COM_port():

	# List all the Serial COM Ports on Raspberry Pi
	proc = subprocess.Popen(['ls /dev/tty[A-Za-z]*'], shell=True, stdout=subprocess.PIPE)
	com_ports = proc.communicate()[0]
	com_ports_list = com_ports.split('\n')

	# Find the right port associated with the Voice Modem
	for com_port in com_ports_list:
		if 'tty' in com_port:
			#Try to open the COM Port and execute AT Command
			try:
				# Set the COM Port Settings
				set_COM_port_settings(com_port)
				analog_modem.open()
			except:
				print "Unable to open COM Port: " + com_port
				pass
			else:
				#Try to put Modem in Voice Mode
				if not exec_AT_cmd("AT", "OK"):
					print "Error: Failed to put modem into voice mode."
					if analog_modem.isOpen():
						analog_modem.close()
				else:
					# Found the COM Port exit the loop
					print "Analog Modem COM Port is: " + com_port
					analog_modem.flushInput()
					analog_modem.flushOutput()
					analog_modem.close()
					break
#==========================

#==========================
# Execute AT Commands at the Modem
#==========================
def exec_AT_cmd(modem_AT_cmd, expected_response="OK"):
	try:
		# Send command to the Modem
		analog_modem.write((modem_AT_cmd + "\r").encode())
		# Read Modem response
		execution_status = read_AT_cmd_response(expected_response)
		disable_modem_event_listener = False
		# Return command execution status
		return execution_status

	except:
		print "Error: Failed to execute the command"
		return False		
#==========================

#==========================
# Read AT Command Response from the Modem
#==========================
def read_AT_cmd_response(expected_response="OK"):
	
	# Set the auto timeout interval
	start_time = datetime.now()

	try:
		while 1:
			# Read Modem Data on Serial Rx Pin
			modem_response = analog_modem.readline()
			print modem_response
			# Recieved expected Response
			if expected_response == modem_response.strip(' \t\n\r' + chr(16)):
				return True
			# Failed to execute the command successfully
			elif "ERROR" in modem_response.strip(' \t\n\r' + chr(16)):
				return False
			# Timeout
			elif (datetime.now()-start_time).seconds > MODEM_RESPONSE_READ_TIMEOUT:
				return False

	except:
		print "Error in read_modem_response function..."
		return False
#==========================


# Call the COM Port function
detect_COM_port()

Following is the screenshot of the Raspberry Pi shell, with the output of this script –

detect_com_port


 

Related Articles:

USB Analog Modem with Raspberry Pi

Record Audio from Phone Line with Raspberry Pi

Play Audio File on Phone Line with Raspberry Pi

Incoming Call Details Logger with Raspberry Pi

Python Script to Reset USB Modem COM Port on Raspberry Pi

References:

Wikipedia – Voice modem command set

USRobotics 56K USB Modem Voice Commands

USRobotics 56K USB Modem – Data and General Commands

Voice +V Commands – Developer’s Guide

Blog Home Page:

Let’s Decipher IoT…

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: