Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Script for "Weather Notifier" added #963

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pdf_watermarkadder/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def makepdf():
pdf_file = input("PDF file: ")
watermark = 'watermark.pdf'
merged = "finalDraft.pdf"
with open(pdf_file, "rb") as input_file,\
with open(pdf_file, "rb") as input_file, \
open(watermark, "rb") as watermark_file:
input_pdf = PdfFileReader(input_file)
watermark_pdf = PdfFileReader(watermark_file)
Expand Down
51 changes: 42 additions & 9 deletions video_cropper/video_cropper.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ def to_int(a, rel_to):
If string contains "%" it converts it to a float and multiplies by rel_to
EG: 50% -> 0.5*rel_to
'''
if type(a) == int:

if isinstance(a):
return a
else:
if '%' in a:
Expand All @@ -25,13 +26,41 @@ def to_int(a, rel_to):
parser = argparse.ArgumentParser()

parser.add_argument('-i', '--input', type=str, help='the file to crop')
parser.add_argument('-c', '--crop', type=str, help='the amount to crop in the format "TOP,BOTTOM,LEFT,RIGHT"')
parser.add_argument('-t', '--top', type=str, help='the amount to crop off the top of the video')
parser.add_argument('-b', '--bottom', type=str, help='the amount to crop off the bottom of the video')
parser.add_argument('-l', '--left', type=str, help='the amount to crop off the left of the video')
parser.add_argument('-r', '--right', type=str, help='the amount to crop off the right of the video')
parser.add_argument('-o', '--output', type=str, help='the file to output to (cannot be the same as input file)')
parser.add_argument('-y', '--yes', action='store_true', help='skip the prompt to confirm overwriting a file')
parser.add_argument(
'-c',
'--crop',
type=str,
help='the amount to crop in the format "TOP,BOTTOM,LEFT,RIGHT"')
parser.add_argument(
'-t',
'--top',
type=str,
help='the amount to crop off the top of the video')
parser.add_argument(
'-b',
'--bottom',
type=str,
help='the amount to crop off the bottom of the video')
parser.add_argument(
'-l',
'--left',
type=str,
help='the amount to crop off the left of the video')
parser.add_argument(
'-r',
'--right',
type=str,
help='the amount to crop off the right of the video')
parser.add_argument(
'-o',
'--output',
type=str,
help='the file to output to (cannot be the same as input file)')
parser.add_argument(
'-y',
'--yes',
action='store_true',
help='skip the prompt to confirm overwriting a file')

args = parser.parse_args()

Expand Down Expand Up @@ -107,7 +136,11 @@ def to_int(a, rel_to):
sys.exit(1)

# call ffmpeg with the required args
cmd = 'ffmpeg -hide_banner -loglevel error -i "{}" -c:a copy -filter:v "crop={}:{}:{}:{}" {}{}'
cmd = (
'ffmpeg -hide_banner -loglevel error -i "{}" -c:a copy '
'-filter:v "crop={}:{}:{}:{}" {}{}'
)

cmd = cmd.format(
args.input,
width,
Expand Down
34 changes: 34 additions & 0 deletions weather_notifier/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Weather Notifier - README

# Overview
The ** Weather Notifier ** is a Python - based GUI application built with `Tkinter`, which allows users to retrieve weather information for any city using the OpenWeatherMap API. It provides two modes of operation:
- **Manual Mode**: Fetch the weather on - demand with a single click.
- **Auto Mode**: Fetch the weather at regular intervals and can also run in the background.

The app displays current weather details such as temperature, humidity, wind speed, and more in a user - friendly interface.

# Features
- Fetch current weather for any city globally.
- Switch between manual and automatic weather updates.
- Display detailed weather information, including temperature, humidity, wind, and more.
- Option to stop the automatic weather updates and return to the main city selection screen.

# Prerequisites
1. Python 3.x
2. The following Python libraries:
- `Tkinter`
- `requests`
- `threading`
- `geopy`
- `dotenv`

To install the required libraries, use the following command:
```bash
pip install - r requirements.txt
```

# Screenshots
![Main Screen](. / images / box.jpg)
![Error](. / images / error_box.jpg)
![Error](. / images / automated_gui.jpg)
![Error](. / images / data_automated.jpg)
Binary file added weather_notifier/images/automated_gui.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added weather_notifier/images/box.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added weather_notifier/images/data_automated.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added weather_notifier/images/error_box.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions weather_notifier/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
requests=2.28.2
geopy=2.4.1
dotenv=1.0.1
263 changes: 263 additions & 0 deletions weather_notifier/weather_notifier.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
import os
from geopy.geocoders import Nominatim
import tkinter as tk
from tkinter import messagebox
import requests
import threading
import time
from dotenv import load_dotenv
load_dotenv()

API_KEY = os.getenv('OPENWEATHER_API_KEY')
if API_KEY is None:
raise ValueError(
"API key not found. Set the OPENWEATHER_API_KEY in the .env file.")


def calculate_lat_long(city):
geolocator = Nominatim(user_agent="weather_notifier")
location = geolocator.geocode(city)
if location:
return location.latitude, location.longitude
return None, None


def get_weather(lat, long):
try:
print(lat, long)
url = (
f"https://api.openweathermap.org/data/2.5/weather?lat={lat}"
f"&lon={long}&units=metric&appid={API_KEY}"
)
res = requests.get(url)
data = res.json()
if data['cod'] != 404:
weather_info = {
"City": data.get(
"name",
"N/A"),
"Latitude": data['coord']['lat'],
"Longitude": data['coord']['lon'],
"Temperature": data['main']['temp'],
"Feels Like": data['main']['feels_like'],
"Min Temp": data['main']['temp_min'],
"Max Temp": data['main']['temp_max'],
"Pressure": data['main']['pressure'],
"Humidity": data['main']['humidity'],
"Wind Speed": data['wind']['speed'],
"Wind Degree": data['wind']['deg'],
"Weather": data['weather'][0]['description'].capitalize(),
"Clouds": f"{data['clouds']['all']}%",
"Visibility": data.get(
'visibility',
"N/A"),
"Sunrise": time.strftime(
'%Y-%m-%d %H:%M:%S',
time.gmtime(
data['sys']['sunrise'] + data['timezone'])),
"Sunset": time.strftime(
'%Y-%m-%d %H:%M:%S',
time.gmtime(
data['sys']['sunset'] + data['timezone'])),
}
return weather_info
else:
return None

except Exception as e:
messagebox.showerror("Error", f"Error fetching weather data: {str(e)}")
return None

# updating the weather


def update_weather():
city = city_entry.get()
if city:
lat, lon = calculate_lat_long(city)
if lat and lon:
weather_info = get_weather(lat, lon)
if weather_info:
weather_info_in_str_to_display = covert_the_info_to_display(
weather_info)
weather_label.config(text=weather_info_in_str_to_display)
stop_button.pack(pady=5)
city_label.pack_forget()
city_entry.pack_forget()
manual_radio.pack_forget()
auto_radio.pack_forget()
start_button.pack_forget()
interval_label.pack_forget()
interval_entry.pack_forget()
else:
weather_label.config(text="Unable to find coordinates!")
stop_button.pack_forget()
else:
weather_label.config(text="Unable to find coordinates!")
stop_button.pack_forget()
else:
messagebox.showerror("Error", "Please enter a valid city name.")
stop_button.pack_forget()
# displaying the info in the tkinter created box


def covert_the_info_to_display(weather_info):
# Clear the previous text
weather_info_in_str_to_display = (
f"City: {weather_info['City']}\n\n"
f"Coordinates: ({weather_info['Latitude']}, "
f"{weather_info['Longitude']})\n\n"
f"Temperature: {weather_info['Temperature']}°C "
f"(Feels like {weather_info['Feels Like']}°C)\n\n"
f"Min Temp: {weather_info['Min Temp']}°C, "
f"Max Temp: {weather_info['Max Temp']}°C\n\n"
f"Pressure: {weather_info['Pressure']} hPa\n\n"
f"Humidity: {weather_info['Humidity']}%\n\n"
f"Wind: {weather_info['Wind Speed']} m/s, "
f"{weather_info['Wind Degree']}°\n\n"
f"Clouds: {weather_info['Clouds']}\n\n"
f"Visibility: {weather_info['Visibility']} meters\n\n"
f"Weather: {weather_info['Weather']}\n\n"
f"Sunrise: {weather_info['Sunrise']}\n\n"
f"Sunset: {weather_info['Sunset']}\n\n"
)

return weather_info_in_str_to_display

# run_in_background logic


def run_in_background(interval):
while auto_mode.get():
update_weather()
time.sleep(interval)

# Function to handle click


def start_notifier():
if auto_mode.get():
interval_str = interval_entry.get().strip()
if not interval_str:
messagebox.showerror(
"Error", "Please enter a valid interval (in seconds).")
return
try:
interval = int(interval_str)
if interval <= 0:
messagebox.showerror(
"Error", "Please enter a valid interval (in seconds).")
return
except ValueError:
messagebox.showerror("Error", "Please enter a valid number.")
return
start_button.config(state=tk.DISABLED)

threading.Thread(
target=run_in_background, args=(
interval,), daemon=True).start()
else:
update_weather()

# Function to stop auto-updating


def stop_notifier():
auto_mode.set(False)
start_button.config(state=tk.NORMAL)
stop_button.pack_forget()
go_back()


def go_back():
weather_label.config(text="")
city_label.pack(pady=10)
city_entry.pack(pady=5)
manual_radio.pack(anchor=tk.W, padx=20)
auto_radio.pack(anchor=tk.W, padx=20)
start_button.pack(pady=10)
interval_label.pack_forget()
interval_entry.pack_forget()
stop_button.pack_forget()

# gui setup


def show_interval_entry():
if auto_mode.get():
interval_label.pack(pady=5)
interval_entry.pack(pady=5)
else:
interval_label.pack_forget()
interval_entry.pack_forget()


def toggle_stop_button():
if auto_mode.get():
stop_button.pack(pady=5)
else:
stop_button.pack_forget()


if __name__ == '__main__':
city = "Surat"
lat, long = calculate_lat_long(city)
if lat is None or long is None:
print('No city found')
exit(0)

root = tk.Tk()
root.title("Weather Notifier")
root.geometry("550x500")
root.resizable(False, False)

# City Label and Entry
city_label = tk.Label(root, text="Enter your city:")
city_label.pack(pady=10)
city_entry = tk.Entry(root, width=30) # Define city_entry here
city_entry.pack(pady=5)

# Weather Info Label
weather_label = tk.Label(
root, text="", font=(
"Helvetica", 10), justify="left")
weather_label.pack(pady=20)

# Mode Selection: Manual or Automatic
auto_mode = tk.BooleanVar()

manual_radio = tk.Radiobutton(
root,
text="On-click only",
variable=auto_mode,
value=False)
manual_radio.pack(anchor=tk.W, padx=20)

auto_radio = tk.Radiobutton(
root,
text="Run after a fixed interval",
variable=auto_mode,
value=True)
auto_radio.pack(anchor=tk.W, padx=20)

# Interval Entry (only visible when interval mode is selected)
interval_label = tk.Label(root, text="Enter interval (seconds):")
interval_entry = tk.Entry(root, width=10)

auto_mode.trace_add("write", lambda *args: show_interval_entry())

# Start Button
start_button = tk.Button(
root,
text="Start Notifier",
command=start_notifier)
start_button.pack(pady=10)

# Stop Button (visible only when auto mode is active)
stop_button = tk.Button(root, text="Stop Notifier", command=stop_notifier)
stop_button.pack_forget()

auto_mode.trace_add("write", lambda *args: toggle_stop_button())

# Run the GUI loop
root.mainloop()
Loading