menator01
Gold Coder
This version should work world wide. May have some bugs when it comes to the wind direction arrow. I've tried testing it and the rain.
To try it create a virtual environment and use pip to run the requirements.txt to install needed modules.
You can download the zip file from my-python to get the images or create your own.
data.py
weather.py
To try it create a virtual environment and use pip to run the requirements.txt to install needed modules.
You can download the zip file from my-python to get the images or create your own.
data.py
Python:
import openmeteo_requests
import requests_cache
from retry_requests import retry
from datetime import datetime
import json
import requests
class Data:
''' Class makes the calls for data and does some formatting '''
def __init__(self):
# Setup the Open-Meteo API client with cache and retry on error
cache_session = requests_cache.CachedSession('.cache', expire_after = 3600)
retry_session = retry(cache_session, retries = 5, backoff_factor = 0.2)
openmeteo = openmeteo_requests.Client(session = retry_session)
location = json.loads(requests.get('http://ipinfo.io/json').text)
info = {
'country': location.get('country'),
'region': location.get('region'),
'city': location.get('city'),
'latitude': location.get('loc').split(',')[0],
'longitude': location.get('loc').split(',')[1]
}
# Make sure all required weather variables are listed here
# The order of variables in hourly or daily is important to assign them correctly below
url = "https://api.open-meteo.com/v1/forecast"
params = {
"latitude": info['latitude'],
"longitude": info['longitude'],
"current": ["temperature_2m", "relative_humidity_2m", "apparent_temperature", "precipitation", "cloud_cover",
"wind_speed_10m", "wind_direction_10m", "wind_gusts_10m"],
"temperature_unit": "fahrenheit",
"wind_speed_unit": "mph",
"precipitation_unit": "inch",
"timeformat": "unixtime"
}
responses = openmeteo.weather_api(url, params=params)
response = responses[0]
current = response.Current()
# Create dict and set wind directions
winddirect = {}
winddirect['N'] = [0,360]
winddirect['NNE'] = [n for n in range(1,45)]
winddirect['NE'] = [45]
winddirect['ENE'] = [n for n in range(46,90)]
winddirect['E'] = [90]
winddirect['ESE'] = [n for n in range(91,135)]
winddirect['SE'] = [135]
winddirect['SSE'] = [n for n in range(136,180)]
winddirect['S'] = [180]
winddirect['SSW'] = [n for n in range(181,225)]
winddirect['SW'] = [225]
winddirect['WSW'] = [n for n in range(226,270)]
winddirect['W'] = [270]
winddirect['WNW'] = [n for n in range(271,315)]
winddirect['NW'] = [315]
winddirect['NNW'] = [n for n in range(316,360)]
# Some variables for testing conditions
self.direct = round(current.Variables(6).Value())
precip = round(current.Variables(3).Value())
cloudy = round(current.Variables(4).Value())
# This loop sets text for wind direction
for key, value in winddirect.items():
if round(current.Variables(6).Value()) in value:
direct = key
# Dict for holding cloudy conditions
cloud = {}
cloud['clear skies'] = [n for n in range(0,5)]
cloud['partly cloudy'] = [n for n in range(5,51)]
cloud['mostly cloudy'] = [n for n in range(51, 86)]
cloud['cloudy'] = [n for n in range(86,101)]
# Compairing cloud dict with retreived data
for key, value in cloud.items():
if cloudy in value:
option = key
# Create dict for testing on image to show
faze = {}
faze['day'] = {
'clear skies':'sunny.png',
'partly cloudy':'day_cloudy.png',
'mostly cloudy': 'day_cloudy.png',
'cloudy': 'cloudy.png',
'rain': 'rain.png'
}
faze['night'] = {
'clear skies': 'moonlight.png',
'partly cloudy':'night_cloudy.png',
'mostly cloudy': 'night_cloudy.png',
'cloudy': 'cloudy.png',
'rain':'rain.png'
}
# Get the hour for testing if it's day or night
# Broke it down to 12 hour periods 1am 6pm is day
hour = datetime.now().strftime('%H')
if hour >= '01' and hour <= '18':
for key, value in faze['day'].items():
if key == option:
img = faze['day'][key]
if precip > 0:
option = ' rain'
img = faze['day']['rain']
else:
for key, value in faze['night'].items():
if key == option:
img = faze['night'][option]
if precip > 0:
img = faze['night']['rain']
option = ' rain'
# Create dict and set key value pairs
self.weather = {}
self.weather['location'] = ', '.join([info['country'], info['city'], info['region']])
self.weather['Date'] = datetime.now().strftime('%A %B %d, %Y')
self.weather['Time'] = datetime.now().strftime('%I:%M:%S %p')
self.weather['temp'] = f'{round(current.Variables(0).Value())}°F'
self.weather['humidity'] = f'{round(current.Variables(1).Value())}%'
self.weather['feels like'] = f'{round(current.Variables(2).Value())}°F'
self.weather['precipitation'] = f'{round(current.Variables(3).Value())}%'
self.weather['cloud cover'] = f'{round(current.Variables(4).Value())}%'
self.weather['wind speed'] = f'{round(current.Variables(5).Value())} mph'
self.weather['wind direction'] = direct
self.weather['wind gust'] = f'{round(current.Variables(7).Value())} mph'
self.weather['image'] = (option, img)
weather.py
Python:
from PySide6.QtWidgets import (QApplication, QMainWindow, QWidget, QGridLayout, QHBoxLayout,
QVBoxLayout,QLabel, QFrame, QGraphicsScene, QGraphicsView)
from PySide6.QtCore import Qt, QTimer
from PySide6.QtGui import QPixmap, QImage, QIcon, QTransform
from datetime import datetime
from data import Data
class Arrow:
''' Class creates the wind direction arrow '''
def __init__(self):
''' Set up Graphics screen and view '''
pixmap = QPixmap('images/arrow.png')
self.pixmap = pixmap.scaled(pixmap.width()/1.25, pixmap.height()/1.25)
self.scene = QGraphicsScene()
self.view = QGraphicsView(self.scene)
self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.view.setFrameStyle(0)
self.view.setFixedHeight(20)
self.view.setStyleSheet('padding-right: 50px; margin-left:-20px')
def viewarrow(self, direction=0, text=''):
self.item = self.scene.addPixmap(self.pixmap)
# Rotates the arrow
self.item.setRotation(direction)
self.item.setTransformOriginPoint(
self.item.boundingRect().center())
self.item.setTransformationMode(Qt.SmoothTransformation)
return self.view
class Window(QMainWindow):
def __init__(self):
super().__init__()
# image icon from https://www.flaticon.com
pixmap = QPixmap('images/weather.png')
appicon = QIcon(pixmap)
self.setWindowIcon(appicon)
self.setWindowTitle('Weather App')
self.setFixedSize(400,450)
# Create main container
container = QVBoxLayout()
widget = QWidget()
widget.setLayout(container)
self.setCentralWidget(widget)
self.show()
# Create the header
header = QLabel('PySide6 Weather')
header.setStyleSheet('background-color: #ffa500; color: #ffffff; font-size: 30px; \
font-weight: bold; font-family: cursive; padding: 10px;')
header.setAlignment(Qt.AlignmentFlag.AlignCenter)
# Add header to container
container.addWidget(header)
# Create content container
self.content = QGridLayout()
self.content.setSpacing(10)
frame = QFrame()
frame.setLayout(self.content)
frame.setFrameStyle(QFrame.StyledPanel | QFrame.Plain)
# Add content container to main container
container.addWidget(frame)
labels = ['location', 'date','time', 'temperature', 'humidity',
'feels like', 'precipitation', 'cloud cover',
'wind speed', 'wind direction', 'wind gust']
self.labels = []
for index, item in enumerate(labels):
label = QLabel(f'{item.title()}:')
label.setStyleSheet('font-weight:500; font-size: 16px;')
self.content.addWidget(label, index,0,1,1)
# self.content.addWidget(QLabel(), index, 1,1,1)
for index, item in enumerate(labels):
self.labels.append(QLabel())
self.labels[index].setStyleSheet('font-size: 16px;')
self.content.addWidget(self.labels[index], index, 1,1,1, Qt.AlignmentFlag.AlignLeft)
self.content.addWidget(QLabel(), index, 2,1,1)
# Setup an image label
self.img_label = QLabel()
self.img_label.setStyleSheet('padding-left: 80px;')
self.content.addWidget(self.img_label, 3,1,9,1, Qt.AlignmentFlag.AlignTop)
# Setup image text label
self.img_text = QLabel()
self.img_text.setStyleSheet('margin-left:40px;')
self.content.addWidget(self.img_text, 8,1,1,1, Qt.AlignmentFlag.AlignCenter)
# Create container for footer
footerframe = QGridLayout()
footerframe.setSpacing(0)
# Add footer container to main container
container.addLayout(footerframe)
# Create the logo image
img = QPixmap('images/my-python-logo.png')
img = img.scaled(40,20)
# Add image to label
logo = QLabel()
logo.setAlignment(Qt.AlignmentFlag.AlignCenter)
logo.setStyleSheet('background-color: #ffa500;padding:5px; margin-left: -5.5em;')
logo.setPixmap(img)
# Create logo text
label = QLabel('™ my-python©')
label.setAlignment(Qt.AlignmentFlag.AlignCenter)
label.setStyleSheet('padding:5px;margin-left: 3em; font-size: 18px;')
# Add logo image and text to footer container
footerframe.addWidget(logo, 0,1,1,1)
footerframe.addWidget(label,0,1,1,1)
class Controller:
def __init__(self, window, arrow):
self.window = window
self.arrow = arrow
self.update()
# Create a timer to update contents
self.timer = QTimer()
self.timer.setInterval(300000)
self.timer.timeout.connect(self.update)
self.timer.start()
self.clock_timer = QTimer()
self.clock_timer.setInterval(1000)
self.clock_timer.timeout.connect(self.clock)
self.clock_timer.start()
def clock(self):
now = datetime.now().strftime('%I:%M:%S %p')
self.window.labels[2].setText(now)
def update(self):
''' Method for updating window '''
# Intialize Data class
data = Data()
# Set index variable
index = 0
# Loop through the data dict and update label text
for key, val in data.weather.items():
if key != 'image':
self.window.labels[index].setText(str(val))
index += 1
if key == 'wind direction':
text = val
# Calls the Arror class and updates arror direction
self.window.content.addWidget(self.arrow.viewarrow(direction=data.direct, \
text=text), 9, 1,1,2, Qt.AlignmentFlag.AlignCenter)
# Sets the image label with correct image cloudy sunny, rain, etc
pixmap = QPixmap(f'images/{data.weather['image'][1]}')
pixmap = pixmap.scaled(120,120)
self.window.img_label.setPixmap(pixmap)
# Set the text under the image
self.window.img_text.setText(data.weather['image'][0].title())
if __name__ == '__main__':
app = QApplication([])
controller = Controller(Window(), Arrow())
app.exec()
Attachments
Last edited: