Home » Python projects » Desktop app in Python for checking covid19 vaccine availability

Desktop app in Python for checking covid19 vaccine availability

desktop app- vaccine availability tracker

Learn to create a Desktop app in Python to check any available slot in your location (based on the pincode) on a given date. A step-by-step method to build the app and learn a lot of things on the way. If you are familiar with Tkinter then Great, it will be very easy for you BUT incase, you don’t know… NO problem at all… you will learn Tkinter along the way as it is pretty easy!! Trust me. Following are the prerequisites for building this project.

Estimated Time: Depends on your dedication

Prerequisites:


Table of Contents


Overview

First, we will learn to design the Desktop application, which is also known as the Front end and then will focus on creating a back-end connection (coding). The GUI has been designed using the Tkinter library in Python and backend code depends on the two external (third-party library) which are mentioned in the prerequisites section.

GUI components that are present in this application are Label, Entry box, Button, Textbox, Radio button, Checkbox and Frame.

Let’s look at the code below and learn to create them. I would recommend you to start coding on your system along the way.

Other Python-projects

news scraping with python
Covid vaccination slot india cowin portal
python api - weather data

CODING Front-End

Step 1: Importing all necessary libraries and declare some constants

# Import modules
from tkinter import *
from tkinter import messagebox
from datetime import datetime
import pytz
import requests

software_version = 'v1.1'
IST = pytz.timezone('Asia/Kolkata')

# Color value reference
top_left_frame_bg  = "#5c4ce1"
top_right_frame_bg = '#867ae9'

Video Playlist – Creating Desktop App step by step

Step2: Create GUI window having a size, title, Icon, and background

app = Tk()

# App Geometry and components
app.geometry("700x480+400+200")
app.title(f"Vaccine Availability Checker  {software_version}")
app.iconbitmap("Images_Icons\covid-vaccine.ico")
app.resizable(True, True)
app.config(background = '#293241')

Step3: Create all the Frames, Labels and Entrybox

# Frame details
frame1 = Frame(app, height = 120, width=180, bg= top_left_frame_bg, bd=1, relief = FLAT)
frame1.place(x=0,y=0)
frame2 = Frame(app, height = 120, width=520, bg= top_right_frame_bg, bd=1, relief = FLAT)
frame2.place(x=180,y=0)
frame3 = Frame(app, height = 30, width=700, bg= 'black', bd=1, relief = RAISED)
frame3.place(x=0,y=120)

# Labels
label_date_now = Label(text="Current Date", bg = top_left_frame_bg, font = 'Verdana 12 bold')
label_date_now.place(x=20, y=40)
label_time_now = Label(text="Current Time", bg = top_left_frame_bg, font = 'Verdana 12')
label_time_now.place(x=20, y=60)
label_pincode = Label(text="Pincode", bg = top_right_frame_bg, font = 'Verdana 11')
label_pincode.place(x=220, y=15)
label_date = Label(text="Date", bg = top_right_frame_bg, font = 'Verdana 11')
label_date.place(x=380, y=15)
label_dateformat = Label(text="[dd-mm-yyyy]", bg = top_right_frame_bg, font = 'Verdana 7')
label_dateformat.place(x=420, y=18)
label_search_vacc = Label(text="Search \nAvailable Vaccine", bg = top_right_frame_bg, font = 'Verdana 8')
label_search_vacc.place(x=570, y=70)
label_head_result = Label(text=" Status       \tCentre-Name\t              Age-Group    Vaccine       Dose_1     Dose_2     Total", bg = 'black', fg='white', font = 'Verdana 8 bold')
label_head_result.place(x=10, y=125)

# Entry boxes
pincode_text_var = StringVar()
pincode_textbox = Entry(app,width = 11, bg = '#eaf2ae', fg= 'black', textvariable = pincode_text_var, font='verdana 11')
pincode_textbox['textvariable'] = pincode_text_var
pincode_textbox.place(x= 220, y=40)

date_text_var = StringVar()
date_textbox = Entry(app,width = 12, bg = '#eaf2ae', fg= 'black', textvariable = date_text_var, font='verdana 10')
date_textbox['textvariable'] = date_text_var
date_textbox.place(x= 380, y=40)

Step4: Create Text box for displaying the result

## TEXT BOX
result_box_avl = Text(app, height = 20, width = 8, bg='#293241',fg='#ecfcff', relief=FLAT, font='verdana 10')
result_box_avl.place(x= 3 , y= 152)
result_box_cent = Text(app, height = 20, width = 30, bg='#293241',fg='#ecfcff', relief=FLAT, font='verdana 10')
result_box_cent.place(x= 75 , y= 152)
result_box_age = Text(app, height = 20, width = 8, bg='#293241',fg='#ecfcff', relief=FLAT, font='verdana 10')
result_box_age.place(x= 330 , y= 152)
result_box_vacc = Text(app, height = 20, width = 10, bg='#293241',fg='#ecfcff', relief=FLAT, font='verdana 10')
result_box_vacc.place(x= 400 , y= 152)
result_box_D1 = Text(app, height = 20, width = 7, bg='#293241',fg='#ecfcff', relief=FLAT, font='verdana 10')
result_box_D1.place(x= 490 , y= 152)
result_box_D2 = Text(app, height = 20, width = 7, bg='#293241',fg='#ecfcff', relief=FLAT, font='verdana 10')
result_box_D2.place(x= 555 , y= 152)
result_box_D1_D2 = Text(app, height = 20, width = 7, bg='#293241',fg='#ecfcff', relief=FLAT, font='verdana 10')
result_box_D1_D2.place(x= 630 , y= 152)

Step5: Create Buttons, RadioButtons and Checkboxes

# Buttons
search_vaccine_image = PhotoImage(file= "Images_Icons\search-icon.png")
search_vaccine_btn = Button(app, image=search_vaccine_image, bg= top_right_frame_bg, command = search_vaccine_avl, relief= RAISED)
search_vaccine_btn.place(x = 600,y = 25)

# Radio Buttons
curr_loc_var = StringVar()
radio_location = Radiobutton(app, text="Current location", bg= top_right_frame_bg, variable= curr_loc_var, value = curr_loc_var, command = fill_pincode_with_radio) #state=DISABLED
radio_location.place(x=215, y=65)

# Check Box 
chkbox_today_var = IntVar()
today_date_chkbox = Checkbutton(app, text='Today', bg= top_right_frame_bg, variable=chkbox_today_var, onvalue= 1, offvalue=0, command = insert_today_date)
today_date_chkbox.place(x= 375, y= 65)

chkbox_tomorrow_var = IntVar()
tomorrow_date_chkbox = Checkbutton(app, text='Tomorrow', bg= top_right_frame_bg, variable=chkbox_tomorrow_var, onvalue= 1, offvalue=0, state = DISABLED)
tomorrow_date_chkbox.place(x= 435, y= 65)

CODING Back-End

Step1: To detect automatic Pincode based on ISP location service

# Detect Automatic Pincode
def fill_pincode_with_radio():
    curr_pincode = get_pincode_ip_service(url)
    pincode_text_var.set(curr_pincode)

url = 'https://ipinfo.io/postal'
def get_pincode_ip_service(url):
    response_pincode = requests.get(url).text
    return response_pincode

Step2:  Code to update the clock (Date and Time) regularly

def update_clock():
    raw_TS = datetime.now(IST)
    date_now = raw_TS.strftime("%d %b %Y")
    time_now = raw_TS.strftime("%H:%M:%S %p")
    formatted_now = raw_TS.strftime("%d-%m-%Y")
    label_date_now.config(text = date_now)
    # label_date_now.after(500, update_clock)
    label_time_now.config(text = time_now)
    label_time_now.after(1000, update_clock)
    return formatted_now

Step3: Using the checkbox to insert today date

def insert_today_date():
    formatted_now = update_clock()
    date_text_var.set(formatted_now)
    tomorrow_date_chkbox['state'] = DISABLED

Step4: Refresh API call and clear the search result area

def refresh_api_call(PINCODE, DATE):
    header = {'User-Agent': 'Chrome/84.0.4147.105 Safari/537.36'}
    request_link = f"https://cdn-api.co-vin.in/api/v2/appointment/sessions/public/findByPin?pincode={PINCODE}&date={DATE}"
    response = requests.get(request_link, headers = header)
    resp_JSON = response.json()
    return resp_JSON

def clear_result_box():
    result_box_avl.delete('1.0', END)
    result_box_cent.delete('1.0', END)
    result_box_age.delete('1.0', END)
    result_box_vacc.delete('1.0', END)
    result_box_D1.delete('1.0', END)
    result_box_D2.delete('1.0', END)
    result_box_D1_D2.delete('1.0', END)

Step5:  Code when search button is pressed

def search_vaccine_avl():
    clear_result_box()
    PINCODE = pincode_text_var.get()
    DATE = date_text_var.get()
    resp_JSON = refresh_api_call(PINCODE, DATE)

    try:
        if len(resp_JSON['sessions']) == 0:
            messagebox.showinfo("INFO","Vaccine not yet arrived for the given date")

        for sess in resp_JSON['sessions']:
            age_limit           = sess['min_age_limit']
            center_name         = sess['name']
            pincode             = sess['pincode']
            vaccine_name        = sess['vaccine']
            available_capacity  = sess['available_capacity']
            qnty_dose_1         = sess['available_capacity_dose1']
            qnty_dose_2         = sess['available_capacity_dose2']
            slot_date           = sess['date']

            if available_capacity > 0:
                curr_status = 'Available'
            else:
                curr_status = 'NA'
            
            if age_limit == 45:
                age_grp = '45+'
            else:
                age_grp = '18-44'


            # data_msg = "{0:<12}{1:<40}{2:<10}{3:<10}{4:<5}{5:<5}\n".format(curr_status,center_name,age_grp,vaccine_name,qnty_dose_1,qnty_dose_2)
            # result_box.insert(END, " {0:<10s} {1:<30.28s}    {2:<10s} {3:<14s}  {4:<5} {5:<5} {6:^8}\n".format(curr_status,center_name,str(age_grp),vaccine_name,str(qnty_dose_1),str(qnty_dose_2), available_capacity))
            # result_box.insert(END, str.rjust(age_grp, 8))
            result_box_avl.insert(END, f"{curr_status:^6s}")
            result_box_avl.insert(END,"\n")
            result_box_cent.insert(END, f"{center_name:<30s}")
            result_box_cent.insert(END,"\n")
            result_box_age.insert(END, f"{age_grp:<6s}")
            result_box_age.insert(END,"\n")
            result_box_vacc.insert(END, f"{vaccine_name:<8s}")
            result_box_vacc.insert(END,"\n")
            result_box_D1.insert(END, f"{qnty_dose_1:>5}")
            result_box_D1.insert(END,"\n")
            result_box_D2.insert(END, f"{qnty_dose_2:>5}")
            result_box_D2.insert(END,"\n")
            result_box_D1_D2.insert(END, f"{available_capacity:<5}")
            result_box_D1_D2.insert(END,"\n")
    except KeyError as KE:
        messagebox.showerror("ERROR","No Available center(s) for the given Pincode and date")
        print (pincode_text_var.get())

Step6: Keep the GUI and components to function, until closed

update_clock()

app.mainloop()

Complete code – Desktop App


# Import modules
from tkinter import *
from tkinter import messagebox
from datetime import datetime
import pytz
import requests


software_version = 'v1.1'
IST = pytz.timezone('Asia/Kolkata')


app = Tk()

# App Geometry and components
app.geometry("700x480+400+200")
app.title(f"Vaccine Availability Checker  {software_version}")
app.iconbitmap("Images_Icons\covid-vaccine.ico")
app.resizable(True, True)
app.config(background = '#293241')

## DEFAULT values
PINCODE = '110096'

# Color value reference
top_left_frame_bg  = "#5c4ce1"
top_right_frame_bg = '#867ae9'

# Frame details
frame1 = Frame(app, height = 120, width=180, bg= top_left_frame_bg, bd=1, relief = FLAT)
frame1.place(x=0,y=0)

frame2 = Frame(app, height = 120, width=520, bg= top_right_frame_bg, bd=1, relief = FLAT)
frame2.place(x=180,y=0)

frame3 = Frame(app, height = 30, width=700, bg= 'black', bd=1, relief = RAISED)
frame3.place(x=0,y=120)

# Labels
label_date_now = Label(text="Current Date", bg = top_left_frame_bg, font = 'Verdana 12 bold')
label_date_now.place(x=20, y=40)

label_time_now = Label(text="Current Time", bg = top_left_frame_bg, font = 'Verdana 12')
label_time_now.place(x=20, y=60)

label_pincode = Label(text="Pincode", bg = top_right_frame_bg, font = 'Verdana 11')
label_pincode.place(x=220, y=15)

label_date = Label(text="Date", bg = top_right_frame_bg, font = 'Verdana 11')
label_date.place(x=380, y=15)

label_dateformat = Label(text="[dd-mm-yyyy]", bg = top_right_frame_bg, font = 'Verdana 7')
label_dateformat.place(x=420, y=18)

label_search_vacc = Label(text="Search \nAvailable Vaccine", bg = top_right_frame_bg, font = 'Verdana 8')
label_search_vacc.place(x=570, y=70)

label_head_result = Label(text=" Status       \tCentre-Name\t              Age-Group    Vaccine       Dose_1     Dose_2     Total", bg = 'black', fg='white', font = 'Verdana 8 bold')
label_head_result.place(x=10, y=125)


# Entry boxes
pincode_text_var = StringVar()
pincode_textbox = Entry(app,width = 11, bg = '#eaf2ae', fg= 'black', textvariable = pincode_text_var, font='verdana 11')
pincode_textbox['textvariable'] = pincode_text_var
pincode_textbox.place(x= 220, y=40)

date_text_var = StringVar()
date_textbox = Entry(app,width = 12, bg = '#eaf2ae', fg= 'black', textvariable = date_text_var, font='verdana 10')
date_textbox['textvariable'] = date_text_var
date_textbox.place(x= 380, y=40)


## TEXT BOX
result_box_avl = Text(app, height = 20, width = 8, bg='#293241',fg='#ecfcff', relief=FLAT, font='verdana 10')
result_box_avl.place(x= 3 , y= 152)
result_box_cent = Text(app, height = 20, width = 30, bg='#293241',fg='#ecfcff', relief=FLAT, font='verdana 10')
result_box_cent.place(x= 75 , y= 152)
result_box_age = Text(app, height = 20, width = 8, bg='#293241',fg='#ecfcff', relief=FLAT, font='verdana 10')
result_box_age.place(x= 330 , y= 152)
result_box_vacc = Text(app, height = 20, width = 10, bg='#293241',fg='#ecfcff', relief=FLAT, font='verdana 10')
result_box_vacc.place(x= 400 , y= 152)
result_box_D1 = Text(app, height = 20, width = 7, bg='#293241',fg='#ecfcff', relief=FLAT, font='verdana 10')
result_box_D1.place(x= 490 , y= 152)
result_box_D2 = Text(app, height = 20, width = 7, bg='#293241',fg='#ecfcff', relief=FLAT, font='verdana 10')
result_box_D2.place(x= 555 , y= 152)
result_box_D1_D2 = Text(app, height = 20, width = 7, bg='#293241',fg='#ecfcff', relief=FLAT, font='verdana 10')
result_box_D1_D2.place(x= 630 , y= 152)

## Defining Functions

# Detect Automatic Pincode
def fill_pincode_with_radio():
    curr_pincode = get_pincode_ip_service(url)
    pincode_text_var.set(curr_pincode)

url = 'https://ipinfo.io/postal'
def get_pincode_ip_service(url):
    response_pincode = requests.get(url).text
    return response_pincode

def update_clock():
    raw_TS = datetime.now(IST)
    date_now = raw_TS.strftime("%d %b %Y")
    time_now = raw_TS.strftime("%H:%M:%S %p")
    formatted_now = raw_TS.strftime("%d-%m-%Y")
    label_date_now.config(text = date_now)
    # label_date_now.after(500, update_clock)
    label_time_now.config(text = time_now)
    label_time_now.after(1000, update_clock)
    return formatted_now

def insert_today_date():
    formatted_now = update_clock()
    date_text_var.set(formatted_now)
    tomorrow_date_chkbox['state'] = DISABLED

def refresh_api_call(PINCODE, DATE):
    header = {'User-Agent': 'Chrome/84.0.4147.105 Safari/537.36'}
    request_link = f"https://cdn-api.co-vin.in/api/v2/appointment/sessions/public/findByPin?pincode={PINCODE}&date={DATE}"
    response = requests.get(request_link, headers = header)
    resp_JSON = response.json()
    return resp_JSON

def clear_result_box():
    result_box_avl.delete('1.0', END)
    result_box_cent.delete('1.0', END)
    result_box_age.delete('1.0', END)
    result_box_vacc.delete('1.0', END)
    result_box_D1.delete('1.0', END)
    result_box_D2.delete('1.0', END)
    result_box_D1_D2.delete('1.0', END)

def search_vaccine_avl():
    clear_result_box()
    PINCODE = pincode_text_var.get()
    DATE = date_text_var.get()
    resp_JSON = refresh_api_call(PINCODE, DATE)

    try:
        if len(resp_JSON['sessions']) == 0:
            messagebox.showinfo("INFO","Vaccine not yet arrived for the given date")

        for sess in resp_JSON['sessions']:
            age_limit           = sess['min_age_limit']
            center_name         = sess['name']
            pincode             = sess['pincode']
            vaccine_name        = sess['vaccine']
            available_capacity  = sess['available_capacity']
            qnty_dose_1         = sess['available_capacity_dose1']
            qnty_dose_2         = sess['available_capacity_dose2']
            slot_date           = sess['date']

            if available_capacity > 0:
                curr_status = 'Available'
            else:
                curr_status = 'NA'
            
            if age_limit == 45:
                age_grp = '45+'
            else:
                age_grp = '18-44'


            # data_msg = "{0:<12}{1:<40}{2:<10}{3:<10}{4:<5}{5:<5}\n".format(curr_status,center_name,age_grp,vaccine_name,qnty_dose_1,qnty_dose_2)
            # result_box.insert(END, " {0:<10s} {1:<30.28s}    {2:<10s} {3:<14s}  {4:<5} {5:<5} {6:^8}\n".format(curr_status,center_name,str(age_grp),vaccine_name,str(qnty_dose_1),str(qnty_dose_2), available_capacity))
            # result_box.insert(END, str.rjust(age_grp, 8))
            result_box_avl.insert(END, f"{curr_status:^6s}")
            result_box_avl.insert(END,"\n")
            result_box_cent.insert(END, f"{center_name:<30s}")
            result_box_cent.insert(END,"\n")
            result_box_age.insert(END, f"{age_grp:<6s}")
            result_box_age.insert(END,"\n")
            result_box_vacc.insert(END, f"{vaccine_name:<8s}")
            result_box_vacc.insert(END,"\n")
            result_box_D1.insert(END, f"{qnty_dose_1:>5}")
            result_box_D1.insert(END,"\n")
            result_box_D2.insert(END, f"{qnty_dose_2:>5}")
            result_box_D2.insert(END,"\n")
            result_box_D1_D2.insert(END, f"{available_capacity:<5}")
            result_box_D1_D2.insert(END,"\n")
    except KeyError as KE:
        messagebox.showerror("ERROR","No Available center(s) for the given Pincode and date")
        print (pincode_text_var.get())

# Buttons
search_vaccine_image = PhotoImage(file= "Images_Icons\search-icon.png")
search_vaccine_btn = Button(app, image=search_vaccine_image, bg= top_right_frame_bg, command = search_vaccine_avl, relief= RAISED)
search_vaccine_btn.place(x = 600,y = 25)

# Radio Buttons
curr_loc_var = StringVar()
radio_location = Radiobutton(app, text="Current location", bg= top_right_frame_bg, variable= curr_loc_var, value = curr_loc_var, command = fill_pincode_with_radio) #state=DISABLED
radio_location.place(x=215, y=65)

# Check Box 
chkbox_today_var = IntVar()
today_date_chkbox = Checkbutton(app, text='Today', bg= top_right_frame_bg, variable=chkbox_today_var, onvalue= 1, offvalue=0, command = insert_today_date)
today_date_chkbox.place(x= 375, y= 65)

chkbox_tomorrow_var = IntVar()
tomorrow_date_chkbox = Checkbutton(app, text='Tomorrow', bg= top_right_frame_bg, variable=chkbox_tomorrow_var, onvalue= 1, offvalue=0, state = DISABLED)
tomorrow_date_chkbox.place(x= 435, y= 65)

update_clock()

app.mainloop()

Download Software

Download the ZIP file containing the .exe software, which runs out of the Box


Disclaimer

This code works perfectly but it is not yet mature. We will keep on testing this code and try to find bugs or improvement in the existing code, as and when these bugs or improvement are found, we will update the newer version of the code. (A newer version below the older version). There is a lot of suggestion, received to add a few more features and we are working on it. Hope you like it. If yes, then please share it with someone who is really interested in building one such application.

Way Forward

As mentioned in the disclaimer section, we are working to further simplify and optimize this code as good as possible and during this time you can enjoy the code. This tutorial would have made you learn so much related to building a GUI application. I am sure, you would not stop here but go beyond and create something for yourself. Go ahead and do it, we are with you.

Keep Learning and Keep Growing !!

Leave a Comment

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

Scroll to Top