>From the logs, it looks like there are some temperature values missing in 
your database (that's where the NoneType came from). Like your station 
stopped working for 2 or 3 days!?
I added a check to address this issue. Could you please replace 
/usr/share/weewx/user/stats_util.py with the attached stats_util.py?

Any chance I could get a copy of your weewx database to test and verify 
this?

For reference: I also added a issue on GH for 
this: https://github.com/Daveiano/weewx-wdc/issues/9
tarob...@gmail.com schrieb am Samstag, 28. Mai 2022 um 18:38:07 UTC+2:

> The skin displays but there are quite a bit of errors (see below).
>
> May 28 12:35:16 raspberrypi weewx[8931] INFO weewx.manager: Added record 
> 2022-05-28 12:35:00 EDT (1653755700) to database 'weewx.sdb'
> May 28 12:35:16 raspberrypi weewx[8931] INFO weewx.manager: Added record 
> 2022-05-28 12:35:00 EDT (1653755700) to daily summary in 'weewx.sdb'
> May 28 12:35:20 raspberrypi weewx[8931] INFO weewx.cheetahgenerator: 
> Generated 8 files for report SeasonsReport in 1.54 seconds
> May 28 12:35:21 raspberrypi weewx[8931] INFO weewx.imagegenerator: 
> Generated 15 images for report SeasonsReport in 0.95 seconds
> May 28 12:35:21 raspberrypi weewx[8931] INFO weewx.reportengine: Copied 0 
> files to /var/www/html/weewx
> May 28 12:35:23 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: 
> Evaluation of template /etc/weewx/skins/weewx-wdc/year-%Y.html.tmpl failed 
> with exception '<class 'TypeError'>'
> May 28 12:35:23 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
> Ignoring template /etc/weewx/skins/weewx-wdc/year-%Y.html.tmpl
> May 28 12:35:23 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
> Reason: '>=' not supported between instances of 'NoneType' and 'float'
> May 28 12:35:23 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
>  Traceback (most recent call last):
> May 28 12:35:23 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
>    File "/usr/share/weewx/weewx/cheetahgenerator.py", line 348, in generate
> May 28 12:35:23 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
>      unicode_string = compiled_template.respond()
> May 28 12:35:23 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
>    File "_etc_weewx_skins_weewx_wdc_year__Y_html_tmpl.py", line 183, in 
> respond
> May 28 12:35:23 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
>    File "/usr/lib/python3/dist-packages/Cheetah/Template.py", line 1707, in 
> _handleCheetahInclude
> May 28 12:35:23 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
>      self._CHEETAH__cheetahIncludes[_includeID].respond(trans)
> May 28 12:35:23 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
>    File "_etc_weewx_skins_weewx_wdc_includes_climatological_days_inc.py", 
> line 277, in respond
> May 28 12:35:23 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
>    File "_etc_weewx_skins_weewx_wdc_includes_climatological_days_inc.py", 
> line 106, in __errorCatcher6
> May 28 12:35:23 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
>    File "<string>", line 1, in <module>
> May 28 12:35:23 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
>    File "/usr/share/weewx/user/stats_util.py", line 175, in 
> get_climatological_day
> May 28 12:35:23 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
>      return len(list(days))
> May 28 12:35:23 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
>    File "/usr/share/weewx/user/stats_util.py", line 173, in <lambda>
> May 28 12:35:23 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
>      days = filter(lambda x: x.raw >= value, list(day_series.data))
> May 28 12:35:23 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
>  TypeError: '>=' not supported between instances of 'NoneType' and 'float'
> May 28 12:35:35 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: 
> Evaluation of template /etc/weewx/skins/weewx-wdc/statistics.html.tmpl 
> failed with exception '<class 'TypeError'>'
> May 28 12:35:35 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
> Ignoring template /etc/weewx/skins/weewx-wdc/statistics.html.tmpl
> May 28 12:35:35 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
> Reason: '>=' not supported between instances of 'NoneType' and 'float'
> May 28 12:35:35 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
>  Traceback (most recent call last):
> May 28 12:35:35 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
>    File "/usr/share/weewx/weewx/cheetahgenerator.py", line 348, in generate
> May 28 12:35:35 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
>      unicode_string = compiled_template.respond()
> May 28 12:35:35 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
>    File "_etc_weewx_skins_weewx_wdc_statistics_html_tmpl.py", line 191, in 
> respond
> May 28 12:35:35 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
>    File "/usr/lib/python3/dist-packages/Cheetah/Template.py", line 1707, in 
> _handleCheetahInclude
> May 28 12:35:35 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
>      self._CHEETAH__cheetahIncludes[_includeID].respond(trans)
> May 28 12:35:35 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
>    File "_etc_weewx_skins_weewx_wdc_includes_climatological_days_inc.py", 
> line 277, in respond
> May 28 12:35:35 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
>    File "_etc_weewx_skins_weewx_wdc_includes_climatological_days_inc.py", 
> line 106, in __errorCatcher6
> May 28 12:35:35 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
>    File "<string>", line 1, in <module>
> May 28 12:35:35 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
>    File "/usr/share/weewx/user/stats_util.py", line 175, in 
> get_climatological_day
> May 28 12:35:35 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
>      return len(list(days))
> May 28 12:35:35 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
>    File "/usr/share/weewx/user/stats_util.py", line 173, in <lambda>
> May 28 12:35:35 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
>      days = filter(lambda x: x.raw >= value, list(day_series.data))
> May 28 12:35:35 raspberrypi weewx[8931] ERROR weewx.cheetahgenerator: **** 
>  TypeError: '>=' not supported between instances of 'NoneType' and 'float'
> May 28 12:35:35 raspberrypi weewx[8931] INFO weewx.cheetahgenerator: 
> Generated 9 files for report WdcReport in 14.05 seconds
> May 28 12:35:35 raspberrypi weewx[8931] INFO weewx.reportengine: Copied 0 
> files to /var/www/html/weewx/wdc
>
> On Friday, May 27, 2022 at 8:25:38 PM UTC-4 david....@gmail.com wrote:
>
>> Yes, that's correct, I think weewx wants the zip to contain only one 
>> folder which contains the whole extension. (if you want to directly install 
>> from zip without the "extract to folder" step)
>>
>> Glad I could help you!
>>
>> tarob...@gmail.com schrieb am Samstag, 28. Mai 2022 um 02:19:15 UTC+2:
>>
>>> Got it working. I see it can't install from zip. Need to extract to 
>>> directory and install from that location. Thank you.
>>>
>>> On Friday, May 27, 2022 at 5:31:53 PM UTC-4 david....@gmail.com wrote:
>>>
>>>> The file location is correct, but you need to use the .zip which is 
>>>> attached to a release.
>>>>
>>>> The latest release is v1.2.0, the download path for the zip is 
>>>> https://github.com/Daveiano/weewx-wdc/releases/download/v1.2.0/weewx-wdc-v1.2.0.zip
>>>> Release page is here: 
>>>> https://github.com/Daveiano/weewx-wdc/releases/tag/v1.2.0 (its the 
>>>> first linked zip)
>>>>
>>>> *Background*: The files in the src/ directory are the Source files 
>>>> (TypeScript, SCSS). When creating a release, the source files get 
>>>> transformed and optimized, the output location of these transformed files 
>>>> is the location from the install.py. The release.zip should contain all 
>>>> these transformed files (like service-worker.js), but if you download the 
>>>> current state of the repo, these files are not included, hence the error. 
>>>>
>>>> Please let me know if this helps and solves the problem, I will also 
>>>> add a notice about it on the readme page.
>>>>
>>>> tarob...@gmail.com schrieb am Freitag, 27. Mai 2022 um 14:30:21 UTC+2:
>>>>
>>>>> Trying to install from zip (also tried from tar.gz) and getting the 
>>>>> following:
>>>>>
>>>>> "sudo wee_extension --install=weewx-wdc.zip
>>>>> Request to install 'weewx-wdc.zip'
>>>>> Extracting from zip archive weewx-wdc.zip
>>>>> Traceback (most recent call last):
>>>>>   File "/usr/share/weewx/wee_extension", line 92, in <module>
>>>>>     main()
>>>>>   File "/usr/share/weewx/wee_extension", line 84, in main
>>>>>     ext.install_extension(options.install)
>>>>>   File "/usr/share/weewx/weecfg/extension.py", line 130, in 
>>>>> install_extension
>>>>>     self.install_from_dir(extension_dir)
>>>>>   File "/usr/share/weewx/weecfg/extension.py", line 183, in 
>>>>> install_from_dir
>>>>>     shutil.copy(source_path, destination_path)
>>>>>   File "/usr/lib/python3.7/shutil.py", line 245, in copy
>>>>>     copyfile(src, dst, follow_symlinks=follow_symlinks)
>>>>>   File "/usr/lib/python3.7/shutil.py", line 120, in copyfile
>>>>>     with open(src, 'rb') as fsrc:
>>>>> FileNotFoundError: [Errno 2] No such file or directory: 
>>>>> '/var/tmp/weewx-wdc-1.2.0/skins/weewx-wdc/service-worker.js'
>>>>> "
>>>>>
>>>>> I can see the service-worker.js is located in a different directory 
>>>>> than where the install is looking. It is located 
>>>>> "weewx-wdc-1.2.0\skins\weewx-wdc\src\js\service-worker.js"
>>>>>
>>>>> On Thursday, May 26, 2022 at 8:49:31 AM UTC-4 david....@gmail.com 
>>>>> wrote:
>>>>>
>>>>>> Thank you for your feedback, very appreciated!
>>>>>>
>>>>>> *Is it possible to set custom values for font and graph size, amount 
>>>>>> of rows and border size so everything including graphs could be made 
>>>>>> visible at a glance without or less scrolling?*
>>>>>> Currently, this is not possible. The skin uses the IBM Carbon Design 
>>>>>> System, so these values are more or less predefined. But you are right, 
>>>>>> using the space and layouting all the graphs were one of the most 
>>>>>> challenging parts of this. I am also not yet 100% happy with it. Perhaps 
>>>>>> I 
>>>>>> could predefine some "Spacing variations", like a dense one and a wide 
>>>>>> one 
>>>>>> for example.
>>>>>>
>>>>>> *Any chance for a web version of the weather data center, so one 
>>>>>> could publish the visualized csv's to the web? Or even comibne it with 
>>>>>> weewx live data in one page? Just a thought*
>>>>>> Do you mean like an export Button on the Desktop Application to 
>>>>>> export all data as HTML pages? Well you can also use the WDC Skin with 
>>>>>> weewx and import all data to weewx via csv, generate the report and 
>>>>>> there 
>>>>>> you go ;)
>>>>>> f4n...@gmail.com schrieb am Donnerstag, 26. Mai 2022 um 12:04:58 
>>>>>> UTC+2:
>>>>>>
>>>>>>> Thanks a lot for this skin (and the weather data visualizing app), 
>>>>>>> looks very clean! 
>>>>>>>
>>>>>>> Is it possible to set custom values for font and graph size, amount 
>>>>>>> of rows and border size so everything including graphs could be made 
>>>>>>> visible at a glance without or less scrolling?
>>>>>>>
>>>>>>> Any chance for a web version of the weather data center, so one 
>>>>>>> could publish the visualized csv's to the web? Or even comibne it with 
>>>>>>> weewx live data in one page? Just a thought
>>>>>>> david....@gmail.com schrieb am Samstag, 14. Mai 2022 um 13:13:39 
>>>>>>> UTC+2:
>>>>>>>
>>>>>>>> Hi guys!
>>>>>>>>
>>>>>>>> I just wanted to do some advertisement for a new weewx Skin, I 
>>>>>>>> developed: https://github.com/Daveiano/weewx-wdc
>>>>>>>>
>>>>>>>> The visual part is based on another weather app, I wrote earlier 
>>>>>>>> this year: https://daveiano.github.io/weather-data-center/
>>>>>>>>
>>>>>>>> Please feel free to check it out, a working demo is hosted here: 
>>>>>>>> https://www.weewx-hbt.de/
>>>>>>>>
>>>>>>>> Key features included:
>>>>>>>> - Clear and beautiful UI thanks to IBM Carbon and nivo
>>>>>>>> - Configurable Statistic Tiles and Diagram tiles
>>>>>>>> - Combinable diagrams via skin.conf
>>>>>>>> - Responsive
>>>>>>>> - Day, week, month, year and all-time pages
>>>>>>>> - Archive and NOAA Reports
>>>>>>>> - Almanac
>>>>>>>> - Translated for DE and EN
>>>>>>>> - Tabular representation with Carbon Data Tables
>>>>>>>>
>>>>>>>> I consider the skin as feature-complete but I will do some updates 
>>>>>>>> in the coming weeks to optimize some things like responsiveness or 
>>>>>>>> perhaps 
>>>>>>>> add some more statistics. 
>>>>>>>>
>>>>>>>> I am a software developer but I never worked with python before. I 
>>>>>>>> have been looking for an opportunity to work with python for a long 
>>>>>>>> time, 
>>>>>>>> so working with weewx and creating a skin did that for me. I am really 
>>>>>>>> caught by how things work together in weewx, a great piece of software.
>>>>>>>>
>>>>>>>

-- 
You received this message because you are subscribed to the Google Groups 
"weewx-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to weewx-user+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/weewx-user/8016299e-8795-4847-b29f-b7aaa2260252n%40googlegroups.com.
from weewx.cheetahgenerator import SearchList
from user.diagram_util import DiagramUtil

# Copyright 2022 David Bätge
# Distributed under the terms of the GNU Public License (GPLv3)


class StatsUtil(SearchList):
    def get_show_min(self, observation):
        """
        Returns if the min stats should be shown.

        Args:
            observation (string): The observation

        Returns:
            bool: Show or hide min stat.
        """
        show_min_stat = [
            "outTemp", "outHumidity", "barometer",
            "windDir", "snowDepth", "heatindex",
            "dewpoint", "windchill", "cloudbase",
            "appTemp"
        ]

        if 'Temp' in observation:
            return True

        elif 'Humid' in observation:
            return True

        if observation in show_min_stat:
            return True

    def get_show_sum(self, observation):
        """
        Returns if the sum stats should be shown.

        Args:
            observation (string): The observation

        Returns:
            bool: Show or hide sum stat.
        """
        show_sum = ["rain", "ET"]

        if observation in show_sum:
            return True

    def get_show_max(self, observation):
        """
        Returns if the max stats should be shown.

        Args:
            observation (string): The observation

        Returns:
            bool: Show or hide max stat.
        """
        show_max = ["rainRate"]

        if observation in show_max:
            return True

    def get_labels(self, prop, precision):
        """
        Returns a label like "Todays Max" or "Monthly average.

        Args:
            prop (string): Min, Max, Sum
            precision (string): Day, week, month, year, alltime

        Returns:
            string: A label.
        """
        if precision == 'alltime':
            return prop

        return prop + ' ' + precision

    def get_climatological_day(self, day, period, unit_type, unit_labels):
        """
        Return number of days in period for day parameter.

        Args:
            day (string): Eg. rainDays, hotDays.
            period (obj): Period to use, eg. $year, month, $span
            unit_type (dict): degree_F or degree_C

        Returns:
            int: Number of days.
        """
        if day == 'iceDays':
            day_series = period.outTemp.series(
                aggregate_type="max",
                aggregate_interval="day",
                time_series='start',
                time_unit='unix_epoch'
            )

            days = filter(lambda x: x.raw is not None and x.raw < 0.0, list(day_series.data))

            return len(list(days))

        if day == 'frostDays':
            day_series = period.outTemp.series(
                aggregate_type="min",
                aggregate_interval="day",
                time_series='start',
                time_unit='unix_epoch'
            )

            days = filter(lambda x: x.raw is not None and x.raw < 0.0, list(day_series.data))

            return len(list(days))

        if day == 'stormDays':
            day_series = period.windGust.series(
                aggregate_type="max",
                aggregate_interval="day",
                time_series='start',
                time_unit='unix_epoch'
            )

            if getattr(unit_labels, 'windGust') == ' km/h':
                value = 62.0
            if getattr(unit_labels, 'windGust') == ' mph':
                value = 38.5
            if getattr(unit_labels, 'windGust') == ' m/s':
                value = 17.2

            days = filter(lambda x: x.raw is not None and x.raw >= value, list(day_series.data))

            return len(list(days))

        if day == 'rainDays':
            day_series = period.rain.series(
                aggregate_type="sum",
                aggregate_interval="day",
                time_series='start',
                time_unit='unix_epoch'
            )

            days = filter(lambda x: x.raw is not None and x.raw > 0.0, list(day_series.data))

            return len(list(days))

        if (day == 'hotDays' or
                day == 'summerDays' or
                day == 'desertDays' or
                day == 'tropicalNights'):

            if day == 'tropicalNights':
                value = 20.0 if getattr(unit_type, 'outTemp') == 'degree_C' else 68.0
                aggregate_type = 'min'
            if day == 'summerDays':
                value = 25.0 if getattr(unit_type, 'outTemp') == 'degree_C' else 77.0
                aggregate_type = 'max'
            if day == 'hotDays':
                value = 30.0 if getattr(unit_type, 'outTemp') == 'degree_C' else 86.0
                aggregate_type = 'max'
            if day == 'desertDays':
                value = 35.0 if getattr(unit_type, 'outTemp') == 'degree_C' else 95.0
                aggregate_type = 'max'

            day_series = period.outTemp.series(
                aggregate_type=aggregate_type,
                aggregate_interval="day",
                time_series='start',
                time_unit='unix_epoch'
            )

            days = filter(lambda x: x.raw is not None and x.raw >= value, list(day_series.data))

            return len(list(days))

    def get_climatological_day_description(self, day, unit_labels,
                                           obs_labels, unit_type):
        """
        Return description of day.

        Args:
            day (string): Eg. rainDays, hotDays.
            unit_labels (dict): weewx $unit
            obs_labels (obj): weewx $obs.labels
            unit_type (dict): degree_F or degree_C

        Returns:
            string: Day description.
        """
        if day == 'iceDays':
            value = '0' if getattr(unit_type, 'outTemp') == 'degree_C' else '32'

            return obs_labels['outTemp'] + '<sub>max</sub> < ' + value + getattr(unit_labels, 'outTemp')

        if day == 'frostDays':
            value = '0' if getattr(unit_type, 'outTemp') == 'degree_C' else '32'

            return obs_labels['outTemp'] + '<sub>min</sub> < ' + value + getattr(unit_labels, 'outTemp')

        if day == 'stormDays':
            if getattr(unit_labels, 'windGust') == ' km/h':
                value = '62'
            if getattr(unit_labels, 'windGust') == ' mph':
                value = '38.5'
            if getattr(unit_labels, 'windGust') == ' m/s':
                value = '17.2'

            return obs_labels['windGust'] + ' > ' + value + getattr(unit_labels, 'windGust')

        if day == 'rainDays':
            return obs_labels['rain'] + ' > 0' + getattr(unit_labels, 'rain')

        if (day == 'hotDays' or
                day == 'summerDays' or
                day == 'desertDays' or
                day == 'tropicalNights'):
            if day == 'tropicalNights':
                value = '20' if getattr(unit_type, 'outTemp') == 'degree_C' else '68'
                aggregate_type = 'min'
            if day == 'summerDays':
                value = '25' if getattr(unit_type, 'outTemp') == 'degree_C' else '77'
                aggregate_type = 'max'
            if day == 'hotDays':
                value = '30' if getattr(unit_type, 'outTemp') == 'degree_C' else '86'
                aggregate_type = 'max'
            if day == 'desertDays':
                value = '35' if getattr(unit_type, 'outTemp') == 'degree_C' else '95'
                aggregate_type = 'max'

            return obs_labels['outTemp'] + '<sub>' + aggregate_type + '</sub> ≥ ' + value + getattr(unit_labels, 'outTemp')

    def get_calendar_color(awlf, obs):
        """
        Returns a color for use in diagram.

        Args:
            observation (string): The observation

        Returns:
            string: Color string.
        """
        if obs == 'rain':
            return ['#032c6a', '#02509d', '#1a72b7',
                    '#4093c7', '#6bb0d7', '#9fcae3'][::-1]

        if obs == 'outTemp':
            # Warming stripes colors
            # @see https://en.wikipedia.org/wiki/Warming_stripes
            return ['#032c6a', '#02509d', '#1a72b7', '#4093c7', '#6bb0d7',
                    '#9fcae3', '#c6dcee', '#dfedf6', '#ffe1d2', '#fcbda3',
                    '#fc9373', '#fa6a48', '#ee3829', '#cd1116', '#a6060d',
                    '#660105']

    def get_calendar_data(self, obs, aggrgate_type, period):
        """
        Returns array of calendar data for use in diagram.

        Args:
            observation (string): The observation
            aggrgate_type (string): Min, max, avg.
            period (obj): Period to use, eg. $year, month, $span

        Returns:
            list: Calendar data.
        """
        diagramUtil = DiagramUtil(SearchList)

        if obs == 'rain':
            day_series = period.rain.series(
                aggregate_type=aggrgate_type,
                aggregate_interval="day",
                time_series='start',
                time_unit='unix_epoch'
            ).round(diagramUtil.get_rounding('rain'))

            days = filter(lambda x: x[1].raw > 0.0, list(zip(day_series.start, day_series.data)))
            rainDays = []

            for day in days:
                rainDays.append({
                    'value': day[1].raw,
                    'day': day[0].format("%Y-%m-%d")
                })

            return rainDays

        if obs == 'outTemp':
            day_series = period.outTemp.series(
                aggregate_type=aggrgate_type,
                aggregate_interval="day",
                time_series='start',
                time_unit='unix_epoch'
            ).round(diagramUtil.get_rounding('rain'))

            days = list(zip(day_series.start, day_series.data))
            tempDays = []

            for day in days:
                tempDays.append({
                    'value': day[1].raw,
                    'day': day[0].format("%Y-%m-%d")
                })

            return tempDays

Reply via email to