Skip to content

Commit edf9bac

Browse files
committed
added the script that shows the weather data either once or runs in background at specified interval, gui is made using tkinter and weather data is coming from open weather api
1 parent 0fa47cd commit edf9bac

File tree

2 files changed

+211
-0
lines changed

2 files changed

+211
-0
lines changed

weather_notifier/requirements.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
requests=2.28.2
2+
geopy=2.4.1
3+
dotenv=1.0.1

weather_notifier/weather_notifier.py

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
import tkinter as tk
2+
from tkinter import messagebox
3+
import requests
4+
import threading
5+
import time
6+
from dotenv import load_dotenv
7+
load_dotenv()
8+
from geopy.geocoders import Nominatim
9+
import os
10+
11+
API_KEY=os.getenv('OPENWEATHER_API_KEY')
12+
if API_KEY is None:
13+
raise ValueError("API key not found. Please set the OPENWEATHER_API_KEY in the .env file.")
14+
15+
def calculate_lat_long(city):
16+
geolocator = Nominatim(user_agent="weather_notifier")
17+
location = geolocator.geocode(city)
18+
if location:
19+
return location.latitude, location.longitude
20+
return None,None
21+
def get_weather(lat,long):
22+
try:
23+
print(lat,long)
24+
url=f"https://api.openweathermap.org/data/2.5/weather?lat={lat}&lon={long}&units=metric&appid={API_KEY}"
25+
res=requests.get(url)
26+
data = res.json()
27+
if data['cod'] != 404:
28+
weather_info = {
29+
"City": data.get("name", "N/A"),
30+
"Latitude": data['coord']['lat'],
31+
"Longitude": data['coord']['lon'],
32+
"Temperature": data['main']['temp'],
33+
"Feels Like": data['main']['feels_like'],
34+
"Min Temp": data['main']['temp_min'],
35+
"Max Temp": data['main']['temp_max'],
36+
"Pressure": data['main']['pressure'],
37+
"Humidity": data['main']['humidity'],
38+
"Wind Speed": data['wind']['speed'],
39+
"Wind Degree": data['wind']['deg'],
40+
"Weather": data['weather'][0]['description'].capitalize(),
41+
"Clouds": f"{data['clouds']['all']}%",
42+
"Visibility": data.get('visibility', "N/A"),
43+
"Sunrise": time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(data['sys']['sunrise'] + data['timezone'])),
44+
"Sunset": time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(data['sys']['sunset'] + data['timezone'])),
45+
}
46+
return weather_info
47+
else:
48+
return None
49+
50+
except Exception as e:
51+
messagebox.showerror("Error", f"Error fetching weather data: {str(e)}")
52+
return None
53+
54+
# updating the weather
55+
def update_weather():
56+
city=city_entry.get()
57+
if city:
58+
lat, lon = calculate_lat_long(city)
59+
if lat and lon:
60+
weather_info = get_weather(lat, lon)
61+
if weather_info:
62+
weather_info_in_str_to_display=covert_the_info_to_display(weather_info)
63+
weather_label.config(text=weather_info_in_str_to_display)
64+
stop_button.pack(pady=5)
65+
city_label.pack_forget()
66+
city_entry.pack_forget()
67+
manual_radio.pack_forget()
68+
auto_radio.pack_forget()
69+
start_button.pack_forget()
70+
else:
71+
weather_label.config(text="Unable to find coordinates!")
72+
stop_button.pack_forget()
73+
else:
74+
weather_label.config(text="Unable to find coordinates!")
75+
stop_button.pack_forget()
76+
else:
77+
messagebox.showerror("Error", "Please enter a valid city name.")
78+
stop_button.pack_forget()
79+
# displaying the info in the tkinter created box
80+
def covert_the_info_to_display(weather_info):
81+
# Clear the previous text
82+
weather_info_in_str_to_display= f'''
83+
City: {weather_info['City']}\n
84+
Coordinates: ({weather_info['Latitude']}, {weather_info['Longitude']})\n
85+
Temperature: {weather_info['Temperature']}°C (Feels like {weather_info['Feels Like']}°C)\n
86+
Min Temp: {weather_info['Min Temp']}°C, Max Temp: {weather_info['Max Temp']}°C\n
87+
Pressure: {weather_info['Pressure']} hPa\n
88+
Humidity: {weather_info['Humidity']}%\n
89+
Wind: {weather_info['Wind Speed']} m/s, {weather_info['Wind Degree']}°\n
90+
Clouds: {weather_info['Clouds']}\n
91+
Visibility: {weather_info['Visibility']} meters\n
92+
Weather: {weather_info['Weather']}\n
93+
Sunrise: {weather_info['Sunrise']}\n
94+
Sunset: {weather_info['Sunset']}\n
95+
'''
96+
return weather_info_in_str_to_display
97+
98+
# run_in_background logic
99+
def run_in_background(interval):
100+
while auto_mode.get():
101+
update_weather()
102+
time.sleep(interval)
103+
104+
# Function to handle click
105+
def start_notifier():
106+
if auto_mode.get():
107+
interval_str = interval_entry.get().strip()
108+
if not interval_str:
109+
messagebox.showerror("Error", "Please enter a valid interval (in seconds).")
110+
return
111+
try:
112+
interval=int(interval_str)
113+
if interval <= 0:
114+
messagebox.showerror("Error", "Please enter a valid interval (in seconds).")
115+
return
116+
except ValueError as e:
117+
messagebox.showerror("Error", "Please enter a valid number.")
118+
return
119+
start_button.config(state=tk.DISABLED)
120+
121+
threading.Thread(target=run_in_background, args=(interval,), daemon=True).start()
122+
else:
123+
update_weather()
124+
125+
# Function to stop auto-updating
126+
def stop_notifier():
127+
auto_mode.set(False)
128+
start_button.config(state=tk.NORMAL)
129+
stop_button.pack_forget()
130+
go_back()
131+
132+
def go_back():
133+
weather_label.config(text="")
134+
city_label.pack(pady=10)
135+
city_entry.pack(pady=5)
136+
manual_radio.pack(anchor=tk.W, padx=20)
137+
auto_radio.pack(anchor=tk.W, padx=20)
138+
start_button.pack(pady=10)
139+
interval_label.pack_forget()
140+
interval_entry.pack_forget()
141+
stop_button.pack_forget()
142+
143+
# gui setup
144+
def show_interval_entry():
145+
if auto_mode.get():
146+
interval_label.pack(pady=5)
147+
interval_entry.pack(pady=5)
148+
else:
149+
interval_label.pack_forget()
150+
interval_entry.pack_forget()
151+
152+
def toggle_stop_button():
153+
if auto_mode.get():
154+
stop_button.pack(pady=5)
155+
else:
156+
stop_button.pack_forget()
157+
158+
if __name__=='__main__':
159+
city ="Surat"
160+
lat,long=calculate_lat_long(city)
161+
if lat==None or long==None:
162+
print('No city found')
163+
exit(0)
164+
165+
root = tk.Tk()
166+
root.title("Weather Notifier")
167+
root.geometry("550x500")
168+
root.resizable(False, False)
169+
170+
# City Label and Entry
171+
city_label = tk.Label(root, text="Enter your city:")
172+
city_label.pack(pady=10)
173+
city_entry = tk.Entry(root, width=30) # Define city_entry here
174+
city_entry.pack(pady=5)
175+
176+
# Weather Info Label
177+
weather_label = tk.Label(root, text="", font=("Helvetica", 10),justify="left")
178+
weather_label.pack(pady=20)
179+
180+
# Mode Selection: Manual or Automatic
181+
auto_mode = tk.BooleanVar()
182+
183+
manual_radio = tk.Radiobutton(root, text="On-click only", variable=auto_mode, value=False)
184+
manual_radio.pack(anchor=tk.W, padx=20)
185+
186+
auto_radio = tk.Radiobutton(root, text="Run after a fixed interval", variable=auto_mode, value=True)
187+
auto_radio.pack(anchor=tk.W, padx=20)
188+
189+
# Interval Entry (only visible when interval mode is selected)
190+
interval_label = tk.Label(root, text="Enter interval (seconds):")
191+
interval_entry = tk.Entry(root, width=10)
192+
193+
194+
195+
auto_mode.trace_add("write", lambda *args: show_interval_entry())
196+
197+
# Start Button
198+
start_button = tk.Button(root, text="Start Notifier", command=start_notifier)
199+
start_button.pack(pady=10)
200+
201+
# Stop Button (visible only when auto mode is active)
202+
stop_button = tk.Button(root, text="Stop Notifier", command=stop_notifier)
203+
stop_button.pack_forget()
204+
205+
auto_mode.trace_add("write", lambda *args: toggle_stop_button())
206+
207+
# Run the GUI loop
208+
root.mainloop()

0 commit comments

Comments
 (0)