Source code for weather
import requests
import json
import os
import tkinter as tk
from plugin import Plugin
import weatherapi
from weathericons import load_weather_icons
IP_INFO = 'http://ipinfo.io/json'
API_KEY = 'c67a801854866dfb'
API_ADDRESS = 'http://api.wunderground.com/api/'
API_CONDITIONS = '/conditions/q/'
TEMPERATURE_SCALE = 'c'
TEMPERATURE_FONT = ('Calibri Light', 55)
[docs]class Weather(tk.Frame, Plugin):
"""Weather module class.
Weather class inherits from tkinter's Frame class and abstract
Plugin class. This module displays weather conditions as an icon
and current temperature in Fahrenheit or Celsius scale depending
on user's preference.
Ipinfo api is used for finding current location and weather
underground api is used for polling weather information.
"""
def __init__(self, master, controller):
tk.Frame.__init__(self, master, bg='black', highlightbackground='black',
highlightthickness=2, cursor='none')
self._controller = controller
self._weather_api = weatherapi.WeatherApiWrapper()
# Creating a dictionary of weather icons.
self._weather_icons = load_weather_icons()
self._framename_coords_dict = controller.get_framename_coords_dict()
self._location = list()
# Finding user's current location.
self._get_location()
self._weather_label = tk.Label(self, bg='black')
self._temperature_label = tk.Label(self, bg='black')
# Placing labels inside a grid geometry manager.
self._weather_label.grid(row=0, column=0, sticky='nesw')
self._temperature_label.grid(row=0, column=1, sticky='ns')
# Coordinates relative to this class' frame.
self._mouse_left_button_click_x_cord = 0
self._mouse_left_button_click_y_cord = 0
# Variable for determining whether the edit mode should be
# switched on or off.
self._frame_in_edit_mode = False
self._display_current_weather_and_temperature()
[docs] def edit_mode(self):
"""Switches edit_mode on/off.
When switching edit mode on this function first makes mouse
cursor visible when on top of this module and makes background
highlight visible by changing it's color to yellow, then
appropriate event handlers are bind to left mouse button click
(<Button-1>) and mouse motion with left mouse button pressed
(<B1-Motion>) for every component.
When switching edit mode off cursor is first hidden, highlight
made invisible by changing it's color to black, then mouse
input event handlers are unbound from all components.
"""
if not self._frame_in_edit_mode:
self._frame_in_edit_mode = True
self.config(highlightbackground='yellow', cursor='arrow')
for label in self.winfo_children():
label.bind('<Button-1>', self._mouse_left_button_click)
label.bind('<B1-Motion>', self._mouse_left_button_motion)
label.bind('<ButtonRelease-1>', self._mouse_left_button_release)
else:
self._frame_in_edit_mode = False
self.config(highlightbackground='black', cursor='none')
for label in self.winfo_children():
label.unbind('<Button-1>')
label.unbind('<B1-Motion>')
label.unbind('<ButtonRelease-1>')
def _mouse_left_button_click(self, event):
"""Saves coordinates of left mouse button click relative to
this class's frame."""
# Saves coordinates of left mouse button click relative to
# this module's frame. These coordinates are calculated by
# adding mouse event coordinates relative to Label on which
# the user clicked to coordinates of said label relative to
# this module's frame.
self._mouse_left_button_click_x_cord = event.widget.winfo_x() + event.x
self._mouse_left_button_click_y_cord = event.widget.winfo_y() + event.y
def _mouse_left_button_motion(self, event):
"""Repositions frame according to mouse cursor movement while
left button is pressed."""
self.place(x=event.x_root - self._mouse_left_button_click_x_cord,
y=event.y_root - self._mouse_left_button_click_y_cord)
coords = (event.x_root - self._mouse_left_button_click_x_cord,
event.y_root - self._mouse_left_button_click_y_cord)
self._framename_coords_dict['Weather'] = coords
def _mouse_left_button_release(self, event):
"""Saves new position to json file."""
with open('../resources/dicts/framename_coords_dict.json', 'w') as dict_json:
json.dump(self._framename_coords_dict, dict_json)
def _get_location(self):
"""Determines current location using ip."""
response = requests.get(IP_INFO)
location_json = response.json()
self._location.append(location_json['country'])
self._location.append(location_json['city'])
def _display_current_weather_and_temperature(self):
"""Updates labels with current weather and temperature."""
# Weather underground api call.
returncode, weather_json = self._weather_api.get_weather()
if returncode == -1:
self._weather_api.call_weather_api(self._location[0], self._location[1])
if weather_json:
# Extracting icon name from icon_url provided in returned
# json by removing path to the file, and then removing
# file extension. This is the only way to distinct daytime
# and nighttime on the api level.
icon_url = weather_json['current_observation']['icon_url']
icon = os.path.basename(icon_url)
icon = os.path.splitext(icon)[0]
temp_scale = 'temp_' + TEMPERATURE_SCALE
temperature_text = ' ' + str(weather_json['current_observation'][temp_scale])\
+ '\N{DEGREE SIGN}'
self._weather_label.config(image=self._weather_icons[icon])
self._temperature_label.config(text=temperature_text, font=TEMPERATURE_FONT,
fg='white')
self.after(900000, self._display_current_weather_and_temperature)
else:
self.after(500, self._display_current_weather_and_temperature)