Skip to content

Instantly share code, notes, and snippets.

@hcho3
Last active March 12, 2025 03:53
Show Gist options
  • Save hcho3/e173a69cb144a0132c8384abe8b9a6c6 to your computer and use it in GitHub Desktop.
Save hcho3/e173a69cb144a0132c8384abe8b9a6c6 to your computer and use it in GitHub Desktop.
# Check for open appointments in the current month at Las Vegas DMV
# Currently, the script looks for appointments of type "Multiple Services - DL/Vehicle"
import datetime
import time
import boto3
import requests
# List of Nevada DMV locations in the Las Vegas metro area
las_dmv = { # site_id, servicetype_id
"Flamingo": (402410, 1260),
"Sahara": (402419, 870),
"Decatur": (402418, 1143),
"Henderson": (402408, 1026),
}
request_headers = {
"Accept": "application/json",
"User-Agent": (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/133.0.0.0 Safari/537.36"
), # Need to spoof the user agent to avoid 429 error
}
email_to = "[email protected]"
email_from = "[email protected]"
def format_url_date_list(*, site_id: str, servicetype_id: str) -> str:
"""List all dates where appointment slots are available"""
return (
f"https://api.waitwell.us/api/{site_id}/client/appointments/available?"
f"ServiceType_id={servicetype_id}&CheckDates=1"
)
def format_url_slot_list(*, site_id: str, servicetype_id: str, date: str) -> str:
"""List all available time slots in a given date"""
start_date = datetime.datetime.strptime(date, "%Y-%m-%d").date()
end_date = start_date + datetime.timedelta(days=1)
return (
f"https://api.waitwell.us/api/{site_id}/client/appointments/available?"
f"ServiceType_id={servicetype_id}&StartDate={start_date}&EndDate={end_date}"
f"&limit=80&AM=1&PM=1"
)
def filter_by_month(date: str, *, month: int) -> bool:
return datetime.datetime.strptime(date, "%Y-%m-%d").date().month == month
def check_date_for_slots(*, site_id: str, servicetype_id: str, date: str) -> str:
url = format_url_slot_list(
site_id=site_id, servicetype_id=servicetype_id, date=date
)
r = requests.get(url, headers=request_headers)
r.raise_for_status()
obj = r.json()
if obj["rows"]:
return True
return False
def alert_via_email(message: str):
"""
Send an alert via e-mail, using Simple Email Service from AWS.
Make sure to configure AWS credentials.
"""
client = boto3.client("ses", region_name="us-west-2")
response = client.send_email(
Destination={
"ToAddresses": [
email_to,
],
},
Message={
"Body": {
"Text": {
"Charset": "UTF-8",
"Data": message,
},
},
"Subject": {
"Charset": "UTF-8",
"Data": "Alert from Philip's monitor for NV DMV appt",
},
},
Source=email_from,
)
def check_spot() -> bool:
this_month = datetime.datetime.today().month
for location, (site_id, servicetype_id) in las_dmv.items():
url = format_url_date_list(site_id=site_id, servicetype_id=servicetype_id)
r = requests.get(url, headers=request_headers)
r.raise_for_status()
obj = r.json()
# Filter available dates this month
dates = [e for e in obj["dates"] if filter_by_month(e, month=this_month)]
# Check individual dates by making a second request to view available
# time slots in each date.
# Sometimes a date shows up as available, but in fact all slots are taken
dates = [
date
for date in dates[:5]
if check_date_for_slots(
site_id=site_id, servicetype_id=servicetype_id, date=date
)
]
if dates:
t = ", ".join(dates)
msg = f"DMV {location} has free slots in {t}"
print(msg)
alert_via_email(msg)
return True
else:
print(f"DMV {location} has no free slot this month")
return False
if __name__ == "__main__":
while True:
r = check_spot()
if r:
break
print("Checking again in 60 sec...")
time.sleep(60)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment