From 3d571844b8f826daf2688e5a6059bd7f6885d0b2 Mon Sep 17 00:00:00 2001 From: alessandro90 Date: Sun, 12 May 2019 11:56:11 +0200 Subject: [PATCH] Add logic to the forecast screen --- .gitignore | 1 + artemis.py | 43 +- artemis.ui | 1808 +++++++++++++++++++++++++---------------- constants.py | 1 + forecastdata.py | 3 - space_weather_data.py | 74 -- switchable_label.py | 24 +- threads.py | 73 +- weatherdata.py | 314 +++++++ 9 files changed, 1538 insertions(+), 803 deletions(-) delete mode 100644 forecastdata.py delete mode 100644 space_weather_data.py create mode 100644 weatherdata.py diff --git a/.gitignore b/.gitignore index 4a63335..4d08bb8 100644 --- a/.gitignore +++ b/.gitignore @@ -7,5 +7,6 @@ csv_info.txt pyinstaller_cmd.txt themes/.current_theme launch.bat +designer.bat *.sh .vscode/ diff --git a/artemis.py b/artemis.py index b7bb2fb..ee2c3cc 100644 --- a/artemis.py +++ b/artemis.py @@ -22,8 +22,7 @@ from PyQt5.QtCore import (QFileInfo, pyqtSlot,) from audio_player import AudioPlayer -from space_weather_data import SpaceWeatherData -from forecastdata import ForecastData +from weatherdata import SpaceWeatherData, ForecastData from download_window import DownloadWindow from switchable_label import SwitchableLabelsIterable from constants import (Constants, @@ -525,30 +524,10 @@ class Artemis(QMainWindow, Ui_MainWindow): self.forecast_info_btn.clicked.connect( lambda: webbrowser.open(Constants.SPACE_WEATHER_INFO) ) + self.forecast_data = ForecastData(self) self.update_forecast_bar.clicked.connect(self.start_update_forecast) self.update_forecast_bar.set_idle() - self.forecast_data = ForecastData() - self.today_forecast_labels = [] - self.today_p1_forecast_labels = [] - self.today_p2_forecast_labels = [] - self.all_forecast_labels = [] - flags = ['', 'p1_', 'p2_'] - for flag in flags: - title_lbl = getattr(self, "today_" + flag + "lbl") - title_lbl.setText("-") - for index in range(20): - label = getattr( - self, - "forecast_today_" + flag + str(index) + "_lbl" - ) - label.setText(Constants.UNKNOWN) - self.all_forecast_labels.append(label) - if flag == flags[0]: - self.today_forecast_labels.append(label) - if flag == flags[1]: - self.today_p1_forecast_labels.append(label) - if flag == flags[2]: - self.today_p2_forecast_labels.append(label) + self.forecast_data.update_complete.connect(self.update_forecast) # Final operations. @@ -558,7 +537,9 @@ class Artemis(QMainWindow, Ui_MainWindow): @pyqtSlot() def start_update_forecast(self): - pass + if not self.forecast_data.is_updating: + self.update_forecast_bar.set_updating() + self.forecast_data.update() @pyqtSlot() def start_update_space_weather(self): @@ -566,6 +547,16 @@ class Artemis(QMainWindow, Ui_MainWindow): self.update_now_bar.set_updating() self.space_weather_data.update() + @pyqtSlot(bool) + def update_forecast(self, status_ok): + self.update_forecast_bar.set_idle() + if status_ok: + self.forecast_data.update_all_labels() + elif not self.closing: + pop_up(self, title=Messages.BAD_DOWNLOAD, + text=Messages.BAD_DOWNLOAD_MSG).show() + self.forecast_data.remove_data() + @pyqtSlot(bool) def update_space_weather(self, status_ok): self.update_now_bar.set_idle() @@ -1421,6 +1412,8 @@ class Artemis(QMainWindow, Ui_MainWindow): self.download_window.close() if self.space_weather_data.is_updating: self.space_weather_data.shutdown_thread() + if self.forecast_data.is_updating: + self.forecast_data.shutdown_thread() super().closeEvent(event) diff --git a/artemis.ui b/artemis.ui index cd446a5..138febd 100644 --- a/artemis.ui +++ b/artemis.ui @@ -178,7 +178,7 @@ QTabWidget::Rounded - 3 + 0 true @@ -197,7 +197,7 @@ - Main + Signal @@ -4683,7 +4683,7 @@ www.qrg.globaltuners.com - 1 + 0 @@ -4781,8 +4781,7 @@ www.qrg.globaltuners.com - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + R0 @@ -4802,8 +4801,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + R1 @@ -4823,8 +4821,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + R2 @@ -4844,8 +4841,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + R3 @@ -4865,8 +4861,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + R4 @@ -4886,8 +4881,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + R5 @@ -4968,8 +4962,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + S0 @@ -4989,8 +4982,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + S1 @@ -5010,8 +5002,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + S2 @@ -5031,8 +5022,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + S3 @@ -5052,8 +5042,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + S4 @@ -5073,8 +5062,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + S5 @@ -5803,8 +5791,7 @@ STORM - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + G0 @@ -5824,8 +5811,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + G1 @@ -5845,8 +5831,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + G2 @@ -5866,8 +5851,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + G3 @@ -5887,8 +5871,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + G4 @@ -5908,8 +5891,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + G5 @@ -5944,8 +5926,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + G0 @@ -5965,8 +5946,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + G1 @@ -5986,8 +5966,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + G2 @@ -6007,8 +5986,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + G3 @@ -6028,8 +6006,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + G4 @@ -6049,8 +6026,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + G5 @@ -6904,38 +6880,14 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto Forecast - - - - TextLabel + + + + + 75 + true + - - Qt::AlignCenter - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - TextLabel @@ -6946,6 +6898,11 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto + + + 9 + + 21 - 00 @@ -6954,108 +6911,78 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + - - TextLabel + + + 75 + true + - - Qt::AlignCenter - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - 18 - 21 - - - 25 - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - 15 - 18 - - - 25 - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - 12 - 15 - - - 25 - - - - - TextLabel @@ -7066,86 +6993,12 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - TextLabel + + + 75 + true + - - Qt::AlignCenter - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - TextLabel @@ -7156,6 +7009,11 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto + + + 9 + + 03 - 06 @@ -7164,6 +7022,259 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 9 + + + + 09 - 12 + + + 25 + + + + + + + + 9 + false + + + + Major + + + 50 + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 9 + + + + 06 - 09 + + + 25 + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 9 + + + + 15 - 18 + + + 25 + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + @@ -7178,8 +7289,14 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - + + + + + 75 + true + + TextLabel @@ -7190,6 +7307,12 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto + + + 75 + true + + TextLabel @@ -7200,6 +7323,12 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto + + + 75 + true + + TextLabel @@ -7208,8 +7337,14 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - + + + + + 75 + true + + TextLabel @@ -7218,8 +7353,14 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - + + + + + 75 + true + + TextLabel @@ -7228,10 +7369,31 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - + + + + + 75 + true + + - 09 - 12 + TextLabel + + + Qt::AlignCenter + + + + + + + + 9 + + + + 12 - 15 25 @@ -7240,6 +7402,11 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto + + + 9 + + 00 - 03 @@ -7248,18 +7415,29 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - + + + + + 9 + + - 06 - 09 + 18 - 21 25 - - + + + + + 75 + true + + TextLabel @@ -7268,68 +7446,110 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - + + + + + 75 + true + + - Major + TextLabel + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 9 + false + + + + Minor 50 - - - - TextLabel + + + + + 75 + true + - - Qt::AlignCenter - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - TextLabel @@ -7340,6 +7560,12 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto + + + 75 + true + + TextLabel @@ -7352,7 +7578,8 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - 10 + 9 + false @@ -7363,197 +7590,14 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - - - TextLabel - - - Qt::AlignCenter - - - - - - - Major - - - 50 - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - Minor - - - 50 - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - Active - - - 50 - - - - - - - Active - - - 50 - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - Minor - - - 50 - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - - 10 - - - - Mid Lat. - - - 25 - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - 11 75 true - - Geomagnetic Act. - - - - - TextLabel @@ -7577,6 +7621,11 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto + + + 9 + + R1 - R2 @@ -7585,8 +7634,14 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - + + + + + 75 + true + + TextLabel @@ -7597,6 +7652,43 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 9 + + + + > R3 + + + 25 + + + + + + + + 75 + true + + TextLabel @@ -7619,8 +7711,14 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - + + + + + 75 + true + + TextLabel @@ -7629,7 +7727,356 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 11 + 75 + true + + + + Geomagnetic Act. + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 9 + false + + + + Minor + + + 50 + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 9 + false + + + + Mid Lat. + + + 25 + + + + + + + + 9 + false + + + + Major + + + 50 + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 9 + false + + + + Active + + + 50 + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 9 + false + + + + Active + + + 50 + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + + + + + + 9 + + + + Proton flare + + + 25 + + + + + + + + 11 + 75 + true + + + + Solar Radiation Storm + + + + + + + + 0 + 0 + + + + + 11 + 75 + true + + + + today + + + Qt::AlignCenter + + + + + + + + 11 + 75 + true + + + + Event Probabilities + + + + @@ -7642,16 +8089,67 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - - - - 0 - 0 - + + + + + 75 + true + - - Qt::Horizontal + + TextLabel + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter @@ -7701,22 +8199,14 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - + + - 11 75 true - - Solar Radiation Storm - - - - - TextLabel @@ -7725,18 +8215,42 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - + + + + + 0 + 0 + + + + Qt::Horizontal + + + + + + + + 9 + + - S1 or Greater + Class M flare 25 - - + + + + + 75 + true + + TextLabel @@ -7745,7 +8259,52 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + + @@ -7773,31 +8332,14 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - - - - 0 - 0 - - + + - 11 75 true - - today - - - Qt::AlignCenter - - - - - TextLabel @@ -7806,75 +8348,28 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - - - TextLabel - - - Qt::AlignCenter - - - - - + + - 11 - 75 - true + 9 - Event Probabilities - - - - - - - Class M flare + S1 or Greater 25 - - - - TextLabel - - - Qt::AlignCenter - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - - 0 - 0 - - - - Qt::Horizontal - - - + + + 9 + + Class X flare @@ -7883,48 +8378,14 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - - - Proton flare - - - 25 - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - TextLabel - - - Qt::AlignCenter - - - + + + 75 + true + + TextLabel @@ -7933,8 +8394,14 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - + + + + + 75 + true + + TextLabel @@ -7943,29 +8410,6 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - - - > R3 - - - 25 - - - - - - - - 0 - 0 - - - - Qt::Horizontal - - - diff --git a/constants.py b/constants.py index a4aab83..c8058a7 100644 --- a/constants.py +++ b/constants.py @@ -91,6 +91,7 @@ class Constants: RTL_SDL_LINK = "https://www.rtl-sdr.com/" UPDATING_STR = "Updating..." ACF_DOCS = "https://aresvalley.com/documentation/" + FORECAST_PROBABILITIES = "https://services.swpc.noaa.gov/text/sgarf.txt" SPACE_WEATHER_XRAY = "https://services.swpc.noaa.gov/text/goes-xray-flux-primary.txt" SPACE_WEATHER_PROT_EL = "https://services.swpc.noaa.gov/text/goes-particle-flux-primary.txt" SPACE_WEATHER_AK_INDEX = "https://services.swpc.noaa.gov/text/wwv.txt" diff --git a/forecastdata.py b/forecastdata.py deleted file mode 100644 index 5c1a0ed..0000000 --- a/forecastdata.py +++ /dev/null @@ -1,3 +0,0 @@ -class ForecastData: - def __init__(self): - pass diff --git a/space_weather_data.py b/space_weather_data.py deleted file mode 100644 index 7928ec0..0000000 --- a/space_weather_data.py +++ /dev/null @@ -1,74 +0,0 @@ -from PyQt5.QtGui import QPixmap -from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject -from threads import UpdateSpaceWeatherThread, ThreadStatus - - -class SpaceWeatherData(QObject): - update_complete = pyqtSignal(bool) - - def __init__(self): - super().__init__() - self.xray = '' - self.prot_el = '' - self.ak_index = '' - self.sgas = '' - self.geo_storm = '' - self.images = [ - QPixmap(), - QPixmap(), - QPixmap(), - QPixmap(), - QPixmap(), - QPixmap(), - QPixmap(), - QPixmap(), - QPixmap() - ] - self.__update_thread = UpdateSpaceWeatherThread(self) - self.__update_thread.finished.connect(self.__parse_and_emit_signal) - - @property - def is_updating(self): - return self.__update_thread.isRunning() - - @pyqtSlot() - def update(self): - self.__update_thread.start() - - def __parse_data(self): - double_split = lambda string: [i.split() for i in string.splitlines()] - self.xray = double_split(self.xray) - self.prot_el = double_split(self.prot_el) - self.ak_index = double_split(self.ak_index) - self.sgas = double_split(self.sgas) - self.geo_storm = double_split(self.geo_storm) - - def remove_data(self): - self.xray = '' - self.prot_el = '' - self.ak_index = '' - self.sgas = '' - self.geo_storm = '' - self.images = [ - QPixmap(), - QPixmap(), - QPixmap(), - QPixmap(), - QPixmap(), - QPixmap(), - QPixmap(), - QPixmap(), - QPixmap() - ] - - @pyqtSlot() - def __parse_and_emit_signal(self): - status_ok = False - if self.__update_thread.status is ThreadStatus.OK: - status_ok = True - self.__parse_data() - self.update_complete.emit(status_ok) - - def shutdown_thread(self): - self.__update_thread.terminate() - self.__update_thread.wait() diff --git a/switchable_label.py b/switchable_label.py index f853295..69773d0 100644 --- a/switchable_label.py +++ b/switchable_label.py @@ -6,6 +6,7 @@ class _BaseSwitchableLabel(QLabel): def __init__(self, parent=None): super().__init__(parent) self.is_on = False + self.level = 0 def switch_on(self): self.is_on = True @@ -44,12 +45,17 @@ class SingleColorSwitchableLabel(_BaseSwitchableLabel): self.active_color = ForecastColors.WARNING_COLOR def switch_on(self): - super().switch_on() - self.setStyleSheet(f"background-color: {self.active_color};") + if self.level >= 30: + super().switch_on() + self.setStyleSheet(f"color: {self.active_color}" + # f"""background-color: {self.active_color}; + # color: #000000;""" + ) def switch_off(self): super().switch_off() - self.setStyleSheet("background-color: transparent;") + # self.setStyleSheet("""background-color: transparent;""") + self.setStyleSheet("") class MultiColorSwitchableLabel(_BaseSwitchableLabel): @@ -64,18 +70,20 @@ class MultiColorSwitchableLabel(_BaseSwitchableLabel): def __init__(self, parent=None): super().__init__(parent) - self.level = 0 def switch_on(self): if 5 <= self.level <= 9: super().switch_on() - self.setStyleSheet(f""" - background-color: {self.LEVEL_COLORS[self.level]}; - """) + self.setStyleSheet(f"color: {self.LEVEL_COLORS[self.level]}" + # f"""background-color: {self.LEVEL_COLORS[self.level]}; + # color: #000000; + # """ + ) def switch_off(self): super().switch_off() - self.setStyleSheet("background-color: transparent;") + # self.setStyleSheet("background-color: transparent;") + self.setStyleSheet("") class SwitchableLabelsIterable: diff --git a/threads.py b/threads.py index 17c1027..fc928f3 100644 --- a/threads.py +++ b/threads.py @@ -19,7 +19,7 @@ class ThreadStatus(Enum): UNDEFINED = auto() -class _BaseDownloadThread(QThread): +class BaseDownloadThread(QThread): def __init__(self, parent=None): super().__init__(parent) self.status = ThreadStatus.UNDEFINED @@ -29,7 +29,7 @@ class _BaseDownloadThread(QThread): self.wait() -class DownloadThread(_BaseDownloadThread): +class DownloadThread(BaseDownloadThread): def __init__(self): super().__init__() self.reason = 0 @@ -65,7 +65,13 @@ class DownloadThread(_BaseDownloadThread): self.status = ThreadStatus.OK -class UpdateSpaceWeatherThread(_BaseDownloadThread): +class _AsyncDownloader: + async def _download_resource(self, session, link): + resp = await session.get(link) + return await resp.read() + + +class UpdateSpaceWeatherThread(BaseDownloadThread, _AsyncDownloader): __properties = ("xray", "prot_el", "ak_index", "sgas", "geo_storm") @@ -73,20 +79,16 @@ class UpdateSpaceWeatherThread(_BaseDownloadThread): super().__init__() self.__space_weather_data = space_weather_data - async def __download_resource(self, session, link): - resp = await session.get(link) - return await resp.read() - async def __download_property(self, session, property_name): link = getattr(Constants, "SPACE_WEATHER_" + property_name.upper()) - data = await self.__download_resource(session, link) + data = await self._download_resource(session, link) setattr(self.__space_weather_data, property_name, str(data, 'utf-8')) async def __download_image(self, session, n): - im = await self.__download_resource(session, Constants.SPACE_WEATHER_IMGS[n]) + im = await self._download_resource(session, Constants.SPACE_WEATHER_IMGS[n]) self.__space_weather_data.images[n].loadFromData(im) - async def __download_resources(self, *links): + async def _download_resources(self): session = aiohttp.ClientSession() try: t = [] @@ -111,4 +113,53 @@ class UpdateSpaceWeatherThread(_BaseDownloadThread): def run(self): self.status = ThreadStatus.UNDEFINED - asyncio.run(self.__download_resources()) + asyncio.run(self._download_resources()) + + +class UpdateForecastThread(BaseDownloadThread, _AsyncDownloader): + + class _PropertyName(Enum): + FORECAST = auto() + PROBABILITIES = auto() + + def __init__(self, parent): + super().__init__() + self.parent = parent + + async def __download_property(self, session, link, prop_name): + resp = await self._download_resource(session, link) + resp = str(resp, 'utf-8') + if prop_name is self._PropertyName.FORECAST: + self.parent.forecast = resp + if prop_name is self._PropertyName.PROBABILITIES: + self.parent.probabilities = resp + + async def _download_resources(self): + session = aiohttp.ClientSession() + try: + await asyncio.gather( + asyncio.create_task( + self.__download_property( + session, + Constants.SPACE_WEATHER_GEO_STORM, + self._PropertyName.FORECAST + ) + ), + asyncio.create_task( + self.__download_property( + session, + Constants.FORECAST_PROBABILITIES, + self._PropertyName.PROBABILITIES + ) + ) + ) + except Exception: + self.status = ThreadStatus.UNKNOWN_ERR + else: + self.status = ThreadStatus.OK + finally: + await session.close() + + def run(self): + self.status = ThreadStatus.UNDEFINED + asyncio.run(self._download_resources()) diff --git a/weatherdata.py b/weatherdata.py new file mode 100644 index 0000000..90d6d35 --- /dev/null +++ b/weatherdata.py @@ -0,0 +1,314 @@ +import re +from PyQt5.QtGui import QPixmap +from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject +from threads import (BaseDownloadThread, + UpdateSpaceWeatherThread, + ThreadStatus, + UpdateForecastThread) +from constants import Constants +from switchable_label import MultiColorSwitchableLabel + + +class _BaseWeatherData(QObject): + update_complete = pyqtSignal(bool) + + def __init__(self): + super().__init__() + self._update_thread = BaseDownloadThread() + + @property + def is_updating(self): + return self._update_thread.isRunning() + + def update(self): + self._update_thread.start() + + def _parse_data(self): + pass + + @pyqtSlot() + def _parse_and_emit_signal(self): + status_ok = False + if self._update_thread.status is ThreadStatus.OK: + status_ok = True + self._parse_data() + self.update_complete.emit(status_ok) + + def _double_split(self, string): + return [i.split() for i in string.splitlines()] + + def shutdown_thread(self): + self._update_thread.terminate() + self._update_thread.wait() + + +class SpaceWeatherData(_BaseWeatherData): + def __init__(self): + super().__init__() + self.xray = '' + self.prot_el = '' + self.ak_index = '' + self.sgas = '' + self.geo_storm = '' + self.images = [ + QPixmap(), + QPixmap(), + QPixmap(), + QPixmap(), + QPixmap(), + QPixmap(), + QPixmap(), + QPixmap(), + QPixmap() + ] + self._update_thread = UpdateSpaceWeatherThread(self) + self._update_thread.finished.connect(self._parse_and_emit_signal) + + def _parse_data(self): + self.xray = self._double_split(self.xray) + self.prot_el = self._double_split(self.prot_el) + self.ak_index = self._double_split(self.ak_index) + self.sgas = self._double_split(self.sgas) + self.geo_storm = self._double_split(self.geo_storm) + + def remove_data(self): + self.xray = '' + self.prot_el = '' + self.ak_index = '' + self.sgas = '' + self.geo_storm = '' + self.images = [ + QPixmap(), + QPixmap(), + QPixmap(), + QPixmap(), + QPixmap(), + QPixmap(), + QPixmap(), + QPixmap(), + QPixmap() + ] + + +class ForecastData(_BaseWeatherData): + + ROW_KEYWORDS = { + "solar_row": "S1 or greater", + "event_row": "III. Event probabilities", + "rb_now_row": "R1-R2", + "ga_now_row": "Geomagnetic Activity Probabilities", + "kp_index_row": "NOAA Kp index breakdown" + } + + def __init__(self, parent): + super().__init__() + self.forecast = '' + self.probabilities = '' + self.labels_table = [] + self.solar_row = None + self.event_row = None + self.rb_now_row = None + self.ga_now_row = None + self.kp_index_row = None + self._update_thread = UpdateForecastThread(self) + self._update_thread.finished.connect(self._parse_and_emit_signal) + self.today_lbl = parent.today_lbl + self.today_p1_lbl = parent.today_p1_lbl + self.today_p2_lbl = parent.today_p2_lbl + self.__today_lbls = [] + self.__today_p1_lbls = [] + self.__today_p2_lbls = [] + self.__all_lbls = [] + flags = ['', 'p1_', 'p2_'] + for flag in flags: + title_lbl = getattr(self, "today_" + flag + "lbl") + title_lbl.setText("-") + for index in range(20): + label = getattr( + parent, + "forecast_today_" + flag + str(index) + "_lbl" + ) + label.setText(Constants.UNKNOWN) + if flag == flags[0]: + self.__today_lbls.append(label) + if flag == flags[1]: + self.__today_p1_lbls.append(label) + if flag == flags[2]: + self.__today_p2_lbls.append(label) + + self.__all_lbls = [ + self.__today_lbls, + self.__today_p1_lbls, + self.__today_p2_lbls + ] + + def _parse_data(self): + self.forecast = self.forecast.splitlines() + # Remove possible '(G\d)' from the kp_index table + self.probabilities = re.sub('(G\d)', lambda obj: '', self.probabilities) + self.probabilities = self.probabilities.splitlines() + + def __split_lists(self): + self.forecast = [i.split() for i in self.forecast] + self.probabilities = [i.split() for i in self.probabilities] + + def __find_row_with(self, data, text): + for i, row in enumerate(data): + if text in row: + return i + return None + + def __get_rows(self): + self.solar_row = self.__find_row_with( + self.forecast, + self.ROW_KEYWORDS["solar_row"] + ) + self.event_row = self.__find_row_with( + self.probabilities, + self.ROW_KEYWORDS["event_row"] + ) + self.rb_now_row = self.__find_row_with( + self.forecast, + self.ROW_KEYWORDS["rb_now_row"] + ) + self.ga_now_row = self.__find_row_with( + self.probabilities, + self.ROW_KEYWORDS["ga_now_row"] + ) + self.kp_index_row = self.__find_row_with( + self.forecast, + self.ROW_KEYWORDS["kp_index_row"] + ) + + is_none = lambda x: x is None + if any([ + is_none(self.solar_row), + is_none(self.event_row), + is_none(self.rb_now_row), + is_none(self.ga_now_row), + is_none(self.kp_index_row) + ]): + raise Exception + + def __set_dates(self): + month = self.forecast[self.solar_row - 1][0] + today = self.forecast[self.solar_row - 1][1] + today_p1 = self.forecast[self.solar_row - 1][3] + today_p2 = self.forecast[self.solar_row - 1][5] + self.today_lbl.setText(month + ' ' + today) + self.today_p1_lbl.setText(month + ' ' + today_p1) + self.today_p2_lbl.setText(month + ' ' + today_p2) + + def __make_labels_table(self): + get_first_split = lambda x: x.split("/")[0] + get_second_split = lambda x: x.split("/")[1] + get_third_split = lambda x: x.split("/")[2] + self.labels_table = [ + [ + [self.forecast, self.solar_row, 3, None], + [self.probabilities, self.event_row + 1, 2, get_first_split], + [self.probabilities, self.event_row + 2, 2, get_first_split], + [self.probabilities, self.event_row + 3, 1, get_first_split], + [self.forecast, self.rb_now_row, 1, None], + [self.forecast, self.rb_now_row + 1, 3, None], + [self.probabilities, self.ga_now_row + 2, 1, get_first_split], + [self.probabilities, self.ga_now_row + 3, 2, get_first_split], + [self.probabilities, self.ga_now_row + 4, 2, get_first_split], + [self.probabilities, self.ga_now_row + 6, 1, get_first_split], + [self.probabilities, self.ga_now_row + 7, 2, get_first_split], + [self.probabilities, self.ga_now_row + 8, 2, get_first_split], + [self.forecast, self.kp_index_row + 3, 1, None], + [self.forecast, self.kp_index_row + 4, 1, None], + [self.forecast, self.kp_index_row + 5, 1, None], + [self.forecast, self.kp_index_row + 6, 1, None], + [self.forecast, self.kp_index_row + 7, 1, None], + [self.forecast, self.kp_index_row + 8, 1, None], + [self.forecast, self.kp_index_row + 9, 1, None], + [self.forecast, self.kp_index_row + 10, 1, None] + ], + [ + [self.forecast, self.solar_row, 4, None], + [self.probabilities, self.event_row + 1, 2, get_second_split], + [self.probabilities, self.event_row + 2, 2, get_second_split], + [self.probabilities, self.event_row + 3, 1, get_second_split], + [self.forecast, self.rb_now_row, 2, None], + [self.forecast, self.rb_now_row + 1, 4, None], + [self.probabilities, self.ga_now_row + 2, 1, get_second_split], + [self.probabilities, self.ga_now_row + 3, 2, get_second_split], + [self.probabilities, self.ga_now_row + 4, 2, get_second_split], + [self.probabilities, self.ga_now_row + 6, 1, get_second_split], + [self.probabilities, self.ga_now_row + 7, 2, get_second_split], + [self.probabilities, self.ga_now_row + 8, 2, get_second_split], + [self.forecast, self.kp_index_row + 3, 2, None], + [self.forecast, self.kp_index_row + 4, 2, None], + [self.forecast, self.kp_index_row + 5, 2, None], + [self.forecast, self.kp_index_row + 6, 2, None], + [self.forecast, self.kp_index_row + 7, 2, None], + [self.forecast, self.kp_index_row + 8, 2, None], + [self.forecast, self.kp_index_row + 9, 2, None], + [self.forecast, self.kp_index_row + 10, 2, None] + ], + [ + [self.forecast, self.solar_row, 5, None], + [self.probabilities, self.event_row + 1, 2, get_third_split], + [self.probabilities, self.event_row + 2, 2, get_third_split], + [self.probabilities, self.event_row + 3, 1, get_third_split], + [self.forecast, self.rb_now_row, 3, None], + [self.forecast, self.rb_now_row + 1, 5, None], + [self.probabilities, self.ga_now_row + 2, 1, get_third_split], + [self.probabilities, self.ga_now_row + 3, 2, get_third_split], + [self.probabilities, self.ga_now_row + 4, 2, get_third_split], + [self.probabilities, self.ga_now_row + 6, 1, get_third_split], + [self.probabilities, self.ga_now_row + 7, 2, get_third_split], + [self.probabilities, self.ga_now_row + 8, 2, get_third_split], + [self.forecast, self.kp_index_row + 3, 3, None], + [self.forecast, self.kp_index_row + 4, 3, None], + [self.forecast, self.kp_index_row + 5, 3, None], + [self.forecast, self.kp_index_row + 6, 3, None], + [self.forecast, self.kp_index_row + 7, 3, None], + [self.forecast, self.kp_index_row + 8, 3, None], + [self.forecast, self.kp_index_row + 9, 3, None], + [self.forecast, self.kp_index_row + 10, 3, None] + ] + ] + + def __get_lbl_value(self, data, row, col, f = None): + val = data[row][col] + if f is not None: + val = f(val) + val = val.lstrip('0').rstrip('%') + return val + + def __is_integer(self, s): + try: + int(s) + except Exception: + return False + else: + return True + + def __set_labels_values(self): + for lbl_list, table in zip(self.__all_lbls, self.labels_table): + for lbl, row in zip(lbl_list, table): + lbl.switch_off() + value = self.__get_lbl_value(*row) + if self.__is_integer(value): + lbl.level = int(value) + if not isinstance(lbl, MultiColorSwitchableLabel): + value += '%' + lbl.setText(value) + lbl.switch_on() + + def update_all_labels(self): + try: + self.__get_rows() + self.__split_lists() + self.__make_labels_table() + self.__set_dates() + self.__set_labels_values() + except Exception: + pass + + def remove_data(self): + self.forecast = '' + self.probabilities = ''