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