Python Forum
PyQt6 Version of weather app
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
PyQt6 Version of weather app
#1
This is my attempt at a pyqt6 version of a weather app. It gets its data from forecast.weather.gov. I plan on adding an extended feature soon.

#! /usr/bin/env python3

from bs4 import BeautifulSoup as bs
import requests, json, re, sys
from time import strftime
from PyQt6.QtCore import (Qt, QTimer, QTime)
from PyQt6.QtGui import (QImage, QPixmap)
from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QGridLayout,
QVBoxLayout, QHBoxLayout, QLabel, QFrame, QPushButton)


class Weather:
    def __init__(self):
        # Get location - lat and long
        location = json.loads(requests.get('http://ipinfo.io/json').text)['loc']
        lat, lon = location.split(',')

        # Get weather page from forecast.weather.gov
        page = requests.get(f'https://forecast.weather.gov/MapClick.php?lat={lat}&lon={lon}')

        # Create the soup
        soup = bs(page.text, 'html.parser')

        # Create some dicts for storing data
        self.data = {}
        summary = {}
        current_conditions = {}

        # Find the header we want and store in the data dict
        self.data['header'] = f"{soup.find('h2', attrs={'class':'panel-title'}).text}"

        # Find current condition summary and data
        weather = soup.find('div', attrs={'id': 'current_conditions-summary'})
        summary['img'] = f"https://forecast.weather.gov/{weather.find('img')['src']}"
        summary['condition'] = weather.find('p', attrs={'class': 'myforecast-current'}).text
        summary['temp f'] = weather.find('p', attrs={'class': 'myforecast-current-lrg'}).text
        summary['temp c'] = weather.find('p', attrs={'class': 'myforecast-current-sm'}).text

        # Find detail data from soup
        table = soup.find('div', attrs={'id': 'current_conditions_detail'})

        # Find the detail header/left td in table and add to dict as keys
        for text in table.findAll('b'):
            current_conditions[text.text] = None

        # Find the data on the right td and add to current_conditions dict
        for key in current_conditions.keys():
            for text in table.findAll('tr'):

                # Using this to get rid of excessive white space in the last dict entry
                if key in text.text.strip():
                    text = re.sub(key, '', text.text.strip())
                    current_conditions[key] = text.replace('\n', '').strip()

        # Add everything to the data dict
        self.data['summary'] = summary
        self.data['details'] = current_conditions


class Window(QMainWindow):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setFixedSize(400,270)

        # Iniate the Weather class
        weather = Weather()
        self.summary = weather.data['summary']
        self.details = weather.data['details']

        self.setWindowTitle('PyQt6 Weather App')

        # Create main container
        container = QGridLayout()

        cbox = QHBoxLayout()

        # Create data container
        dgrid = QGridLayout()
        dgrid.setSpacing(1)
        dgrid.setContentsMargins(2, 2, 2, 2)
        dframe = QFrame()
        dframe.setFrameStyle(1)
        dframe.setFrameShadow(QFrame.Shadow.Sunken)
        dframe.setLayout(dgrid)

        # Create the header
        header = QLabel('PyQt6 Weather App')
        header.setAlignment(Qt.AlignmentFlag.AlignCenter)
        header.setStyleSheet('font-size: 18px; background-color: lightgray; padding: 5 3 5 3; \
        font-weight: bold; border: 1px solid gray; color:steelblue;')

        # Create local header
        self.loc_header = QLabel(f'Current Conditions at {weather.data["header"]}')
        self.loc_header.setStyleSheet('font-size: 12px; color: navy; background-color: lightgray; \
        padding: 5, 3, 5, 3; border: 1px solid gray; font-weight: bold;')

        # Get first init image
        img_url = self.summary['img']
        image = QImage()
        image.loadFromData(requests.get(img_url).content)

        # Create image label
        self.img_label = QLabel()
        self.img_label.setStyleSheet('padding: 3 3 3 3;')
        self.img_label.setPixmap(QPixmap(image))


        # Create detail labels
        i = 0
        self.myvlabels = []
        hlabels = []
        for key, value in self.details.items():
            self.myvlabels.append(value)
            hlabels.append(key)
            hlabels[i] = QLabel(f'<b>{key}</b>:')
            hlabels[i].setStyleSheet('border: 1px solid lightgray; padding: 0 0 0 8;')
            self.myvlabels[i] = QLabel(value)
            self.myvlabels[i].setStyleSheet('border: 1px solid lightgray; padding 0 0 0 0;')
            dgrid.addWidget(hlabels[i], i, 1, 1, 1)
            dgrid.addWidget(self.myvlabels[i], i, 2, 1, 1)
            i += 1

        # Create current conditions label
        text = f'<b>Currently</b>: {self.summary["condition"]} {self.summary["temp f"]} / {self.summary["temp c"]}'
        self.current_label = QLabel(text)
        self.current_label.setFrameStyle(1)
        self.current_label.setFrameShadow(QFrame.Shadow.Sunken)

        # Create a clock
        self.clock = QLabel(f'Current Time: <font color="navy">{strftime("%I:%M:%S %p")}</font>')
        self.clock.setFrameStyle(1)
        self.clock.setFrameShadow(QFrame.Shadow.Sunken)

        # Compact current data and clock
        cbox.addWidget(self.current_label)
        cbox.addWidget(self.clock)

        # Add data widget to data container
        dgrid.addWidget(self.img_label, 0, 0, len(self.details), 1)

        # Add widgets to main container grid
        container.addWidget(header, 0, 0, 1, 1, Qt.AlignmentFlag.AlignTop)
        container.addWidget(self.loc_header, 1, 0, 1, 1, Qt.AlignmentFlag.AlignTop)
        container.addWidget(dframe, 2, 0, 1, 1, Qt.AlignmentFlag.AlignTop)
        container.addLayout(cbox, 3, 0, 1, 1, Qt.AlignmentFlag.AlignTop)

        # Setup the clock timer
        clock_timer = QTimer(self)
        clock_timer.timeout.connect(self.clock_update)
        clock_timer.start(1000)

        # Setup the update timer
        update_timer = QTimer(self)
        update_timer.timeout.connect(self.update)
        update_timer.start(3000000)




        widget = QWidget()
        widget.setLayout(container)
        self.setCentralWidget(widget)

    def clock_update(self):
        self.clock.setText(f'<b>Current Time</b>: <font color="navy">{strftime("%I:%M:%S %p")}</font>')

    def update(self):
        # Iniate the Weather class
        weather = Weather()

        # Set some variables
        summary = weather.data['summary']
        details = weather.data['details']

        # Update the labels
        img_url = self.summary['img']
        image = QImage()
        image.loadFromData(requests.get(img_url).content)
        self.img_label.setPixmap(QPixmap(image))

        i = 0
        for val in details.values():
            self.myvlabels[i].setText(val)
            i += 1

        self.current_label.setText(f'<b>Currently</b>: {summary["condition"]} {summary["temp f"]} / {summary["temp c"]}')

def main():
    app = QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec())

if __name__ == '__main__':
    main()
I welcome all feedback.
The only dumb question, is one that doesn't get asked.
My Github
How to post code using bbtags


Reply


Messages In This Thread
PyQt6 Version of weather app - by menator01 - Jan-18-2022, 02:00 AM
RE: PyQt6 Version of weather app - by Axel_Erfurt - Jan-18-2022, 10:26 AM
RE: PyQt6 Version of weather app - by menator01 - Jan-18-2022, 03:43 PM
RE: PyQt6 Version of weather app - by menator01 - Jan-30-2022, 12:32 AM

Possibly Related Threads…
Thread Author Replies Views Last Post
  pyqt6 and random emoji menator01 0 2,401 Sep-19-2022, 06:46 PM
Last Post: menator01
  Basic PyQt6 Example of a timer menator01 0 4,749 May-27-2022, 05:24 PM
Last Post: menator01
  Tkinter Weather App menator01 1 2,040 Jan-16-2022, 11:23 PM
Last Post: menator01
  Meteostat - Historical Weather and Climate Data clampr 1 3,759 May-25-2021, 04:32 PM
Last Post: Gribouillis
  Talking Weather b4iknew 0 2,165 Jan-31-2019, 08:42 PM
Last Post: b4iknew
  SCIKItlearn -Naive Bayes Accuracy (Weather Data) usman 0 3,354 Nov-07-2018, 05:25 PM
Last Post: usman
  A weather program. mcmxl22 0 2,884 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