Automatic VitalCheck


What’s VitalCheck?

VitalCheck is a theoretically lovely and practically useless system designed to prevent COVID transmissions within a community by having individuals confirm each day whether they are experiencing any symptoms of COVID or are at any risk of having been exposed. Fordham requires that students complete the daily survey before being allowed on campus or into any university buildings.

I appreciate them being proactive about reducing the spread of COVID, but frankly the existence of asymptomatic carriers and many people’s lack of honesty about their individual COVID risk make the system pretty much entirely useless. So I decided: why bother taking the 15 seconds each morning to say I’m feeling well when I can have a computer do it for me? Worst comes to worst I’ll self-report should I end up actually feeling unwell or being exposed to someone with COVID.

Automating it

The actual process of completing the daily survey is really quick and easy, and the program to automate it is similarly simple.

The daily VitalCheck screening. Push "No to all above" and you're allowed on campus!

Each day, I receive an email at 7 in the morning asking me to click a link and complete the pictured survey. The link changes each day (though I think previous links actually work, so perhaps I vastly over-complicated this in hindsight…), so I have to navigate to the email, click on the link, click on the big green button, and I’m clear to go about my on-campus activities.

The program functions very similarly. It waits until the configured time, checks the most recent emails and looks for the VitalCheck email, navigates to the page at the link, and presses the button. And it does it much faster than I ever could, without any effort on my part!

Checking the email

I use the imaplib and email libraries to facilitate checking and reading the emails. Logging into the email and retrieving the messages is as simple as:

imap = imaplib.IMAP4_SSL("imap.gmail.com")
imap.login(email_address, password)
_, messages = imap.select("INBOX")
imap.close()
imap.logout()

Actually, I will say it isn’t totally quite that simple, as Google (for whatever reason) cares about their email security and doesn’t allow you to login from some random, unverified Python script. Instead of having the program log into the email I usually receive the VitalCheck surveys at, I forward all of the emails to a different account (for which I’ve disabled basically every security feature except 2FA), and check that email instead.

To read through the emails, imap has a series of pretty icky-looking functions for fetching end decoding information from the email. I copied a lot of it from somewhere on the internet, but it’s all mostly self-explanatory. Have a look at CheckEmails() in check_email.py for a closer look at how it works.

I decided to use Selenium for interacting with the page, and I’m a big fan of the library. All I had to do was open the page with get(link) and find the element on the page to click on. I browsed through the HTML in the survey page and found the unique class for the “No to all above button”. I selected the button like this:

driver.find_element_by_xpath("//button[@class='btn btn-lg btn-succcess btn-block language ENGLISH']")

Perhaps there would have been a better and nicer to look at method to use than this, but this is what ended up working so I left it like this.

I ended up running into an interesting problem when (I think) they updated the VitalCheck page to have a help box at the bottom. I’m not sure why, but Selenium gave an error saying that something was obscuring the button it was trying to click. After doing some internet sleuthing I came acrosss the solution of retrieving the obscuring element (fortunately the error message said what it was), setting the element’s visibility to hidden, and continuing with the rest of the program.

# If Selenium couldn't find an element with this class this would break, so
# creating a list of elements with the class stops that from happening
obscuringHelpMeBox = driver.find_elements_by_xpath(
    "//div[@class='pull-right help-me-box col-md-4 col-sm-8 col-xs-12']"
)

if len(obscuringHelpMeBox != 0):
    # Hide the element
    driver.execute_script("arguments[0].style.visibily='hidden'", obscuringHelpMeBox[0])

After that I run a very nice, clean button.click() and my VitalCheck is officially completed.

Running it continuously

I knew from the beginning that I would have to keep this running perpetually in order for it to actually make the check at 7 AM, but I knew it would be utterly impractical to keep the script running on my PC 24/7. So I looked into hosting and running it on a virtual machine somewhere, and boy what a can of worms to open.

It seemed the easiest way to go about it was to start a virtual machine through Google Cloud Platform, SFTP the files to the machine, and run it there forever. A few problems arose:

  1. The Chrome webdriver did not play as nicely on Linux as it did on Windows
  2. I had to find a way to keep the script running even after exiting the terminal

Fixing the Chrome webdriver ended up being an hour or so of just trying different installations of Chromium and the webdriver. I honestly don’t even remember how I got it working at the end, but there was a lot of removing files and apt-get updates.

As for keeping the script running all the time, I decided to use GNU Screen, which allows you to keep multiple terminal windows open, and conveniently allows you to keep scripts running in the background even when the terminal isn’t logged into. I tried sending the process to the bg a few times, but it seemed to close it out after a little while, which basically ruled that option out.

With GNU Screen it’s super easy. Type screen to make a new screen, run the program there, and press Ctrl+Shift+a and then d to ‘detach’ from the screen. Voilà, the script will run forever (or at least until my free Google Cloud Platform access expires) and my VitalCheck is completed each morning!

So…

Yeah so that took longer than I thought it would, and saves me much less time than I thought it would too. But, it was a fun exercise, it provides me with the most minor of conveniences, and it was the perfectly sutble jab at Fordham that I needed in my life.

Also I wanted to figure out a way to make it work for multiple people so I could automate VitalCheck en masse, but I didn’t end up doing it and I think it will be a thing of the past as of next semester. In hindsight I suppose I would have had people simply forward their VitalCheck emails to my dedicated receiver email address, and implemented checking for multiple emails and then archiving them. Alas.

⇠ 2D Orbital Simulator