Python Forum
Version 0.02 of the PySide6 Weather App
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Version 0.02 of the PySide6 Weather App
#1
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 http://my-python.org to get the images or create your own.

data.py

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

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; margin-top:5px;')
        
    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()

Attached Files

Thumbnail(s)
   
I welcome all feedback.
The only dumb question, is one that doesn't get asked.
My Github
How to post code using bbtags
Download my project scripts


Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  PySide6 Movie Search menator01 0 1,126 Sep-03-2024, 02:32 AM
Last Post: menator01
  Tkinter weather app menator01 0 1,593 Jul-02-2024, 05:17 PM
Last Post: menator01
  PyQt6 Version of weather app menator01 3 4,918 Jan-30-2022, 12:32 AM
Last Post: menator01
  Tkinter Weather App menator01 1 2,775 Jan-16-2022, 11:23 PM
Last Post: menator01
  Meteostat - Historical Weather and Climate Data clampr 1 5,275 May-25-2021, 04:32 PM
Last Post: Gribouillis
  Talking Weather b4iknew 0 2,723 Jan-31-2019, 08:42 PM
Last Post: b4iknew
  SCIKItlearn -Naive Bayes Accuracy (Weather Data) usman 0 3,876 Nov-07-2018, 05:25 PM
Last Post: usman
  A weather program. mcmxl22 0 3,482 Jul-30-2018, 03:19 AM
Last Post: mcmxl22

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020