from newsapi import NewsApiClient from Tkinter import * from decimal import * import webbrowser import PIL.Image import datetime import requests import time import json import sys import dis import os directory = '<your weather-icon directory' # Where you stored your collection of weather icons time1 = '' # used in clock news_api_key = '<your news api key>' # News API key weather_api_key = '<your weather api key' # Dark Sky API key width = 100 # Width of four day forecast icons in pixels height = 100 # Height of four day forecast icons in pixels degree_sign = u'\N{DEGREE SIGN}' # unicode degrees sign for temperature # *****Headline Class***** # class Headline: # Headline Object consists of a button and an onClick() method def __init__(self, headline, url, parent_frame): self.Btn = Button(parent_frame, justify=LEFT, wraplength=250, text=headline, command=self.onClick, highlightbackground='black', highlightcolor='black', highlightthickness=1) self.url = url def onClick(self): webbrowser.open(self.url) # When pressed open url in web browser # *****Following 4 day forecast Tkinter layout***** # class DailyWeather: days_of_the_week = ['Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat', 'Sun'] # list of abbreviated weekdays today = datetime.datetime.today().weekday() # get integer value for current day of the week # index is it's index of the list produced by getWeather, this identifies it's numerical distance from today's day of the week # forecast_icons is a dictionary consisting of the icon key names parameter and the local path to the corresponding icon image file def __init__(self, icon, temp, index, parent_frame, forecast_icons): self.frame = Frame(parent_frame, highlightbackground='black', highlightcolor='black', highlightthickness=1) # create frame inside parent_frame # index determines day of the week and therefore placement relative to today's weather if index == 0: self.frame.grid(column=2, row=1, sticky=N + S + E + W) if index == 1: self.frame.grid(column=0, row=2, sticky=N + S + E + W) if index == 2: self.frame.grid(column=1, row=2, sticky=N + S + E + W) if index == 3: self.frame.grid(column=2, row=2, sticky=N + S + E + W) # configure the 3 by 3 layout to scale when there is available space for i in range(0, 3): self.frame.rowconfigure(i, weight=1) self.frame.columnconfigure(i, weight=1) self.fp = forecast_icons.get(icon) # get file path of the icon self.img = PhotoImage( file=self.fp) # convert image into Tkinter PhotoImage object so it can be placed in a label self.icon = Label(self.frame, image=self.img) # create icon label self.temp = Label(self.frame, text=str(temp) + ' ' + degree_sign + 'C') # create temperature label self.day_name = self.days_of_the_week[ (self.today + index + 1) % len( self.days_of_the_week)] # use modulo to make list circular and retrieve relative day of the week self.day = Label(self.frame, text=self.day_name) # create day of the week label # place the objects labels in the proper spots def place(self): self.icon.grid(row=0, column=0, rowspan=3, columnspan=2, sticky=N + S + E + W) self.day.grid(row=0, column=2, sticky=N + S + E + W) self.temp.grid(row=2, column=2, sticky=N + S + E + W) # *****Today's Weather Label Layout***** # class TodaysWeather: # icon_fp is the filepath to today's weather icon def __init__(self, icon_fp, temp, summary, parent_frame): self.todaysWeatherFrame = Frame(parent_frame, highlightbackground='black', highlightcolor='black', highlightthickness=1) # create frame for today's weather self.todaysWeatherFrame.grid(column=0, columnspan=2, row=0, rowspan=2, sticky=N + S + E + W) # configure todaysWeatherFrame to scale for i in range(0, 3): self.todaysWeatherFrame.rowconfigure(i, weight=1) self.todaysWeatherFrame.columnconfigure(i, weight=1) # image process is the same as explained in DailyWeather self.fp = icon_fp self.img = PhotoImage(file=self.fp) self.icon = Label(self.todaysWeatherFrame, image=self.img) self.temp = Label(self.todaysWeatherFrame, text=str(temp) + ' ' + degree_sign + 'C', justify=LEFT) self.summary = Label(self.todaysWeatherFrame, text=summary) self.today = Label(self.todaysWeatherFrame, text='Today', justify=LEFT) def place(self): self.icon.grid(row=0, column=0, rowspan=2, columnspan=3, sticky=N + S + E + W) self.temp.grid(row=1, column=3, sticky=N + S + E + W) self.summary.grid(row=2, column=0, columnspan=4, sticky=N + S + E + W) self.today.grid(row=0, column=3, sticky=N + S + E + W) class MainWindow: def __init__(self, directory, news_api_key, weather_api_key, width, height): # initialize MainWindow object variables self.width = width # width of DailyWeather icons self.height = height # height of DailyWeather icons self.news_api_key = news_api_key self.weather_api_key = weather_api_key self.directory = directory # directory of base weather icons self.buttonHeadlines = [] # list of headline buttons self.forecast = [] # list containing the next four days weather self.forecast_icons = {} # dictionary of standardized weather keys, and their corresponding DailyWeather sized icon paths self.todays_icons = {} # dictionary of standardized weather keys, and their corresponding TodaysWeather sized icon paths self.objects = {} # holds daily weather objects self.state = False # state for full screen toggle self.root = Tk() # base Tk() object self.country = '' # country code used for news headlines self.todays_weather_list = [] def body(self): self.root.attributes('-fullscreen', True) # start in fullscreen mode self.root.bind("<F11>", self.toggle_fullscreen) # bind F11 as button to toggle fullscreen self.root.bind("<Escape>", self.end_fullscreen) # bind Escape as a way to exit fullscreen self.root.columnconfigure(0, weight=1) # making root scalable in y self.root.rowconfigure(0, weight=1) # and x # ***Base Frame*** # frame = Frame(self.root) # allow frame to scale to the size of root frame.rowconfigure(0, weight=1) frame.columnconfigure(1, weight=1) frame.grid(sticky=N + S + E + W) # sticky allows it to scale in all directions # ***Create Left Frame for News Headlines*** # leftFrame = Frame(frame, bg="red") leftFrame.grid(row=0, column=0, sticky=N + S + E + W) # in the first row and column of frame # ***Making the headlines scalable*** # leftFrame.columnconfigure(0, weight=1) # top ten headlines, be displayed in 10 rows for i in range(0, 10): leftFrame.rowconfigure(i, weight=1) # ***Frame for clock and weather*** # rightFrame = Frame(frame) rightFrame.grid(column=1, row=0, sticky=N + S + E + W) # allow frame to scale rightFrame.columnconfigure(0, weight=1) rightFrame.rowconfigure(0, weight=1) # ***Frame for weather data*** # weatherFrame = Frame(rightFrame) weatherFrame.grid(column=0, row=0, sticky=N + S + E + W) # make rows and columns of weather data scalable for i in range(0, 3): weatherFrame.rowconfigure(i, weight=1) weatherFrame.columnconfigure(i, weight=1) # *****Weather***** # todays_forecast, four_day_forecast = self.getWeather() # *** Four Day Forecast*** # for i, day in enumerate(four_day_forecast): item = DailyWeather(day[0], day[1], i, weatherFrame, self.forecast_icons) # day[0] = icon, day[1] = avgTemp self.objects['item' + str(i)] = item # store in dictionary to avoid garbage collection on image for item in self.objects: self.objects[item].place() # place the DailyWeather Items # ***Today's weather*** # icon_fp = self.todays_icons.get(todays_forecast[0]) temp = todays_forecast[1] summary = todays_forecast[2] todays_weather = TodaysWeather(icon_fp, temp, summary, weatherFrame) self.todays_weather_list.append(todays_weather) # store it in list so that garbage collection doesn't throw out the image self.todays_weather_list[0].place() # place stored TodaysWeather object # ***Headlines*** # for title in self.getNews(self.country): # takes in country code for relevant news headline = Headline(title[0], title[1], leftFrame) # create Headline object with each headline. title[0] = title or article, title[1] = url of article self.buttonHeadlines.append(headline) # create list of headline objects # ***Clock Placeholder*** # Clock = Label(weatherFrame, font=('helvetica', 20, 'bold'), highlightbackground='black', highlightcolor='black', highlightthickness=1) # ***Packing in Headlines*** 3 for i, object in enumerate(self.buttonHeadlines): object.Btn.grid(row=i, sticky=N + S + E + W) # *****Clock Widget***** # def tick(): global time1 # get the current local time from the PC time2 = time.strftime('%H:%M:%S') # if time string has changed, update it if time2 != time1: time1 = time2 Clock.config(text=time2) # calls itself every 200 milliseconds # to update the time display as needed # could use >200 ms, but display gets jerky Clock.after(200, tick) # ***Placing Clock*** # Clock.grid(column=2, row=0, sticky=N + S + E + W) tick() def toggle_fullscreen(self, event=None): self.state = not self.state # Just toggling the boolean self.root.attributes("-fullscreen", self.state) def end_fullscreen(self, event=None): self.state = False self.root.attributes("-fullscreen", False) def getNews(self, country): newsapi = NewsApiClient(api_key=self.news_api_key) newsHeadlines = [] top_headlines = newsapi.get_top_headlines(country=country) response = top_headlines # this is already in json format, hype top_ten_headlines = response['articles'][:10] # take top 10 headlines for articles in top_ten_headlines: newsHeadlines.append((articles['title'].encode('utf-8'), articles['url'].encode('utf-8'))) return newsHeadlines # return list of tuples def getWeather(self): four_day_forecast = [] # list of tuples[(icon, avgTemp)] # ***Use IP to get Lat/Long for local weather r = requests.get('http://ip-api.com/json') response = r.text response = json.loads(response) lat_long = str(response['lat']) + ', ' + str(response['lon']) self.country = str(response['countryCode']) self.country = self.country.lower() # ***API request to get weather data url = 'https://api.darksky.net/forecast/' + self.weather_api_key + '/' + lat_long weather = requests.get(url, params={'exclude': 'minutely,alerts,flags', 'units': 'ca'}) weather = weather.json() # ***Today's weather info*** # todays_weather_raw = weather['hourly']['data'][0] todays_summary = todays_weather_raw['summary'] # summary of today's weather todays_icon = todays_weather_raw['icon'] # icon for today's weather temp = Decimal(todays_weather_raw['temperature']) temp = round(temp, 1) todays_temp = temp # current temp todays_weather = [todays_icon, todays_temp, todays_summary] # ***Next 4 days weather*** # for i in range(1, 5): daily_weather = weather['daily']['data'][i] x = Decimal((daily_weather['temperatureHigh'] + daily_weather['temperatureLow']) / 2) avg_temp = round(x, 1) four_day_forecast.append((daily_weather['icon'], avg_temp)) # now just have to reference icon title to a library of icons for representation in gui return todays_weather, four_day_forecast # *****Resize Icons***** # def resize_icons(self): # ***Create Subdirectories for resized icons*** # subdir_forecast = self.directory + 'forecast' # directory for daily forecast sized icons subdir_todays = self.directory + 'todays' # directory for today's weather sized icons # if they don't already exist if not os.path.exists(subdir_forecast): os.makedirs(subdir_forecast) if not os.path.exists(subdir_todays): os.makedirs(subdir_todays) # ***Iterate through icons directory resizing each image*** # for file in os.listdir(directory): if file.endswith('.jpeg') or file.endswith('.png'): # expand depending on what file types your icons are original_path = directory + file # open images so they can be resized fp = open(original_path) img = PIL.Image.open(fp) resizedImage = img.resize((self.width, self.height), PIL.Image.ANTIALIAS) resizedImage.save(subdir_forecast + '/' + file, "PNG") # save forecast sized icon fp.close() resizedImage.close() # repeat above for double the size today's icons fp = open(original_path) img = PIL.Image.open(fp) resizedImage = img.resize((int(2 * width), int(2 * height)), PIL.Image.ANTIALIAS) # adjust the multiplying factor of height and width resizedImage.save(subdir_todays + '/' + file, "PNG") fp.close() resizedImage.close() # fill dictionary for reference in filling label name, extension = file.split(".") self.forecast_icons[name] = str(subdir_forecast + '/' + file) self.todays_icons[name] = str(subdir_todays + '/' + file) if __name__ == '__main__': window = MainWindow(directory, news_api_key, weather_api_key, width, height) window.resize_icons() window.body() window.root.mainloop()