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 for key, group in groupby(events, get_start_date): dayStart = itemStart # Calculate if key == datetime.today().date(): dateStr = "Today" elif key == (datetime.today() + timedelta(days=1)).date(): dateStr = "Tomorrow" else: dateStr = key.strftime("%d %b") w, h = getsize(fontLarge, "Today") dayStart += h + (ep) dayTasks = list(group) for thing in dayTasks: reflowedItem = reflow_quote(thing["summary"], 170, fontSmall) w, h = getsize(fontLarge, "Today") h *= reflowedItem.count("\n") + 1 dayStart += h + (ep) dayStart + ep if dayStart > 280: print() break # Commit if possible draw.text((215, itemStart), dateStr, black, fontLargeBold) w, h = getsize(fontLargeBold, dateStr) itemStart += h + ep for thing in dayTasks: reflowedItem = reflow_quote(thing["summary"], 170, fontSmall) w, h = getsize(fontSmall, thing["summary"]) h *= reflowedItem.count("\n") + 1 draw.text((230, itemStart), reflowedItem, black, fontSmall) itemStart += h + ep itemStart += ep return image if __name__ == "__main__": load_dotenv() img = draw_image() img.save("built.bmp")