roe-dl/weewx-GTS

Kompatibilitätsprobleme mit WeeWX 5.X

roe-dl opened this issue · 21 comments

Bei meinem Test mit der Beta-Version von 5.0 hatte ich keine Probleme. Die Praxis ist dann eben immer noch etwas anderes.

Bekannt ist, daß WeeWX etwas an der Berechnung der X-Typen geändert hat. Die Frage ist, wie man herausfindet, was hier anders läuft als vorher. Als Workaround kann man die Größen in die Datenbank aufnehmen. Aber die endgültige Lösung ist das nicht. Vielleicht müßte man als erste die Implementation von get_series zwischen den beiden Versionen vergleichen.

Ein kurzer Vergleich von xtype.py zwischen den Versionen brachte eine Funktion has_data() zutage, die get_aggregate() mit not_null aufruft, so nach der Art $day.GTS.not_null. not_null ist in der GTS-Erweiterung nicht implementiert.

Originally posted by @roe-dl in #26 (comment)

Der not_null Aufruf hier https://github.com/weewx/weewx/blob/v5.0.2/src/weewx/xtypes.py#L156, korrekt?

Heißt also GTS müsste noch die has_data methode implementieren?

Ich könnte mir vorstellen, daß das Problem dort liegt. Ich habe noch angefragt, was der Unterschied zwischen has_data und not_null ist. Die Funktion heißt has_data(), ruft aber den aggregation type not_null auf, und in der Dokumentation von WeeWX 5.0 gibt es sowohl den aggregation type not_null als auch has_data, und die Beschreibung ist sehr ähnlich.

Antwort von Tom Keffer zum Unterschied zwischen has_data und not_null:

The aggregation not_null does not check first to see if the type exists. If you know the type exists, it's slightly faster.

In practice, I don't think it's very useful. I may remove it from the documentation.

On Fri, Feb 23, 2024 at 3:48 AM Karen K <kk44...@gmail.com> wrote:

What is the difference between the aggregation types has_data and not_null according to the documentation in http://weewx.com/docs/5.0/reference/aggtypes/.

Quelle: https://groups.google.com/g/weewx-user/c/pzAYNK1eUjg/m/hI0xtgMwAAAJ

Daraus ergibt sich, daß beide implementiert werden müssen.

Fehler bleibt leider bestehen wie in #26 (comment) beschrieben

Feb 23 01:05:36 dba-MS-7D07 weewxd[899218]: ERROR weewx.cheetahgenerator: Evaluation of template /etc/weewx/skins/weewx-wdc/year.html.tmpl failed with exception '<class 'weewx.UnknownType'>'
Feb 23 01:05:36 dba-MS-7D07 weewxd[899218]: ERROR weewx.cheetahgenerator: **** Ignoring template /etc/weewx/skins/weewx-wdc/year.html.tmpl
Feb 23 01:05:36 dba-MS-7D07 weewxd[899218]: ERROR weewx.cheetahgenerator: **** Reason: 'yearGDD' or 'avg'
Feb 23 01:05:36 dba-MS-7D07 weewxd[899218]: ERROR weewx.cheetahgenerator: ****  Traceback (most recent call last):
Feb 23 01:05:36 dba-MS-7D07 weewxd[899218]: ERROR weewx.cheetahgenerator: ****    File "/usr/share/weewx/weewx/cheetahgenerator.py", line 334, in generate
Feb 23 01:05:36 dba-MS-7D07 weewxd[899218]: ERROR weewx.cheetahgenerator: ****      unicode_string = compiled_template.respond()
Feb 23 01:05:36 dba-MS-7D07 weewxd[899218]: ERROR weewx.cheetahgenerator: ****    File "_etc_weewx_skins_weewx_wdc_year_html_tmpl.py", line 193, in respond
Feb 23 01:05:36 dba-MS-7D07 weewxd[899218]: ERROR weewx.cheetahgenerator: ****    File "/usr/lib/python3/dist-packages/Cheetah/Template.py", line 1708, in _handleCheetahInclude
Feb 23 01:05:36 dba-MS-7D07 weewxd[899218]: ERROR weewx.cheetahgenerator: ****      self._CHEETAH__cheetahIncludes[_includeID].respond(trans)
Feb 23 01:05:36 dba-MS-7D07 weewxd[899218]: ERROR weewx.cheetahgenerator: ****    File "_etc_weewx_skins_weewx_wdc_includes_body_alternative_inc.py", line 324, in respond
Feb 23 01:05:36 dba-MS-7D07 weewxd[899218]: ERROR weewx.cheetahgenerator: ****    File "/usr/lib/python3/dist-packages/Cheetah/Template.py", line 1708, in _handleCheetahInclude
Feb 23 01:05:36 dba-MS-7D07 weewxd[899218]: ERROR weewx.cheetahgenerator: ****      self._CHEETAH__cheetahIncludes[_includeID].respond(trans)
Feb 23 01:05:36 dba-MS-7D07 weewxd[899218]: ERROR weewx.cheetahgenerator: ****    File "_etc_weewx_skins_weewx_wdc_includes_combined_diagram_tile_inc.py", line 360, in respond
Feb 23 01:05:36 dba-MS-7D07 weewxd[899218]: ERROR weewx.cheetahgenerator: ****    File "_etc_weewx_skins_weewx_wdc_includes_combined_diagram_tile_inc.py", line 115, in __errorCatcher7
Feb 23 01:05:36 dba-MS-7D07 weewxd[899218]: ERROR weewx.cheetahgenerator: ****    File "<string>", line 1, in <module>
Feb 23 01:05:36 dba-MS-7D07 weewxd[899218]: ERROR weewx.cheetahgenerator: ****    File "/etc/weewx/bin/user/weewx_wdc.py", line 1398, in get_diagram_data
Feb 23 01:05:36 dba-MS-7D07 weewxd[899218]: ERROR weewx.cheetahgenerator: ****      obs_start_vt, obs_stop_vt, obs_vt = weewx.xtypes.get_series(
Feb 23 01:05:36 dba-MS-7D07 weewxd[899218]: ERROR weewx.cheetahgenerator: ****    File "/usr/share/weewx/weewx/xtypes.py", line 127, in get_series
Feb 23 01:05:36 dba-MS-7D07 weewxd[899218]: ERROR weewx.cheetahgenerator: ****      raise weewx.UnknownType(msg)
Feb 23 01:05:36 dba-MS-7D07 weewxd[899218]: ERROR weewx.cheetahgenerator: ****  weewx.UnknownType: 'yearGDD' or 'avg'

Diese Meldungen kommen nach start des report run teilweise mehrfach pro sekunde:

Feb 23 02:25:59 dba-MS-7D07 weewxd[947879]: DEBUG user.GTS: GDD integral base=50.0 limit=86.0 stop=1000.0
Feb 23 02:25:59 dba-MS-7D07 weewxd[947879]: DEBUG user.GTS: GDD integral unit=degree_F_day unitgroup=group_degree_day
Feb 23 02:25:59 dba-MS-7D07 weewxd[947879]: DEBUG user.GTS: GDD integral base=50.0 limit=86.0 stop=1000.0
Feb 23 02:25:59 dba-MS-7D07 weewxd[947879]: DEBUG user.GTS: GDD integral unit=degree_F_day unitgroup=group_degree_day

@c0by85 hatte Änderungen zum Positiven beobachtet: #26 (comment)

$year.yearGDD.series dauert unter WeeWX 4.10 zwar 3 Minuten, wird aber ohne Fehler berechnet.

Zum Nachvollziehen bräuchte ich mal das komplette Tag $...yearGDD.series(...) bzw. die Aufrufparameter von get_series(), die zu den o.g. Meldungen führen.

tags.ObservationBinder.has_data in WeeWX 4.10:

    @property
    def has_data(self):
        return self.db_lookup(self.data_binding).has_data(self.obs_type, self.timespan)

tags.ObservationBinder.has_data in WeeWX 5.0:

    @property
    def has_data(self):
        db_manager = self.db_lookup(self.data_binding)
        # First see if the type exists in the database.
        if db_manager.exists(self.obs_type):
            # Yes. Is it non-null?
            val = bool(weewx.xtypes.get_aggregate(self.obs_type, self.timespan,
                                                  'not_null', db_manager)[0])
        else:
            # Nope. Try the xtypes system.
            val = weewx.xtypes.has_data(self.obs_type, self.timespan, db_manager)
        return val

Und wenn man weiter guckt, dann scheint es mir im Moment so, daß bei der 5.0-Version unabhängig von der if-Bedingung in beiden Fällen letztlich dasselbe passiert. Die Datenbank wird gar nicht mehr befragt, nur noch das XType-System. Vielleicht ist das auch die Ursache für die diversen Geschwindigkeitsprobleme von WeeWX 5.0 im Vergleich zu 4.X.

https://groups.google.com/g/weewx-user/c/pzAYNK1eUjg/m/lGYlhuptAAAJ

Zum Nachvollziehen bräuchte ich mal das komplette Tag $...yearGDD.series(...) bzw. die Aufrufparameter von get_series(), die zu den o.g. Meldungen führen.

Das wäre dann z.B.:

obs_start_vt, obs_stop_vt, obs_vt = weewx.xtypes.get_series(
    "GTS",
    TimeSpan(1677106800, 1708772100),
    self.generator.db_binder.get_manager("wx_binding"),
    aggregate_type="avg",
    aggregate_interval=86400
)

Siehe auch hier: https://github.com/Daveiano/weewx-wdc/blob/3.x/bin/user/weewx_wdc.py#L1388-L1399

Die Fehlermeldungen beziehen sich auf yearGDD. Auch nur dort können im Debug-Modus diese massenhaften Meldungen auftreten. Bei GTS gibt es eine solche Meldung nicht.

Ich habe den Funktionsaufruf mal in $span($day_delta=365).GTS.series(aggregate_type='avg',aggregate_interval=86400) übersetzt. Das liefert bei mir unter WeeWX 4.10 eine lange Liste nachvollziehbarer Werte. Gleiches gilt für yearGDD anstelle von GTS. Für WeeWX 5.0 müssen wir erst eine aktuelle Installation aufsetzen. Das kann noch ein bißchen dauern.

In der Zwischenzeit die Frage: Treten die Fehlermeldungen auch auf, wenn

  • der Zeitraum an einer Jahresgrenze beginnt?
  • der Zeitraum für GTS nur von Januar bis Mai geht?

Die Fehlermeldungen beziehen sich auf yearGDD. Auch nur dort können im Debug-Modus diese massenhaften Meldungen auftreten. Bei GTS gibt es eine solche Meldung nicht.

Ich habe den Funktionsaufruf mal in $span($day_delta=365).GTS.series(aggregate_type='avg',aggregate_interval=86400) übersetzt. Das liefert bei mir unter WeeWX 4.10 eine lange Liste nachvollziehbarer Werte. Gleiches gilt für yearGDD anstelle von GTS.

Korrekt, das Beispiel war einfach copy & pasted.

In der Zwischenzeit die Frage: Treten die Fehlermeldungen auch auf, wenn
der Zeitraum an einer Jahresgrenze beginnt?

Wenn ich im Skin start_ts für die jährlichen Charts in get_series auf den 1.1. des jeweiligen Jahres setzte, wird die Seite für 2021 generiert, bei den nachfolgenden Seiten für 22/23/24 steigt WeeWX dann jedoch wieder aus.

der Zeitraum für GTS nur von Januar bis Mai geht?

Bei kürzeren Zeiträumen scheint es zu funktionieren, ja. Ein Chart für die letzten 30 Tage lässt sich generieren, dauert aber lange.

Mein Eindruck ist kurzgefasst, das die Berechnung der Werte scheinbar einfach zu lange für den Report run dauert.

Mein Eindruck ist kurzgefasst, das die Berechnung der Werte scheinbar einfach zu lange für den Report run dauert.

Und das könnte daran liegen, daß WeeWX 5.0 bei has_data schon einmal alle Werte berechnet und dann bei der eigentlichen Ausgabe noch einmal. Wenn die Theorie stimmt, sollte es bei GTS allein nicht so schlimm sein, weil alle Werte im Speicher gehalten werden.

Vielleicht sollte man einmal testweise in GTS.py am Anfang der Funktion get_aggregate() einfügen

        if aggregate_type=='not_null':
            return weewx.units.ValueTuple(True,'boolean','group_boolean')

und gucken, wie das Zeitverhalten dann ist.

Und als zweiten Versuch könnte man weewx.xtypes.xtypes.append(self.GTSextension) durch weewx.xtypes.xtypes.insert(0,self.GTSextension) ersetzen und erneut das Zeitverhalten beobachten. Letztere Maßnahme ist aber nicht ohne Nebenwirkungen, denn sie meldet dann für alle Meßgrößen (wirklich alle) und alle Zeitintervalle, daß Daten da sind, egal ob das stimmt oder nicht.

Und man könnte unabhängig von den beiden obigen Versuchen in tags.py die Funktion weewx.tags.ObservationBinder.has_data folgendermaßen verändern (nur eine Zeile geändert):

    @property
    def has_data(self):
        db_manager = self.db_lookup(self.data_binding)
        # First see if the type exists in the database.
        if db_manager.exists(self.obs_type):
            # Yes. Is it non-null?
            val = bool(db_manager.has_data(self.obs_type, self.timespan))
        else:
            # Nope. Try the xtypes system.
            val = weewx.xtypes.has_data(self.obs_type, self.timespan, db_manager)
        return val

Da bin ich mir aber nicht sicher, ob diese Variante der Funktion auch unter WeeWX 5.0 funktioniert. Aber probieren geht über studieren.

Und das könnte daran liegen, daß WeeWX 5.0 bei has_data schon einmal alle Werte berechnet und dann bei der eigentlichen Ausgabe noch einmal.

Ja, macht den Eindruck.

Vielleicht sollte man einmal testweise in GTS.py am Anfang der Funktion get_aggregate() einfügen [...] und gucken, wie das Zeitverhalten dann ist.

Hier konnte ich keine Änderung feststellen

Und als zweiten Versuch könnte man weewx.xtypes.xtypes.append(self.GTSextension) durch weewx.xtypes.xtypes.insert(0,self.GTSextension) ersetzen und erneut das Zeitverhalten beobachten.

Leider ebenfalls keine bemerkbare Änderung des Verhaltens.

Und man könnte unabhängig von den beiden obigen Versuchen in tags.py die Funktion weewx.tags.ObservationBinder.has_data folgendermaßen verändern (nur eine Zeile geändert):

Das macht einen Unterschied, damit können schon mal die Jahres-Charts generiert werden, es dauert allerdings trotzdem ziemlich lang. Die tests führe ich auf einem starken Desktop-PC aus, ich bezweifele fast das mein RP4 das schaffen würde. Es scheint also immer noch sehr rechenintensiv zu sein. Und ich bemerke gerade: Das ganze funktioniert auch nur wenn der Startpunkt für get_series der 1.1. des jeweiligen Jahres ist.

Wie sieht es mit Tom Keffers Variante aus?

P.S.: Ich versuche mal in den nächsten Tagen, selbst ein System mit WeeWX 5.0 aufzusetzen, um auch selbst testen zu können. Leider hat das noch nicht geklappt.

Ich habe mir diese Fehlermeldungen noch einmal angesehen:

...
Feb 23 01:05:36 dba-MS-7D07 weewxd[899218]: ERROR weewx.cheetahgenerator: ****    File "/etc/weewx/bin/user/weewx_wdc.py", line 1398, in get_diagram_data
Feb 23 01:05:36 dba-MS-7D07 weewxd[899218]: ERROR weewx.cheetahgenerator: ****      obs_start_vt, obs_stop_vt, obs_vt = weewx.xtypes.get_series(
Feb 23 01:05:36 dba-MS-7D07 weewxd[899218]: ERROR weewx.cheetahgenerator: ****    File "/usr/share/weewx/weewx/xtypes.py", line 127, in get_series
Feb 23 01:05:36 dba-MS-7D07 weewxd[899218]: ERROR weewx.cheetahgenerator: ****      raise weewx.UnknownType(msg)
Feb 23 01:05:36 dba-MS-7D07 weewxd[899218]: ERROR weewx.cheetahgenerator: ****  weewx.UnknownType: 'yearGDD' or 'avg'

Die GTS-Erweiterung hat keine Funktion get_series() implementiert und hatte das auch nie. Es kommt also eine Standardfunktion von WeeWX zum Einsatz. Hier habe ich die Versionen von 4.10 und 5.0 mal verglichen, und in der Tat gibt es deutliche Unterschiede:

WeeWX 4.10:

class ArchiveTable(XType):
    ...
    @staticmethod
    def get_series(obs_type, timespan, db_manager, aggregate_type=None, aggregate_interval=None,
                   **option_dict):
        ...
            for stamp in weeutil.weeutil.intervalgen(startstamp, stopstamp, aggregate_interval):
                # Get the aggregate as a ValueTuple
                agg_vt = get_aggregate(obs_type, stamp, do_aggregate, db_manager)
                if agg_vt[0] is None:
                    continue
                ...

WeeWX 5.0:

class ArchiveTable(XType):
    ...
    @staticmethod
    def get_series(obs_type, timespan, db_manager, aggregate_type=None, aggregate_interval=None,
                   **option_dict):
        ...
            for stamp in weeutil.weeutil.intervalgen(startstamp, stopstamp, aggregate_interval):
                if db_manager.first_timestamp is None or stamp.stop <= db_manager.first_timestamp:
                    continue
                if db_manager.last_timestamp is None or stamp.start >= db_manager.last_timestamp:
                    break
                try:
                    # Get the aggregate as a ValueTuple
                    agg_vt = get_aggregate(obs_type, stamp, do_aggregate, db_manager,
                                           **option_dict)
                except weewx.CannotCalculate:
                    # Function get_aggregate() should not raise CannotCalculate. But, just in case,
                    # catch it and convert to None.
                    agg_vt = ValueTuple(None, unit, unit_group)
                ...

Als markante Unterschiede sehen wir die Tests auf db_manager.first_timestamp und db_manager.last_timestamp. Und dann kommt ein viel gravierenderer Unterschied: WeeWX 4.10 filtert None-Werte komplett aus, während WeeWX 5.0 sie drin beläßt. Das sollte zwar kein Problem sein, aber vielleicht doch, und es ist ein Ansatzpunkt für die Suche.

Als Tests würden hier anstehen (jeweils mit dem anderen im Originalzustand):

  • Auskommentieren der beiden Bedingungen im gezeigten Ausschnitt und Ausfiltern der None-Werte mittels if agg_vt[0] is None: continue. Dann alles schrittweise wieder aktivieren.
  • Übernahme der 4.10er Version von get_series in GTS.py für GTS, seasonGDD und yearGDD.

Mit dem Finden der Ursache ist noch keine Entscheidung verbunden, wie man das Problem dann löst.

Wie sieht es mit Tom Keffers Variante aus?

Hatte den Kommentar auch schon gesehen und die Änderung getestet, aber keine Veränderung im Verhalten feststellen können.

Die GTS-Erweiterung hat keine Funktion get_series() implementiert und hatte das auch nie. Es kommt also eine Standardfunktion von WeeWX zum Einsatz. Hier habe ich die Versionen von 4.10 und 5.0 mal verglichen, und in der Tat gibt es deutliche Unterschiede: [...] Und dann kommt ein viel gravierenderer Unterschied: WeeWX 4.10 filtert None-Werte komplett aus, während WeeWX 5.0 sie drin beläßt.

Das habe ich bei Tests mit dem wdc Skin auch bermerkt, ich musste hier dann selbst die null Values herausfiltern für die Charts.

Auskommentieren der beiden Bedingungen im gezeigten Ausschnitt und Ausfiltern der None-Werte mittels if agg_vt[0] is None: continue. Dann alles schrittweise wieder aktivieren.

Sieht dann so hier aus, aber bringt auch keine Änderung:

#
# ######################## Class ArchiveTable ##############################
#

class ArchiveTable(XType):
    """Calculate types and aggregates directly from the archive table"""

    @staticmethod
    def get_series(obs_type, timespan, db_manager, aggregate_type=None, aggregate_interval=None,
                   **option_dict):
        ...

            for stamp in weeutil.weeutil.intervalgen(startstamp, stopstamp, aggregate_interval):
                #if db_manager.first_timestamp is None or stamp.stop <= db_manager.first_timestamp:
                #    continue
                #if db_manager.last_timestamp is None or stamp.start >= db_manager.last_timestamp:
                #    break
                try:
                    # Get the aggregate as a ValueTuple
                    agg_vt = get_aggregate(obs_type, stamp, do_aggregate, db_manager,
                                           **option_dict)
                except weewx.CannotCalculate:
                    # Function get_aggregate() should not raise CannotCalculate. But, just in case,
                    # catch it and convert to None.
                    agg_vt = ValueTuple(None, unit, unit_group)
                if agg_vt[0] is None:
                    continue
                if unit:
                    # Make sure units are consistent so far.
                    if agg_vt[1] is not None and (unit != agg_vt[1] or unit_group != agg_vt[2]):
                        raise weewx.UnsupportedFeature("Cannot change units within a series.")
                else:
                    unit, unit_group = agg_vt[1], agg_vt[2]
                ...

P.S.: Ich versuche mal in den nächsten Tagen, selbst ein System mit WeeWX 5.0 aufzusetzen, um auch selbst testen zu können. Leider hat das noch nicht geklappt.

Alles gut, kein Stress von meiner Seite, obwohl GTS bei uns wohl bald 200 überschreiten wird :)

Mir kommt gerade noch ein Gedanke: Kommt die Fehlermeldung auch, wenn man statt avg last nimmt?

Alle drei Größen GTS, yearGDD und seasonGDD sind Tageswerte. So einen richtigen Durchschnitt gibt es da nicht.

@Daveiano Warum muß man eigentlich bei der WDC-Skin die ZIP-Datei vor der Installation entpacken?

Und wie muß ich jetzt die WDC-Skin konfigurieren, daß der Fehler auftritt? Ich würde mich da ungern erst durch die ganze Konfiguration wühlen müssen.

@Daveiano Warum muß man eigentlich bei der WDC-Skin die ZIP-Datei vor der Installation entpacken?

Steht auf meiner Liste der Todos... Wusste es anfangs nicht besser (im .zip muss es ja noch einen Ordner geben in dem dann wiederum install.py, etc liegen - ich hatte die Dateien direkt ins Root des .zip gelegt) und habe es bis heute nicht korrigiert (die liebe Zeit...).

Und wie muß ich jetzt die WDC-Skin konfigurieren, daß der Fehler auftritt? Ich würde mich da ungern erst durch die ganze Konfiguration wühlen müssen.

Anleitung siehe hier https://github.com/Daveiano/weewx-wdc/wiki/Code-Snippets#using-weewx-gts, ich hoffe das ist verständlich. Bei der Einbindung unter [[[month]]] sollte es noch funktionieren, bei [[[year]]] bzw [[[alltime]]] kommt es dann zum Fehler.


Zu den übrigen Tests werde ich leider erst Mitte der Woche kommen.

Mit der Seasons-Skin ließen sich auch schon Versuche anstellen. Wenn man GTS zu den anzuzeigenden Werten hinzufügt, ändert sich noch nicht viel. Bei mir dauerte die Erzeugung der HTML-Seiten 0,43 s ohne und 0,44 s mit GTS beim ersten Durchlauf, dann wieder 0,43 s. Fügt man GTS bei den Statistiken hinzu, waren es auf einmal 20 s. Weitere Tests ergaben, daß es bei jedem Durchlauf über 100000 Abrufe des GTS-Wertes gab. Verursacht werden sie von der Funktion weewx.xtypes.XTypeTable.get_aggregate, die es bei WeeWX 5.0 gibt, bei WeeWX 4.10 jedoch noch nicht.

Nur wenige Zeilen Code genügen, um das Problem zu produzieren: weewx/weewx#939

Anleitung siehe hier https://github.com/Daveiano/weewx-wdc/wiki/Code-Snippets#using-weewx-gts, ich hoffe das ist verständlich. Bei der Einbindung unter [[[month]]] sollte es noch funktionieren, bei [[[year]]] bzw [[[alltime]]] kommt es dann zum Fehler.

Einen Link auf diese Anleitung habe ich in die Dokumentation aufgenommen. Unklar war mir bei der Beschreibung zunächst, in welche Datei die Sachen einzutragen sind.

Mit den Änderungen an GTS.py wurden die Dateien in endlicher Zeit erzeugt. Für "year" und "alltime" gab es aber eine Fehlermeldung, wonach die Maßeinheiten nicht konsistent seien. Diese Fehlermeldung konnte ich nicht einordnen.

@Daveiano Geht jetzt wieder alles?

Einen Link auf diese Anleitung habe ich in die Dokumentation aufgenommen. Unklar war mir bei der Beschreibung zunächst, in welche Datei die Sachen einzutragen sind.

Ah sehr gut, vielen Dank dafür. Ich habe noch einen Hinweis hinzugefügt das sich die Änderungen auf die skin.conf beziehen.

Geht jetzt wieder alles?

Habe die Änderungen aus den letzten beiden Commits getestet und es funktioniert wieder alles. Habe in einem Report Run 4 Jahres Berichte mit GTS, yearGDD und seasonGDD und die Alltime-seite generieren können - und das auch ziemlich flott. Zumindest gefühlt ähnliche Performance wie unter WeeWX 4 - wenn nicht sogar schneller.