from PIL import Image from PIL import ImageDraw from PIL import ImageFont from datetime import datetime, timedelta from time import gmtime, strftime import time from itertools import groupby from hasApi import get_calendar_events, get_todo_items import dateutil.parser from dotenv import load_dotenv black = "#000000" white = "#ffffff" fontSymbols = ImageFont.truetype("SymbolsNerdFont-Regular.ttf", 18) fontTitle = ImageFont.truetype("Nunito-Bold.ttf", 24) fontLarge = ImageFont.truetype("Nunito-ExtraLight.ttf", 18) fontLargeBold = ImageFont.truetype("Nunito-SemiBold.ttf", 18) fontSmall = ImageFont.truetype("Nunito-ExtraLight.ttf", 16) fontVerySmall = ImageFont.truetype("Nunito-ExtraLight.ttf", 10) class Space(Exception): pass def getsize(font, text): _, _, right, bottom = font.getbbox(text) return (right, bottom) def reflow_quote(quote, width, font): words = quote.split(" ") reflowed = "" line_length = 0 for i in range(len(words)): word = words[i] + " " word_length = getsize(font, word)[0] line_length += word_length if line_length < width: reflowed += word else: line_length = word_length reflowed = reflowed[:-1] + "\n " + word reflowed = reflowed.rstrip() return reflowed def draw_image(): image = Image.new("P", (400, 300)) draw = ImageDraw.Draw(image) # Draw the top bar topbar = 26 draw.rectangle((0, 0, 400, 300), fill=white) draw.rectangle((0, 0, 400, topbar), fill=black) # Add the clock timeStr = strftime("%H:%M", time.localtime()) draw.text((10, 3), timeStr, white, fontSmall) # Add indoor temperature draw.text((350, 3), "19c", white, fontSmall) # Add sections ep = 3 margin = 5 draw.rounded_rectangle( (margin, topbar + margin, (400 / 2) - margin, 300 - margin), 10, outline=black, width=2, ) draw.rounded_rectangle( ((400 / 2) + margin, topbar + margin, 400 - margin, 300 - margin), 10, outline=black, width=2, ) # Add tasks draw.text((20, topbar + 7), "Tasks", black, fontTitle) draw.line((margin, 62, 200 - margin, 62), fill=black, width=1) tasks = get_todo_items() taskStart = 70 for task in tasks: if task["status"] == "completed": continue draw.text((15, taskStart - 2), "󰄵", black, fontSymbols) else: draw.text((15, taskStart), "󰄱", black, fontSymbols) reflowedTitle = reflow_quote(task["summary"], 160, fontLarge) titleSizeW, titleSizeH = getsize(fontLarge, reflowedTitle) titleSizeH *= reflowedTitle.count("\n") + 1 draw.text((35, taskStart - 3), reflowedTitle, black, fontLarge) taskStart += titleSizeH + (2 * ep) # Add cal draw.text((220, topbar + 7), "Calendar", black, fontTitle) draw.line(((400 / 2) + margin, 62, 400 - margin, 62), fill=black, width=1) events = get_calendar_events() def get_start_date(x): start = x["start"] if "date" in start: startDate = datetime.strptime(start["date"], "%Y-%m-%d").date() elif "dateTime" in start: startDate = datetime.strptime(start["dateTime"][:10], "%Y-%m-%d").date() else: print("Error") print(start) return None if startDate < datetime.today().date(): return datetime.today().date() else: return startDate itemStart = 70 try: for key, group in groupby(events, get_start_date): if key == datetime.today().date(): dateStr = "Today" elif key == (datetime.today() + timedelta(days=1)).date(): dateStr = "Tomorrow" else: dateStr = key.strftime("%d %b") draw.text((215, itemStart), dateStr, black, fontLargeBold) w, h = getsize(fontLarge, "Today") itemStart += h + (ep) for thing in list(group): reflowedItem = reflow_quote(thing["summary"], 170, fontSmall) w, h = getsize(fontLarge, "Today") h *= reflowedItem.count("\n") + 1 # print(f'After {reflowedItem}, {itemStart + h}') if itemStart + h > 270: raise Space draw.text((230, itemStart), reflowedItem, black, fontSmall) itemStart += h + (ep) if itemStart > 250: raise Space except Space: pass return image if __name__ == "__main__": load_dotenv() img = draw_image() img.save("built.bmp")