Skip to content
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
22 changes: 17 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
# Aplikacja Pogody

To prosta aplikacja w Pythonie, która pobiera i wyświetla aktualną pogodę dla wybranego miasta, korzystając z darmowego API Open-Meteo (https://open-meteo.com/). Nie wymaga klucza API ani rejestracji.
To prosta aplikacja w Pythonie, która pobiera i wyświetla aktualną pogodę dla wybranego miasta, korzystając z darmowego API Open-Meteo (https://open-meteo.com/). Nie wymaga klucza API ani rejestracji. Projekt został rozbudowany o prosty interfejs graficzny (Tkinter), obsługę prognozy na kilka dni oraz przykładowy skrypt w Node.js.

## Uruchomienie
1. Zainstaluj wymagane biblioteki:
1. Zainstaluj wymagane biblioteki Pythona:
```bash
pip install requests
pip install -r requirements.txt
```
2. Uruchom skrypt:
2. Aby uruchomić aplikację w trybie tekstowym:
```bash
python main.py
python main.py Warszawa -d 3
```
Możesz pominąć nazwę miasta, aby podać ją podczas działania programu.
3. (Opcjonalnie) uruchom prosty interfejs graficzny:
```bash
python gui.py
```
4. (Opcjonalnie) przykład w Node.js:
```bash
node weather.js Warszawa
```

## Jak to działa?
Expand All @@ -19,6 +28,9 @@ To prosta aplikacja w Pythonie, która pobiera i wyświetla aktualną pogodę dl
## Funkcjonalności
- Pobieranie aktualnej pogody dla wybranego miasta.
- Wyświetlanie temperatury, prędkości wiatru i podstawowych informacji.
- Prognoza na dowolną liczbę dni (parametr `-d`).
- Prosty interfejs graficzny (Tkinter).
- Dodatkowy skrypt `weather.js` pokazujący, jak pobrać dane w Node.js.
- Brak potrzeby rejestracji ani klucza API.

---
Expand Down
43 changes: 6 additions & 37 deletions gui.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,10 @@

import tkinter as tk
from tkinter import ttk, messagebox
from urllib.parse import quote
import requests
from PIL import Image, ImageTk
from PIL import Image, ImageTk, ImageDraw
import io

# Logika pobierania pogody (przeniesiona i dostosowana z main.py)
BASE_URL_FORECAST = "https://api.open-meteo.com/v1/forecast"

def get_lat_lon(city_name):
url = f"https://nominatim.openstreetmap.org/search?q={quote(city_name)}&format=json&limit=1"
try:
response = requests.get(url, headers={"User-Agent": "weather-app-gui"})
response.raise_for_status()
data = response.json()
if data:
return float(data[0]['lat']), float(data[0]['lon'])
return None, None
except requests.RequestException as e:
messagebox.showerror("Błąd", f"Błąd połączenia: {e}")
return None, None

def get_weather_data(lat, lon):
params = {
'latitude': lat,
'longitude': lon,
'current_weather': 'true',
}
try:
response = requests.get(BASE_URL_FORECAST, params=params)
response.raise_for_status()
return response.json()
except requests.RequestException as e:
messagebox.showerror("Błąd", f"Błąd pobierania danych pogody: {e}")
return None
from weather import get_lat_lon, get_current_weather

# Główna klasa aplikacji GUI
class WeatherApp(tk.Tk):
Expand Down Expand Up @@ -91,9 +61,11 @@ def fetch_weather(self, event=None):
messagebox.showerror("Błąd", f"Nie znaleziono miasta: {city}")
return

weather_data = get_weather_data(lat, lon)
if weather_data:
try:
weather_data = get_current_weather(lat, lon)
self.display_weather(city, weather_data)
except Exception as e:
messagebox.showerror("Błąd", f"Błąd pobierania danych pogody: {e}")

def display_weather(self, city, data):
current_weather = data.get('current_weather', {})
Expand Down Expand Up @@ -167,8 +139,5 @@ def create_rain_icon(self):


if __name__ == "__main__":
# Potrzebny import dla rysowania ikon
from PIL import ImageDraw

app = WeatherApp()
app.mainloop()
105 changes: 42 additions & 63 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,74 +1,53 @@
"""Command line weather application."""

import requests
from urllib.parse import quote
import argparse

BASE_URL = "https://api.open-meteo.com/v1/forecast"
from weather import get_lat_lon, get_current_weather, get_daily_forecast


def get_lat_lon(city_name):
"""
Pobiera szerokość i długość geograficzną miasta korzystając z Nominatim (OpenStreetMap).
"""
url = f"https://nominatim.openstreetmap.org/search?q={quote(city_name)}&format=json&limit=1"
try:
response = requests.get(url, headers={"User-Agent": "weather-app"})
response.raise_for_status()
data = response.json()
if data:
return float(data[0]['lat']), float(data[0]['lon'])
else:
print("Nie znaleziono miasta.")
return None, None
except requests.RequestException as e:
print(f"Błąd podczas pobierania współrzędnych: {e}")
return None, None

def get_weather(city_name):
"""
Pobiera dane pogodowe dla podanego miasta z Open-Meteo API.
"""
lat, lon = get_lat_lon(city_name)
if lat is None or lon is None:
return None
params = {
'latitude': lat,
'longitude': lon,
'current_weather': 'true',
}
try:
response = requests.get(BASE_URL, params=params)
response.raise_for_status()
data = response.json()
data['city'] = city_name
return data
except requests.RequestException as e:
print(f"Błąd podczas pobierania danych pogodowych: {e}")
return None


def display_weather(data):
"""
Wyświetla dane pogodowe w czytelny sposób.
"""
if data and data.get('current_weather'):
city = data.get('city', 'Nieznane miasto')
weather = data['current_weather']
temp = weather['temperature']
wind = weather['windspeed']
desc = "Brak opisu (Open-Meteo nie udostępnia opisu)"
print(f"\nPogoda w {city}:")
print(f"Temperatura: {temp}°C")
print(f"Opis: {desc}")
print(f"Wiatr: {wind} km/h")
else:
def display_current(city: str, data: dict):
"""Pretty print current weather information."""
if not data or "current_weather" not in data:
print("Nie udało się pobrać danych pogodowych.")
return
weather = data["current_weather"]
print(f"\nPogoda w {city}:")
print(f"Temperatura: {weather['temperature']}°C")
print(f"Wiatr: {weather['windspeed']} km/h")


def display_forecast(forecast: dict):
"""Display simple daily forecast."""
days = forecast.get("daily", {})
dates = days.get("time", [])
tmax = days.get("temperature_2m_max", [])
tmin = days.get("temperature_2m_min", [])
if not dates:
return
print("\nPrognoza:")
for date, mx, mn in zip(dates, tmax, tmin):
print(f"{date}: {mn}°C - {mx}°C")


def main():
print("Witaj w aplikacji pogodowej!")
city = input("Podaj nazwę miasta: ")
data = get_weather(city)
display_weather(data)
parser = argparse.ArgumentParser(description="Aplikacja pogodowa")
parser.add_argument("city", nargs="?", help="Nazwa miasta")
parser.add_argument("-d", "--days", type=int, default=0,
help="Liczba dni prognozy (0 = tylko bieżąca pogoda)")
args = parser.parse_args()

city = args.city or input("Podaj nazwę miasta: ")
lat, lon = get_lat_lon(city)
if lat is None or lon is None:
print("Nie znaleziono miasta.")
return

current = get_current_weather(lat, lon)
display_current(city, current)

if args.days > 0:
forecast = get_daily_forecast(lat, lon, args.days)
display_forecast(forecast)


if __name__ == "__main__":
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
requests
Pillow
58 changes: 58 additions & 0 deletions weather.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#!/usr/bin/env node
// Simple Node.js script to fetch current weather for a city using Open-Meteo
// Demonstrates using a different language to access the same API.

const https = require('https');

function getJson(url) {
return new Promise((resolve, reject) => {
https.get(url, {headers: {'User-Agent': 'weather-app-node'}}, res => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => {
try {
resolve(JSON.parse(data));
} catch (err) {
reject(err);
}
});
}).on('error', reject);
});
}

async function getLatLon(city) {
const url = `https://nominatim.openstreetmap.org/search?q=${encodeURIComponent(city)}&format=json&limit=1`;
const data = await getJson(url);
if (data && data.length > 0) {
return {lat: data[0].lat, lon: data[0].lon};
}
throw new Error('City not found');
}

async function getWeather(city) {
const {lat, lon} = await getLatLon(city);
const url = `https://api.open-meteo.com/v1/forecast?latitude=${lat}&longitude=${lon}&current_weather=true`;
const data = await getJson(url);
data.city = city;
return data;
}

async function main() {
const city = process.argv.slice(2).join(' ');
if (!city) {
console.log('Usage: node weather.js <city>');
process.exit(1);
}
try {
const weather = await getWeather(city);
if (weather.current_weather) {
console.log(`Weather in ${weather.city}:`);
console.log(`Temperature: ${weather.current_weather.temperature}°C`);
console.log(`Wind: ${weather.current_weather.windspeed} km/h`);
}
} catch (err) {
console.error('Error:', err.message);
}
}

main();
50 changes: 50 additions & 0 deletions weather.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""Shared weather utilities for the command line and GUI apps."""

import requests
from urllib.parse import quote

BASE_FORECAST_URL = "https://api.open-meteo.com/v1/forecast"


def get_lat_lon(city_name: str):
"""Return latitude and longitude for a given city using Nominatim."""
url = f"https://nominatim.openstreetmap.org/search?q={quote(city_name)}&format=json&limit=1"
try:
response = requests.get(url, headers={"User-Agent": "weather-app"})
response.raise_for_status()
data = response.json()
if data:
return float(data[0]["lat"]), float(data[0]["lon"])
except requests.RequestException:
pass
return None, None


def get_current_weather(lat: float, lon: float):
"""Fetch current weather data from Open-Meteo."""
params = {
"latitude": lat,
"longitude": lon,
"current_weather": "true",
}
response = requests.get(BASE_FORECAST_URL, params=params)
response.raise_for_status()
return response.json()


def get_daily_forecast(lat: float, lon: float, days: int = 3):
"""Fetch daily forecast for a given number of days."""
params = {
"latitude": lat,
"longitude": lon,
"timezone": "auto",
"daily": "temperature_2m_max,temperature_2m_min,weathercode",
}
response = requests.get(BASE_FORECAST_URL, params=params)
response.raise_for_status()
data = response.json()
if days > 0:
# Limit results to requested number of days if API returned more
for key in data.get("daily", {}):
data["daily"][key] = data["daily"][key][:days]
return data