Establish a Console Connection within a Python script with pySerial

I have been using the python library called pySerial and wanted to share how I made it work on my end.

I have used it to establish a console connection to a Cisco AP in order to perform send the initial set of configurations within a python script and automate the process. I will only talk about using it on macOS as this is what I use. See: Configure a Cisco IOS-XE AP for an APoS Site Survey using Python.

Console Connection

In order for pySerial to work properly, you need to first establish your console connection with the network equipment you are configuring. In my case, I connected it to a Cisco AP.

Use a console cable to connect your computer to the console port of the equipment. In my case, I am using an AirConsole

On macOS, that means retrieving the tty corresponding to your serial connection. In order to see all of the tty available once you have connected your console cable, you can use the following command:

In my case, you can see that the tty I will need is called: /dev/tty.AirConsole-68-raw-serial 

pySerial Installation

All you have to do to install pySerial is to run this command: python -m pip install pyserial

Note: the serial python library also exists. Make sure that you install the pyserial library and not the serial one!

Time to Code!

You can now create a python script. To use the library, you need to import it using the following line:

import serial

Then, you will need to create a serial.Serial object that will open the serial connection to your equipment (my AP here). You can do it within a with statement so it can open and close it nicely for you:

with serial.Serial("/dev/tty.AirConsole-68-raw-serial ", timeout=1) as ser:
    print(f"Connecting to {ser.name}...")

You can notice that I need the TTY in order to create that Serial object.
You can also set a timeout of the connection. This is optional and I have set mine to 1sec.
You also notice that I am printing the name of the Serial connection by using the ser.name variable.

In order to send a command, you will have to use this code (in this case we are just sending a return character):

# Building the command to send
    command = "\r"
    
    # Sending the command out through the serial connection
    ser.write(command.encode("utf-8"))
    
    # Waiting for the command to be executed on the AP
    sleep(0.5)
    
    # Retreiving the amount of available data to read (output)
    nb_bytes_to_read = ser.inWaiting()
    
    # Reading and printing out the output of the command
    print(ser.read(output).decode("utf-8"), end="")

Here are a few things to note:

  • The text to be sent needs to be encoded using utf-8
  • The ‘\r’ character has to be added to the command in order to simulate the user pressing on Enter (Note: ‘\n’ didn’t work for me when interacting with the Cisco AP)
  • You will have to use the sleep function to wait for the command to be executed and send you the output back
  • The text received will have to be decoded using utf-8

This set of code will have to be executed for every command that you want to send out. So I would recommend creating a function that will do all of this for you. Here is an example:

def send_to_console(ser: serial.Serial, command: str, wait_time: float = 0.5):
    command_to_send = command + "\r"
    ser.write(command_to_send.encode('utf-8'))
    sleep(wait_time)
    print(ser.read(ser.inWaiting()).decode('utf-8'), end="")

You can use the wait_time to see how long you need to wait in order to receive all the output from the AP. For instance, you will need to wait longer if you are sending a “show run” vs. sending “conf t”.

Example – Show AP Summary

Here is an example of a script that will connect to an AP (running EWC) and send out the “show ap summary” to discover which APs are joined:

import serial
from time import sleep


def send_to_console(ser: serial.Serial, command: str, wait_time: float = 0.5):
    command_to_send = command + "\r"
    ser.write(command_to_send.encode('utf-8'))
    sleep(wait_time)
    print(ser.read(ser.inWaiting()).decode('utf-8'), end="")

with serial.Serial("/dev/tty.AirConsole-68-raw-serial", timeout=1) as ser:
    print(f"Connecting to {ser.name}...")
    send_to_console(ser, "")
    send_to_console(ser, "enable")
    send_to_console(ser, "show ap summary", wait_time=2)
    print(f"Connection to {ser.name} closed.")

And here is the output when you run the script:

Source code can be found here: ​github.com/francoisverges/semfio-cisco/blob/master/pyserial-example/show-ap-summary.py

Resources

Leave a Reply

Your email address will not be published. Required fields are marked *