diff --git a/pb_tool.cfg b/pb_tool.cfg index fb8f230..5662690 100644 --- a/pb_tool.cfg +++ b/pb_tool.cfg @@ -48,7 +48,7 @@ plugin_path:/home/patrick/.local/share/QGIS/QGIS3/profiles/default/python/plugin [files] # Python files that should be deployed with the plugin -python_files: __init__.py pegelonline.py pegelonline_dockwidget.py po_runner.py poGraph2.py +python_files: __init__.py pegelonline.py pegelonline_dockwidget.py po_runner.py # The main dialog file that is loaded (not compiled) main_dialog: pegelonline_dockwidget_base.ui diff --git a/pegelonline_dockwidget_base.ui b/pegelonline_dockwidget_base.ui index 1936b0b..eb536be 100644 --- a/pegelonline_dockwidget_base.ui +++ b/pegelonline_dockwidget_base.ui @@ -6,8 +6,8 @@ 0 0 - 290 - 676 + 288 + 660 @@ -39,65 +39,61 @@ Optionen: - + - + - - - - - Name - - - - - - - Nummer - - - - - - - Betreiber - - - - - - - Zeitstempel - - - - + + + Name + + - - - - - Aktueller Wert - - - - - - - MNW, MHW - - - - - - - NSW, HSW - - - - + + + Nummer + + + + + + + Organisation + + + + + + + Zeitstempel + + + + + + + + + + + Aktueller Wert + + + + + + + MNW, MHW + + + + + + + NSW, HSW + + @@ -168,7 +164,7 @@ - Betreiber + Organisation @@ -199,35 +195,137 @@ - + Pegelverlauf: - + + + + 0 + 0 + + + + + 50 + 0 + + Station: - + + + + 0 + 0 + + + + + + + + 0 + 0 + + + + + 80 + 0 + + + + Neu Laden + + + + + + + + + + 0 + 0 + + + + + 50 + 0 + + Tage - + + + + 0 + 0 + + + + + 50 + 0 + + + + 1 + + + 30 + + + 14 + + + + + + + + 0 + 0 + + + + + 80 + 0 + + + + Anzeigen + + + + + + Bitte wählen... + + + diff --git a/poGraph2.py b/poGraph2.py deleted file mode 100644 index 65034ff..0000000 --- a/poGraph2.py +++ /dev/null @@ -1,117 +0,0 @@ -import ctypes -from urllib.parse import quote - -from PyQt5 import QtCore, QtGui -from PyQt5 import QtWidgets - -from .pomodules import poBaseURL -from .pomodules.urlreader import UrlReader - - -class PoGraphDisplay(QtWidgets.QWidget): - - def __init__(self, parent=None): - QtWidgets.QWidget.__init__(self, parent) - self.setupUi(self) - - # Layer - self.layer = None - - def setupUi(self, poGraphDisplay): - """Definition der Benutzeroberflaeche des Wasserstanddiagramms mit den dazugehoerigen Funktionen.""" - - # uebergeordnetes Layout - self.verticalLayout = QtWidgets.QVBoxLayout(poGraphDisplay) - - # Erste Zeile --- - - self.horizontalLayout = QtWidgets.QHBoxLayout() - - # Label Station - self.lbStation = QtWidgets.QLabel() - self.lbStation.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter) - self.horizontalLayout.addWidget(self.lbStation) - self.lbStation.setText("Geben Sie hier eine Station ein:") - - # ComboBox Stations - self.comboBox = QtWidgets.QComboBox() - self.comboBox.setEditable(True) - self.horizontalLayout.addWidget(self.comboBox) - - # Label Tage - self.lbTage = QtWidgets.QLabel() - self.lbTage.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter) - self.lbTage.setText("Tage") - self.horizontalLayout.addWidget(self.lbTage) - - # SpinBox Tage - self.sbTage = QtWidgets.QSpinBox() - self.sbTage.setMinimum(5) - self.sbTage.setMaximum(30) - self.sbTage.setProperty("value", 14) - self.horizontalLayout.addWidget(self.sbTage) - - # PushButton Laden - self.pbLaden = QtWidgets.QPushButton() - self.pbLaden.setObjectName("pbLaden") - self.pbLaden.setText("Laden") - self.horizontalLayout.addWidget(self.pbLaden) - - # Signal Slots - self.pbLaden.clicked.connect(self.doPbLaden) - self.verticalLayout.addLayout(self.horizontalLayout) - - # Zweite Zeile --- - - # Label fuer den Graphen - self.lbGraph = QtWidgets.QLabel() - self.lbGraph.setText("") - self.lbGraph.setObjectName("lbGraph") - self.verticalLayout.addWidget(self.lbGraph) - - # Quellenhinweis - self.lbDatenquelle = QtWidgets.QLabel() - self.lbDatenquelle.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignLeading | QtCore.Qt.AlignVCenter) - self.lbDatenquelle.setText("Die Daten werden von 'pegelonline.wsv.de' zur Verfügung gestellt.") - self.verticalLayout.addWidget(self.lbDatenquelle) - - # Dritte Zeile --- - - spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.verticalLayout.addItem(spacerItem) - - def doLoadGraph(self): - """Laedt die Stationsdaten anhand der vom Nutzer eingegebenen Daten.""" - - # Anzahl der Tage in der SpinBox - days = self.getCurrentDays() - - # Stationsname aus der ComboBox - station = quote(self.getCurrentStation()) - url = poBaseURL + "/stations/%s/W/measurements.png?start=P%dD" % (station, days) - ur = UrlReader(url) - self.img_data = ur.getDataResponse() - - if ur.code > 299: - AlertBox = ctypes.windll.user32.MessageBoxW - AlertBox(None, "Beim Laden der Daten ist ein Fehler aufgetreten.", "Fehler", 0) - - else: - # Grafik einsetzen - pixmap = QtGui.QPixmap() - pixmap.loadFromData(self.img_data) - self.lbGraph.clear() - self.lbGraph.setPixmap(pixmap) - self.lbGraph.resize(pixmap.width(), pixmap.height()) - - def doPbLaden(self): - """Laedt den Graphen der ausgewaehlten Station.""" - - if self.layer is None: - self.doLoadGraph() - - def getCurrentDays(self): - return self.sbTage.value() - - def getCurrentStation(self): - return self.comboBox.currentText() diff --git a/po_runner.py b/po_runner.py index e8be14d..a291b7b 100644 --- a/po_runner.py +++ b/po_runner.py @@ -1,11 +1,14 @@ import os.path from typing import Callable +from PyQt5 import QtGui from qgis._core import QgsVectorLayer, QgsProject, QgsLayerTreeLayer, QgsPalLayerSettings, QgsVectorLayerSimpleLabeling from .pegelonline_dockwidget import PegelonlineDockWidget -from .pomodules.poqgscurrentw import PoQgsCurrentW -from .pomodules.poqgsstations import PoQgsStations +from .pomodules.po_history import PoHistory +from .pomodules.po_stations import PoStations +from .pomodules.po_stations_qgs import PoQgsStations +from .pomodules.po_waterlevels_qgs import PoQgsCurrentW INFIX = ", ' - ', " @@ -27,16 +30,12 @@ class PoRunner(object): self.connect_basemap_signals() self.connect_stations_signals() self.connect_waterlevels_signals() + self.connect_history_signals() + + self._historyLoadStations() # basemap ----------------------------------------------------------------- - def disconnectStations(self): - print("disconnectStations") - self.stations = None - self.ui.cbStationsVisible.setChecked(False) - - # basemap signals --------------------------------------------------------- - def _basemapCreate(self, path, name, disconnect: Callable[[], None]) -> None | QgsVectorLayer: print("_basemapCreate: %s" % (name,)) path = os.path.join(self.local_dir, "basemap", path) @@ -59,6 +58,8 @@ class PoRunner(object): return basemap + # basemap signals --------------------------------------------------------- + def connect_basemap_signals(self): print("connect_basemap_signals") self.ui.cbBasemapLines.toggled.connect(self.cbBasemapLinesToggled) @@ -98,28 +99,6 @@ class PoRunner(object): # stations ---------------------------------------------------------------- - # noinspection DuplicatedCode - def _stationsUpdateLabeling(self): - print("_stationsUpdateLabeling") - if self.stations is None: - return - - fields = [] - if self.ui.cbStationsName.isChecked(): - fields.append("shortname") - if self.ui.cbStationsNumber.isChecked(): - fields.append("number") - if self.ui.cbStationsAgency.isChecked(): - fields.append("agency") - if self.ui.cbStationsKm.isChecked(): - fields.append("km") - if self.ui.cbStationsWater.isChecked(): - fields.append("water") - - self._layerUpdateLabeling(self.stations, fields) - - # stations signals -------------------------------------------------------- - def connect_stations_signals(self): print("connect_stations_signals") # noinspection DuplicatedCode @@ -169,31 +148,32 @@ class PoRunner(object): print("cbStationsWaterToggled: %s" % (checked,)) self._stationsUpdateLabeling() - # waterlevels ------------------------------------------------------------- + def disconnectStations(self): + print("disconnectStations") + self.stations = None + self.ui.cbStationsVisible.setChecked(False) # noinspection DuplicatedCode - def _waterlevelsUpdateLabeling(self): - if self.waterlevels is None: + def _stationsUpdateLabeling(self): + print("_stationsUpdateLabeling") + if self.stations is None: return fields = [] - if self.ui.cbWaterlevelsName.isChecked(): + if self.ui.cbStationsName.isChecked(): fields.append("shortname") - if self.ui.cbWaterlevelsNumber.isChecked(): + if self.ui.cbStationsNumber.isChecked(): fields.append("number") - if self.ui.cbWaterlevelsAgency.isChecked(): + if self.ui.cbStationsAgency.isChecked(): fields.append("agency") - if self.ui.cbWaterlevelsTimestamp.isChecked(): - fields.append("timestamp") - if self.ui.cbWaterlevelsValue.isChecked(): - fields.append("value") - if self.ui.cbWaterlevelsMean.isChecked(): - fields.append("stateMnwMhw") - if self.ui.cbWaterlevelsAbsolute.isChecked(): - fields.append("stateNswHsw") - self._layerUpdateLabeling(self.waterlevels, fields) + if self.ui.cbStationsKm.isChecked(): + fields.append("km") + if self.ui.cbStationsWater.isChecked(): + fields.append("water") - # waterlevels signals ----------------------------------------------------- + self._layerUpdateLabeling(self.stations, fields) + + # waterlevels ------------------------------------------------------------- def connect_waterlevels_signals(self): print("connect_waterlevels_signals") @@ -261,6 +241,28 @@ class PoRunner(object): self.waterlevels = None self.ui.cbWaterlevelsVisible.setChecked(False) + # noinspection DuplicatedCode + def _waterlevelsUpdateLabeling(self): + if self.waterlevels is None: + return + + fields = [] + if self.ui.cbWaterlevelsName.isChecked(): + fields.append("shortname") + if self.ui.cbWaterlevelsNumber.isChecked(): + fields.append("number") + if self.ui.cbWaterlevelsAgency.isChecked(): + fields.append("agency") + if self.ui.cbWaterlevelsTimestamp.isChecked(): + fields.append("timestamp") + if self.ui.cbWaterlevelsValue.isChecked(): + fields.append("value") + if self.ui.cbWaterlevelsMean.isChecked(): + fields.append("stateMnwMhw") + if self.ui.cbWaterlevelsAbsolute.isChecked(): + fields.append("stateNswHsw") + self._layerUpdateLabeling(self.waterlevels, fields) + # layers ------------------------------------------------------------------ def _layerSetVisible(self, basemap: QgsVectorLayer, visible): @@ -338,3 +340,81 @@ class PoRunner(object): layer.triggerRepaint() else: self.iface.mapCanvas().refresh() + + # history signals --------------------------------------------------------- + + def connect_history_signals(self): + self.ui.slHistoryStation.currentTextChanged.connect(self.slHistoryStationChanged) + self.ui.btnHistoryStationsRefresh.clicked.connect(self.btnHistoryStationsRefreshClicked) + self.ui.inHistoryDays.valueChanged.connect(self.inHistoryDaysChanged) + self.ui.btnHistoryGo.clicked.connect(self._historyLoadGraph) + + def btnHistoryStationsRefreshClicked(self): + print("btnHistoryStationsRefreshClicked") + self._historyLoadStations() + + def slHistoryStationChanged(self): + print("slHistoryStationChanged: %s" % (self.ui.slHistoryStation.currentText(),)) + self._historyLoadGraph() + + def inHistoryDaysChanged(self): + print("inHistoryDays: %s" % (self.ui.inHistoryDays.value(),)) + + def _historyLoadGraph(self): + station = self.ui.slHistoryStation.currentText() + days = self.ui.inHistoryDays.value() + + print("_historyLoad: station=%s days=%s" % (station, days)) + + self.ui.lbHistory.clear() + self.ui.lbHistory.setText("Laden...") + + if station == '' or station is None: + print("_historyLoad: Fehler: Ungültige Station: %s" % (station,)) + self.ui.lbHistory.setText("Bitte Station wählen...") + return + + if days is None or days < 1 or days > 30: + print("_historyLoad: Fehler: Ungültige Anzahl von Tagen: %s" % (days,)) + self.ui.lbHistory.setText("Bitte Tage [1, 30] wählen...") + return + + history = PoHistory(station, days) + image_data = history.download() + + if image_data is None or len(image_data) == 0: + print("_historyLoad: Fehler: Keine Daten erhalten") + self.ui.lbHistory.setText("Fehler beim Download!") + return + + pixmap = QtGui.QPixmap() + pixmap.loadFromData(image_data) + self.ui.lbHistory.setPixmap(pixmap) + self.ui.lbHistory.resize(pixmap.width(), pixmap.height()) + + def _historyLoadStations(self): + print("_init_history_signals") + + # merke die aktuelle Station, um sie wiederherzustellen + bisherige_station = self.ui.slHistoryStation.currentText() + + self.ui.slHistoryStation.clear() + + stations = PoStations().getStations() + if stations is None or len(stations) == 0: + print("_init_history_signals: Fehler: Keine Stationen erhalten") + return + + index = 0 + neuer_index = None + for station in stations: + shortname = station['attributes']['shortname'] + if shortname == bisherige_station: + neuer_index = index + self.ui.slHistoryStation.addItem(shortname) + index += 1 + + if neuer_index is not None: + self.ui.slHistoryStation.setCurrentIndex(neuer_index) + else: + self.ui.slHistoryStation.setCurrentIndex(0) diff --git a/pomodules/po_history.py b/pomodules/po_history.py new file mode 100644 index 0000000..3bd3137 --- /dev/null +++ b/pomodules/po_history.py @@ -0,0 +1,21 @@ +from urllib.parse import quote + +from . import poBaseURL +from .urlreader import UrlReader + + +class PoHistory(UrlReader): + + def __init__(self, station: str, days: int): + super().__init__(poBaseURL + 'stations/%s/W/measurements.png?start=P%dD' % (quote(station), days)) + + def download(self): + print("download: Getting data...") + + image_data = self.getDataResponse() + if image_data is None or len(image_data) == 0: + print("download: Fehler: Keine Daten erhalten") + return None + + print("download: Complete") + return image_data diff --git a/pomodules/postations.py b/pomodules/po_stations.py similarity index 89% rename from pomodules/postations.py rename to pomodules/po_stations.py index d585c3c..32fe3d9 100644 --- a/pomodules/postations.py +++ b/pomodules/po_stations.py @@ -2,17 +2,16 @@ from . import poBaseURL from .urlreader import UrlReader -class PoStations(object): +class PoStations(UrlReader): def __init__(self): - self.url = poBaseURL + 'stations.json' + super().__init__(poBaseURL + 'stations.json') def getStations(self): print("getStations: Getting data...") - reader = UrlReader(self.url) - stations_json = reader.getJsonResponse() - if stations_json is None: + stations_json = self.getJsonResponse() + if stations_json is None or len(stations_json) == 0: print("getStations: Keine Stationen erhalten") return None diff --git a/pomodules/poqgsstations.py b/pomodules/po_stations_qgs.py similarity index 87% rename from pomodules/poqgsstations.py rename to pomodules/po_stations_qgs.py index a99e172..8da8646 100644 --- a/pomodules/poqgsstations.py +++ b/pomodules/po_stations_qgs.py @@ -2,13 +2,13 @@ from PyQt5.QtCore import QVariant from qgis._core import QgsCoordinateReferenceSystem, QgsGeometry, QgsPointXY from qgis.core import QgsFields, QgsFeature, QgsField -from .postations import PoStations +from .po_stations import PoStations class PoQgsStations(PoStations): def __init__(self): - PoStations.__init__(self) + super().__init__() self.fields = None self.crs = QgsCoordinateReferenceSystem(4326, QgsCoordinateReferenceSystem.EpsgCrsId) @@ -25,7 +25,13 @@ class PoQgsStations(PoStations): self.fields.append(QgsField('water', QVariant.String)) features = [] - for station in self.getStations(): + stations = self.getStations() + + if stations is None or len(stations) == 0: + print("getStations: Fehler: Keine Stationen erhalten") + return None + + for station in stations: feature = self._getFeatureForStation(station) features.append(feature) diff --git a/pomodules/pocurrentw.py b/pomodules/po_waterlevels.py similarity index 86% rename from pomodules/pocurrentw.py rename to pomodules/po_waterlevels.py index 4820c68..a24dfe2 100644 --- a/pomodules/pocurrentw.py +++ b/pomodules/po_waterlevels.py @@ -2,17 +2,16 @@ from . import poBaseURL from .urlreader import UrlReader -class PoCurrentW(object): +class PoCurrentW(UrlReader): def __init__(self): - self.url = poBaseURL + 'stations.json?timeseries=W&includeTimeseries=true&includeCurrentMeasurement=true' + super().__init__(poBaseURL + 'stations.json?timeseries=W&includeTimeseries=true&includeCurrentMeasurement=true') def getCurrentW(self): print("getCurrentW: Getting data...") - reader = UrlReader(self.url) - stations_json = reader.getJsonResponse() - if stations_json is None: + stations_json = self.getJsonResponse() + if stations_json is None or len(stations_json) == 0: print("getCurrentW: FEHLER: Keine Stationen erhalten") return None diff --git a/pomodules/poqgscurrentw.py b/pomodules/po_waterlevels_qgs.py similarity index 88% rename from pomodules/poqgscurrentw.py rename to pomodules/po_waterlevels_qgs.py index 1133184..9037d14 100644 --- a/pomodules/poqgscurrentw.py +++ b/pomodules/po_waterlevels_qgs.py @@ -2,7 +2,7 @@ from PyQt5.QtCore import QVariant from qgis._core import QgsCoordinateReferenceSystem, QgsGeometry, QgsPointXY from qgis.core import QgsFields, QgsFeature, QgsField -from .pocurrentw import PoCurrentW +from .po_waterlevels import PoCurrentW class PoQgsCurrentW(PoCurrentW): @@ -25,7 +25,12 @@ class PoQgsCurrentW(PoCurrentW): self.fields.append(QgsField('stateNswHsw', QVariant.String)) features = [] - for station in self.getCurrentW(): + waterlevels = self.getCurrentW() + if waterlevels is None or len(waterlevels) > 0: + print("getCurrentW: Fehler: Keine Pegelstände erhalten") + return None + + for station in waterlevels: feature = self._getFeatureForStation(station) features.append(feature)