mirror of
https://github.com/weewx/weewx.git
synced 2026-04-19 09:06:58 -04:00
Merge branch 'master' into development
# Conflicts: # docs/changes.txt
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
from six.moves import zip
|
||||
|
||||
try:
|
||||
from PIL import ImageFont, ImageColor
|
||||
except ImportError:
|
||||
@@ -188,7 +189,7 @@ def scale(data_min, data_max, prescale=(None, None, None), nsteps=10):
|
||||
return minscale, maxscale, interval
|
||||
|
||||
|
||||
def scaletime(tmin_ts, tmax_ts) :
|
||||
def scaletime(tmin_ts, tmax_ts):
|
||||
"""Picks a time scaling suitable for a time plot.
|
||||
|
||||
tmin_ts, tmax_ts: The time stamps in epoch time around which the times will be picked.
|
||||
@@ -246,16 +247,16 @@ def scaletime(tmin_ts, tmax_ts) :
|
||||
>>> print(to_string(xmin), to_string(xmax), xinc)
|
||||
2013-05-16 17:00:00 PDT (1368748800) 2013-05-17 08:00:00 PDT (1368802800) 7200
|
||||
"""
|
||||
if tmax_ts <= tmin_ts :
|
||||
if tmax_ts <= tmin_ts:
|
||||
raise weeplot.ViolatedPrecondition("scaletime called with tmax <= tmin")
|
||||
|
||||
|
||||
tdelta = tmax_ts - tmin_ts
|
||||
|
||||
|
||||
tmin_dt = datetime.datetime.fromtimestamp(tmin_ts)
|
||||
tmax_dt = datetime.datetime.fromtimestamp(tmax_ts)
|
||||
|
||||
|
||||
if tdelta <= 16 * 3600:
|
||||
if tdelta <= 3*3600:
|
||||
if tdelta <= 3 * 3600:
|
||||
# For time intervals less than 3 hours, use an increment of 15 minutes
|
||||
interval = 900
|
||||
elif tdelta <= 12 * 3600:
|
||||
@@ -272,72 +273,75 @@ def scaletime(tmin_ts, tmax_ts) :
|
||||
stop_dt += datetime.timedelta(hours=1)
|
||||
n_hours = int((tdelta + 3599) / 3600)
|
||||
start_dt = stop_dt - datetime.timedelta(hours=n_hours)
|
||||
|
||||
|
||||
elif tdelta <= 27 * 3600:
|
||||
# A day plot is wanted. A time increment of 3 hours is appropriate
|
||||
interval = 3 * 3600
|
||||
# h is the hour of tmax_dt
|
||||
h = tmax_dt.timetuple()[3]
|
||||
# Subtract off enough to get to the lower 3-hour boundary from tmax:
|
||||
stop_dt = tmax_dt.replace(minute=0, second=0, microsecond=0) - datetime.timedelta(hours = h % 3)
|
||||
stop_dt = tmax_dt.replace(minute=0, second=0, microsecond=0) \
|
||||
- datetime.timedelta(hours=h % 3)
|
||||
# If tmax happens to lie on a 3 hour boundary we don't need to do anything. If not, we need
|
||||
# to round up to the next 3 hour boundary:
|
||||
if tmax_dt > stop_dt:
|
||||
stop_dt += datetime.timedelta(hours=3)
|
||||
# The stop time is one day earlier
|
||||
start_dt = stop_dt - datetime.timedelta(days=1)
|
||||
|
||||
if tdelta == 27 * 3600 :
|
||||
|
||||
if tdelta == 27 * 3600:
|
||||
# A "slightly more than a day plot" is wanted. Start 3 hours earlier:
|
||||
start_dt -= datetime.timedelta(hours=3)
|
||||
|
||||
elif 27 * 3600 < tdelta <= 31 * 24 * 3600 :
|
||||
|
||||
elif 27 * 3600 < tdelta <= 31 * 24 * 3600:
|
||||
# The time scale is between a day and a month. A time increment of one day is appropriate
|
||||
start_dt = tmin_dt.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
stop_dt = tmax_dt.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
|
||||
stop_dt = tmax_dt.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
|
||||
tmax_tt = tmax_dt.timetuple()
|
||||
if tmax_tt[3]!=0 or tmax_tt[4]!=0 :
|
||||
if tmax_tt[3] != 0 or tmax_tt[4] != 0:
|
||||
stop_dt += datetime.timedelta(days=1)
|
||||
|
||||
|
||||
interval = 24 * 3600
|
||||
elif tdelta < 2 * 365.25 * 24 * 3600 :
|
||||
# The time scale is between a month and 2 years. A time increment of a month is appropriate
|
||||
elif tdelta <= 2 * 365.25 * 24 * 3600:
|
||||
# The time scale is between a month and 2 years, inclusive. A time increment of a month
|
||||
# is appropriate
|
||||
start_dt = tmin_dt.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
|
||||
|
||||
(year , mon, day) = tmax_dt.timetuple()[0:3]
|
||||
if day != 1 :
|
||||
|
||||
year, mon, day = tmax_dt.timetuple()[0:3]
|
||||
if day != 1:
|
||||
mon += 1
|
||||
if mon==13 :
|
||||
if mon == 13:
|
||||
mon = 1
|
||||
year += 1
|
||||
stop_dt = datetime.datetime(year, mon, 1)
|
||||
# Average month length:
|
||||
interval = 365.25/12 * 24 * 3600
|
||||
else :
|
||||
# The time scale is between a month and 2 years. A time increment of a year is appropriate
|
||||
interval = 365.25 / 12 * 24 * 3600
|
||||
else:
|
||||
# The time scale is over 2 years. A time increment of six months is appropriate
|
||||
start_dt = tmin_dt.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
|
||||
|
||||
(year , mon, day) = tmax_dt.timetuple()[0:3]
|
||||
if day != 1 or mon !=1 :
|
||||
year, mon, day = tmax_dt.timetuple()[0:3]
|
||||
if day != 1 or mon != 1:
|
||||
day = 1
|
||||
mon = 1
|
||||
year += 1
|
||||
stop_dt = datetime.datetime(year, mon, 1)
|
||||
# Average year length
|
||||
interval = 365.25 * 24 * 3600
|
||||
# Average length of six months
|
||||
interval = 365.25 * 24 * 3600 / 2.0
|
||||
|
||||
# Convert to epoch time stamps
|
||||
start_ts = int(time.mktime(start_dt.timetuple()))
|
||||
stop_ts = int(time.mktime(stop_dt.timetuple()))
|
||||
stop_ts = int(time.mktime(stop_dt.timetuple()))
|
||||
|
||||
return start_ts, stop_ts, interval
|
||||
|
||||
return (start_ts, stop_ts, interval)
|
||||
|
||||
|
||||
class ScaledDraw(object):
|
||||
"""Like an ImageDraw object, but lines are scaled.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, draw, imagebox, scaledbox):
|
||||
"""Initialize a ScaledDraw object.
|
||||
|
||||
@@ -361,14 +365,15 @@ class ScaledDraw(object):
|
||||
urs = scaledbox[1]
|
||||
if urs[1] == lls[1]:
|
||||
pass
|
||||
self.xscale = float(lri[0] - uli[0]) / float(urs[0] - lls[0])
|
||||
self.yscale = -float(lri[1] - uli[1]) / float(urs[1] - lls[1])
|
||||
self.xscale = float(lri[0] - uli[0]) / float(urs[0] - lls[0])
|
||||
self.yscale = -float(lri[1] - uli[1]) / float(urs[1] - lls[1])
|
||||
self.xoffset = int(lri[0] - urs[0] * self.xscale + 0.5)
|
||||
self.yoffset = int(uli[1] - urs[1] * self.yscale + 0.5)
|
||||
|
||||
self.draw = draw
|
||||
|
||||
def line(self, x, y, line_type='solid', marker_type=None, marker_size=8, maxdx=None, **options) :
|
||||
self.draw = draw
|
||||
|
||||
def line(self, x, y, line_type='solid', marker_type=None, marker_size=8, maxdx=None,
|
||||
**options):
|
||||
"""Draw a scaled line on the instance's ImageDraw object.
|
||||
|
||||
x: sequence of x coordinates
|
||||
@@ -391,39 +396,40 @@ class ScaledDraw(object):
|
||||
"""
|
||||
# Break the line up around any nulls or gaps between samples
|
||||
for xy_seq in xy_seq_line(x, y, maxdx):
|
||||
# Create a list with the scaled coordinates...
|
||||
xy_seq_scaled = [(self.xtranslate(xc), self.ytranslate(yc)) for (xc,yc) in xy_seq]
|
||||
# Create a list with the scaled coordinates...
|
||||
xy_seq_scaled = [(self.xtranslate(xc), self.ytranslate(yc)) for (xc, yc) in xy_seq]
|
||||
if line_type == 'solid':
|
||||
# Now pick the appropriate drawing function, depending on the length of the line:
|
||||
if len(xy_seq) == 1 :
|
||||
if len(xy_seq) == 1:
|
||||
self.draw.point(xy_seq_scaled, fill=options['fill'])
|
||||
else :
|
||||
else:
|
||||
self.draw.line(xy_seq_scaled, **options)
|
||||
if marker_type and marker_type.lower().strip() not in ['none', '']:
|
||||
self.marker(xy_seq_scaled, marker_type, marker_size=marker_size, **options)
|
||||
|
||||
|
||||
def marker(self, xy_seq, marker_type, marker_size=10, **options):
|
||||
half_size = marker_size/2
|
||||
marker=marker_type.lower()
|
||||
half_size = marker_size / 2
|
||||
marker = marker_type.lower()
|
||||
for x, y in xy_seq:
|
||||
if marker == 'cross':
|
||||
self.draw.line([(x-half_size, y), (x+half_size, y)], **options)
|
||||
self.draw.line([(x, y-half_size), (x, y+half_size)], **options)
|
||||
self.draw.line([(x - half_size, y), (x + half_size, y)], **options)
|
||||
self.draw.line([(x, y - half_size), (x, y + half_size)], **options)
|
||||
elif marker == 'x':
|
||||
self.draw.line([(x-half_size, y-half_size), (x+half_size, y+half_size)], **options)
|
||||
self.draw.line([(x-half_size, y+half_size), (x+half_size, y-half_size)], **options)
|
||||
self.draw.line([(x - half_size, y - half_size), (x + half_size, y + half_size)],
|
||||
**options)
|
||||
self.draw.line([(x - half_size, y + half_size), (x + half_size, y - half_size)],
|
||||
**options)
|
||||
elif marker == 'circle':
|
||||
self.draw.ellipse([(x-half_size, y-half_size),
|
||||
(x+half_size, y+half_size)], outline=options['fill'])
|
||||
self.draw.ellipse([(x - half_size, y - half_size),
|
||||
(x + half_size, y + half_size)], outline=options['fill'])
|
||||
elif marker == 'box':
|
||||
self.draw.line([(x-half_size, y-half_size),
|
||||
(x+half_size, y-half_size),
|
||||
(x+half_size, y+half_size),
|
||||
(x-half_size, y+half_size),
|
||||
(x-half_size, y-half_size)], **options)
|
||||
|
||||
|
||||
def rectangle(self, box, **options) :
|
||||
self.draw.line([(x - half_size, y - half_size),
|
||||
(x + half_size, y - half_size),
|
||||
(x + half_size, y + half_size),
|
||||
(x - half_size, y + half_size),
|
||||
(x - half_size, y - half_size)], **options)
|
||||
|
||||
def rectangle(self, box, **options):
|
||||
"""Draw a scaled rectangle.
|
||||
|
||||
box: A pair of 2-way tuples, containing coordinates of opposing corners
|
||||
@@ -431,33 +437,34 @@ class ScaledDraw(object):
|
||||
|
||||
options: passed on to draw.rectangle. Usually contains 'fill' (the color)
|
||||
"""
|
||||
box_scaled = [(coord[0]*self.xscale + self.xoffset + 0.5, coord[1]*self.yscale + self.yoffset + 0.5) for coord in box]
|
||||
box_scaled = [(coord[0] * self.xscale + self.xoffset + 0.5,
|
||||
coord[1] * self.yscale + self.yoffset + 0.5) for coord in box]
|
||||
self.draw.rectangle(box_scaled, **options)
|
||||
|
||||
|
||||
def vector(self, x, vec, vector_rotate, **options):
|
||||
|
||||
if vec is None:
|
||||
|
||||
if vec is None:
|
||||
return
|
||||
xstart_scaled = self.xtranslate(x)
|
||||
ystart_scaled = self.ytranslate(0)
|
||||
|
||||
|
||||
vecinc_scaled = vec * self.yscale
|
||||
|
||||
|
||||
if vector_rotate:
|
||||
vecinc_scaled *= complex(math.cos(math.radians(vector_rotate)),
|
||||
math.sin(math.radians(vector_rotate)))
|
||||
|
||||
|
||||
# Subtract off the x increment because the x-axis
|
||||
# *increases* to the right, unlike y, which increases
|
||||
# downwards
|
||||
xend_scaled = xstart_scaled - vecinc_scaled.real
|
||||
yend_scaled = ystart_scaled + vecinc_scaled.imag
|
||||
|
||||
|
||||
self.draw.line(((xstart_scaled, ystart_scaled), (xend_scaled, yend_scaled)), **options)
|
||||
|
||||
def xtranslate(self, x):
|
||||
return int(x * self.xscale + self.xoffset + 0.5)
|
||||
|
||||
|
||||
def ytranslate(self, y):
|
||||
return int(y * self.yscale + self.yoffset + 0.5)
|
||||
|
||||
@@ -509,7 +516,7 @@ def xy_seq_line(x, y, maxdx=None):
|
||||
[(0, 0), (1, 10), (2, 20), (3, 30)]
|
||||
[(5.1, 50), (6, 60), (7, 70), (8, 80), (9, 90)]
|
||||
"""
|
||||
|
||||
|
||||
line = []
|
||||
last_x = None
|
||||
for xy in zip(x, y):
|
||||
@@ -526,6 +533,7 @@ def xy_seq_line(x, y, maxdx=None):
|
||||
if len(line):
|
||||
yield line
|
||||
|
||||
|
||||
def pickLabelFormat(increment):
|
||||
"""Pick an appropriate label format for the given increment.
|
||||
|
||||
@@ -541,16 +549,17 @@ def pickLabelFormat(increment):
|
||||
"""
|
||||
|
||||
i_log = math.log10(increment)
|
||||
if i_log < 0 :
|
||||
if i_log < 0:
|
||||
i_log = abs(i_log)
|
||||
decimal_places = int(i_log)
|
||||
if i_log != decimal_places :
|
||||
if i_log != decimal_places:
|
||||
decimal_places += 1
|
||||
else :
|
||||
else:
|
||||
decimal_places = 0
|
||||
|
||||
|
||||
return "%%.%df" % decimal_places
|
||||
|
||||
|
||||
def get_font_handle(fontpath, *args):
|
||||
"""Get a handle for a font path, caching the results"""
|
||||
|
||||
@@ -563,21 +572,24 @@ def get_font_handle(fontpath, *args):
|
||||
return get_font_handle.fontCache[font_key]
|
||||
|
||||
font = None
|
||||
if fontpath_str is not None :
|
||||
try :
|
||||
if fontpath_str is not None:
|
||||
try:
|
||||
if fontpath_str.endswith('.ttf'):
|
||||
font = ImageFont.truetype(fontpath_str, *args)
|
||||
else :
|
||||
else:
|
||||
font = ImageFont.load_path(fontpath_str)
|
||||
except IOError :
|
||||
except IOError:
|
||||
pass
|
||||
|
||||
if font is None :
|
||||
|
||||
if font is None:
|
||||
font = ImageFont.load_default()
|
||||
if font is not None :
|
||||
if font is not None:
|
||||
get_font_handle.fontCache[font_key] = font
|
||||
return font
|
||||
get_font_handle.fontCache={}
|
||||
return font
|
||||
|
||||
|
||||
get_font_handle.fontCache = {}
|
||||
|
||||
|
||||
def _rel_approx_equal(x, y, rel=1e-7):
|
||||
"""Relative test for equality.
|
||||
@@ -598,7 +610,7 @@ def _rel_approx_equal(x, y, rel=1e-7):
|
||||
>>> rel_approx_equal(1e8, 1e8+1e-3)
|
||||
True
|
||||
"""
|
||||
return abs(x-y) <= rel*max(abs(x), abs(y))
|
||||
return abs(x - y) <= rel * max(abs(x), abs(y))
|
||||
|
||||
|
||||
def tobgr(x):
|
||||
@@ -612,8 +624,8 @@ def tobgr(x):
|
||||
if x.startswith('0x'):
|
||||
return int(x, 0)
|
||||
try:
|
||||
(r,g,b) = ImageColor.getrgb(x)
|
||||
return r + g*256 + b*256*256
|
||||
r, g, b = ImageColor.getrgb(x)
|
||||
return r + g * 256 + b * 256 * 256
|
||||
except ValueError:
|
||||
try:
|
||||
return int(x)
|
||||
@@ -622,9 +634,9 @@ def tobgr(x):
|
||||
"Colors must be specified as 0xBBGGRR, #RRGGBB, or standard color names." % x)
|
||||
return x
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
|
||||
if not doctest.testmod().failed:
|
||||
print("PASSED")
|
||||
|
||||
|
||||
@@ -32,14 +32,14 @@ Example:
|
||||
[CheetahGenerator]
|
||||
# How to specify search list extensions:
|
||||
search_list_extensions = user.forecast.ForecastVariables, user.extstats.ExtStatsVariables
|
||||
encoding = html_entities # html_entities, utf8, strict_ascii, or normalized_ascii
|
||||
encoding = html_entities
|
||||
[[SummaryByMonth]] # period
|
||||
[[[NOAA_month]]] # report
|
||||
encoding = utf8
|
||||
encoding = normalized_ascii
|
||||
template = NOAA-YYYY-MM.txt.tmpl
|
||||
[[SummaryByYear]]
|
||||
[[[NOAA_year]]]]
|
||||
encoding = utf8
|
||||
encoding = normalized_ascii
|
||||
template = NOAA-YYYY.txt.tmpl
|
||||
[[ToDate]]
|
||||
[[[day]]]
|
||||
@@ -335,7 +335,7 @@ class CheetahGenerator(weewx.reportengine.ReportGenerator):
|
||||
normalized = unicodedata.normalize('NFD', unicode_string)
|
||||
byte_string = normalized.encode('ascii', 'ignore')
|
||||
else:
|
||||
byte_string = unicode_string.encode('utf8')
|
||||
byte_string = unicode_string.encode(encoding)
|
||||
|
||||
# Open in binary mode. We are writing a byte-string, not a string
|
||||
with open(tmpname, mode='wb') as fd:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2009-2020 Tom Keffer <tkeffer@gmail.com>
|
||||
# Copyright (c) 2009-2021 Tom Keffer <tkeffer@gmail.com>
|
||||
#
|
||||
# See the file LICENSE.txt for your full rights.
|
||||
#
|
||||
@@ -32,7 +32,7 @@ from weewx.crc16 import crc16
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
DRIVER_NAME = 'Vantage'
|
||||
DRIVER_VERSION = '3.2.1'
|
||||
DRIVER_VERSION = '3.2.2'
|
||||
|
||||
|
||||
def loader(config_dict, engine):
|
||||
@@ -107,12 +107,13 @@ class BaseWrapper(object):
|
||||
if _resp == b'\n\r':
|
||||
log.debug("Rude wake up of console successful")
|
||||
return
|
||||
print("Unable to wake up console... sleeping")
|
||||
time.sleep(self.wait_before_retry)
|
||||
print("Unable to wake up console... retrying")
|
||||
except weewx.WeeWxIOError:
|
||||
pass
|
||||
|
||||
log.debug("Retry #%d failed", count)
|
||||
print("Unable to wake up console... sleeping")
|
||||
time.sleep(self.wait_before_retry)
|
||||
print("Unable to wake up console... retrying")
|
||||
|
||||
log.error("Unable to wake up console")
|
||||
raise weewx.WakeupError("Unable to wake up Vantage console")
|
||||
|
||||
@@ -717,7 +717,7 @@ class StdPWSWeather(StdRESTful):
|
||||
"""Specialized version of the Ambient protocol for PWSWeather"""
|
||||
|
||||
# The URL used by PWSWeather:
|
||||
archive_url = "http://www.pwsweather.com/pwsupdate/pwsupdate.php"
|
||||
archive_url = "https://www.pwsweather.com/pwsupdate/pwsupdate.php"
|
||||
|
||||
def __init__(self, engine, config_dict):
|
||||
super(StdPWSWeather, self).__init__(engine, config_dict)
|
||||
@@ -756,7 +756,7 @@ class StdWOW(StdRESTful):
|
||||
"""
|
||||
|
||||
# The URL used by WOW:
|
||||
archive_url = "http://wow.metoffice.gov.uk/automaticreading"
|
||||
archive_url = "https://wow.metoffice.gov.uk/automaticreading"
|
||||
|
||||
def __init__(self, engine, config_dict):
|
||||
super(StdWOW, self).__init__(engine, config_dict)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
TEST MONTHLY CLIMATOLOGICAL SUMMARY for Jan 2010
|
||||
|
||||
|
||||
NAME: Ĺōćāţĩőń with UTF8 characters
|
||||
NAME: Location with UTF8 characters
|
||||
ELEV: 328 feet LAT: 45-41.16 N LONG: 121-33.96 W
|
||||
|
||||
|
||||
TEMPERATURE (°F), RAIN (in), WIND SPEED (mph)
|
||||
TEMPERATURE (F), RAIN (in), WIND SPEED (mph)
|
||||
|
||||
HEAT COOL AVG
|
||||
MEAN DEG DEG WIND DOM
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
TEST MONTHLY CLIMATOLOGICAL SUMMARY for Feb 2010
|
||||
|
||||
|
||||
NAME: Ĺōćāţĩőń with UTF8 characters
|
||||
NAME: Location with UTF8 characters
|
||||
ELEV: 328 feet LAT: 45-41.16 N LONG: 121-33.96 W
|
||||
|
||||
|
||||
TEMPERATURE (°F), RAIN (in), WIND SPEED (mph)
|
||||
TEMPERATURE (F), RAIN (in), WIND SPEED (mph)
|
||||
|
||||
HEAT COOL AVG
|
||||
MEAN DEG DEG WIND DOM
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
TEST MONTHLY CLIMATOLOGICAL SUMMARY for Mar 2010
|
||||
|
||||
|
||||
NAME: Ĺōćāţĩőń with UTF8 characters
|
||||
NAME: Location with UTF8 characters
|
||||
ELEV: 328 feet LAT: 45-41.16 N LONG: 121-33.96 W
|
||||
|
||||
|
||||
TEMPERATURE (°F), RAIN (in), WIND SPEED (mph)
|
||||
TEMPERATURE (F), RAIN (in), WIND SPEED (mph)
|
||||
|
||||
HEAT COOL AVG
|
||||
MEAN DEG DEG WIND DOM
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
TEST MONTHLY CLIMATOLOGICAL SUMMARY for Apr 2010
|
||||
|
||||
|
||||
NAME: Ĺōćāţĩőń with UTF8 characters
|
||||
NAME: Location with UTF8 characters
|
||||
ELEV: 328 feet LAT: 45-41.16 N LONG: 121-33.96 W
|
||||
|
||||
|
||||
TEMPERATURE (°F), RAIN (in), WIND SPEED (mph)
|
||||
TEMPERATURE (F), RAIN (in), WIND SPEED (mph)
|
||||
|
||||
HEAT COOL AVG
|
||||
MEAN DEG DEG WIND DOM
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
TEST MONTHLY CLIMATOLOGICAL SUMMARY for May 2010
|
||||
|
||||
|
||||
NAME: Ĺōćāţĩőń with UTF8 characters
|
||||
NAME: Location with UTF8 characters
|
||||
ELEV: 328 feet LAT: 45-41.16 N LONG: 121-33.96 W
|
||||
|
||||
|
||||
TEMPERATURE (°F), RAIN (in), WIND SPEED (mph)
|
||||
TEMPERATURE (F), RAIN (in), WIND SPEED (mph)
|
||||
|
||||
HEAT COOL AVG
|
||||
MEAN DEG DEG WIND DOM
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
TEST MONTHLY CLIMATOLOGICAL SUMMARY for Jun 2010
|
||||
|
||||
|
||||
NAME: Ĺōćāţĩőń with UTF8 characters
|
||||
NAME: Location with UTF8 characters
|
||||
ELEV: 328 feet LAT: 45-41.16 N LONG: 121-33.96 W
|
||||
|
||||
|
||||
TEMPERATURE (°F), RAIN (in), WIND SPEED (mph)
|
||||
TEMPERATURE (F), RAIN (in), WIND SPEED (mph)
|
||||
|
||||
HEAT COOL AVG
|
||||
MEAN DEG DEG WIND DOM
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
TEST MONTHLY CLIMATOLOGICAL SUMMARY for Jul 2010
|
||||
|
||||
|
||||
NAME: Ĺōćāţĩőń with UTF8 characters
|
||||
NAME: Location with UTF8 characters
|
||||
ELEV: 328 feet LAT: 45-41.16 N LONG: 121-33.96 W
|
||||
|
||||
|
||||
TEMPERATURE (°F), RAIN (in), WIND SPEED (mph)
|
||||
TEMPERATURE (F), RAIN (in), WIND SPEED (mph)
|
||||
|
||||
HEAT COOL AVG
|
||||
MEAN DEG DEG WIND DOM
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
TEST MONTHLY CLIMATOLOGICAL SUMMARY for Aug 2010
|
||||
|
||||
|
||||
NAME: Ĺōćāţĩőń with UTF8 characters
|
||||
NAME: Location with UTF8 characters
|
||||
ELEV: 328 feet LAT: 45-41.16 N LONG: 121-33.96 W
|
||||
|
||||
|
||||
TEMPERATURE (°F), RAIN (in), WIND SPEED (mph)
|
||||
TEMPERATURE (F), RAIN (in), WIND SPEED (mph)
|
||||
|
||||
HEAT COOL AVG
|
||||
MEAN DEG DEG WIND DOM
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
TEST MONTHLY CLIMATOLOGICAL SUMMARY for Sep 2010
|
||||
|
||||
|
||||
NAME: Ĺōćāţĩőń with UTF8 characters
|
||||
NAME: Location with UTF8 characters
|
||||
ELEV: 328 feet LAT: 45-41.16 N LONG: 121-33.96 W
|
||||
|
||||
|
||||
TEMPERATURE (°F), RAIN (in), WIND SPEED (mph)
|
||||
TEMPERATURE (F), RAIN (in), WIND SPEED (mph)
|
||||
|
||||
HEAT COOL AVG
|
||||
MEAN DEG DEG WIND DOM
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
TEST MONTHLY CLIMATOLOGICAL SUMMARY for Jan 2010
|
||||
|
||||
|
||||
NAME: Ĺōćāţĩőń with UTF8 characters
|
||||
NAME: Location with UTF8 characters
|
||||
ELEV: 100 meters LAT: 45-41.16 N LONG: 121-33.96 W
|
||||
|
||||
|
||||
TEMPERATURE (°C), RAIN (mm), WIND SPEED (kph)
|
||||
TEMPERATURE (C), RAIN (mm), WIND SPEED (kph)
|
||||
|
||||
HEAT COOL AVG
|
||||
MEAN DEG DEG WIND DOM
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
TEST MONTHLY CLIMATOLOGICAL SUMMARY for Feb 2010
|
||||
|
||||
|
||||
NAME: Ĺōćāţĩőń with UTF8 characters
|
||||
NAME: Location with UTF8 characters
|
||||
ELEV: 100 meters LAT: 45-41.16 N LONG: 121-33.96 W
|
||||
|
||||
|
||||
TEMPERATURE (°C), RAIN (mm), WIND SPEED (kph)
|
||||
TEMPERATURE (C), RAIN (mm), WIND SPEED (kph)
|
||||
|
||||
HEAT COOL AVG
|
||||
MEAN DEG DEG WIND DOM
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
TEST MONTHLY CLIMATOLOGICAL SUMMARY for Mar 2010
|
||||
|
||||
|
||||
NAME: Ĺōćāţĩőń with UTF8 characters
|
||||
NAME: Location with UTF8 characters
|
||||
ELEV: 100 meters LAT: 45-41.16 N LONG: 121-33.96 W
|
||||
|
||||
|
||||
TEMPERATURE (°C), RAIN (mm), WIND SPEED (kph)
|
||||
TEMPERATURE (C), RAIN (mm), WIND SPEED (kph)
|
||||
|
||||
HEAT COOL AVG
|
||||
MEAN DEG DEG WIND DOM
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
TEST MONTHLY CLIMATOLOGICAL SUMMARY for Apr 2010
|
||||
|
||||
|
||||
NAME: Ĺōćāţĩőń with UTF8 characters
|
||||
NAME: Location with UTF8 characters
|
||||
ELEV: 100 meters LAT: 45-41.16 N LONG: 121-33.96 W
|
||||
|
||||
|
||||
TEMPERATURE (°C), RAIN (mm), WIND SPEED (kph)
|
||||
TEMPERATURE (C), RAIN (mm), WIND SPEED (kph)
|
||||
|
||||
HEAT COOL AVG
|
||||
MEAN DEG DEG WIND DOM
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
TEST MONTHLY CLIMATOLOGICAL SUMMARY for May 2010
|
||||
|
||||
|
||||
NAME: Ĺōćāţĩőń with UTF8 characters
|
||||
NAME: Location with UTF8 characters
|
||||
ELEV: 100 meters LAT: 45-41.16 N LONG: 121-33.96 W
|
||||
|
||||
|
||||
TEMPERATURE (°C), RAIN (mm), WIND SPEED (kph)
|
||||
TEMPERATURE (C), RAIN (mm), WIND SPEED (kph)
|
||||
|
||||
HEAT COOL AVG
|
||||
MEAN DEG DEG WIND DOM
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
TEST MONTHLY CLIMATOLOGICAL SUMMARY for Jun 2010
|
||||
|
||||
|
||||
NAME: Ĺōćāţĩőń with UTF8 characters
|
||||
NAME: Location with UTF8 characters
|
||||
ELEV: 100 meters LAT: 45-41.16 N LONG: 121-33.96 W
|
||||
|
||||
|
||||
TEMPERATURE (°C), RAIN (mm), WIND SPEED (kph)
|
||||
TEMPERATURE (C), RAIN (mm), WIND SPEED (kph)
|
||||
|
||||
HEAT COOL AVG
|
||||
MEAN DEG DEG WIND DOM
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
TEST MONTHLY CLIMATOLOGICAL SUMMARY for Jul 2010
|
||||
|
||||
|
||||
NAME: Ĺōćāţĩőń with UTF8 characters
|
||||
NAME: Location with UTF8 characters
|
||||
ELEV: 100 meters LAT: 45-41.16 N LONG: 121-33.96 W
|
||||
|
||||
|
||||
TEMPERATURE (°C), RAIN (mm), WIND SPEED (kph)
|
||||
TEMPERATURE (C), RAIN (mm), WIND SPEED (kph)
|
||||
|
||||
HEAT COOL AVG
|
||||
MEAN DEG DEG WIND DOM
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
TEST MONTHLY CLIMATOLOGICAL SUMMARY for Aug 2010
|
||||
|
||||
|
||||
NAME: Ĺōćāţĩőń with UTF8 characters
|
||||
NAME: Location with UTF8 characters
|
||||
ELEV: 100 meters LAT: 45-41.16 N LONG: 121-33.96 W
|
||||
|
||||
|
||||
TEMPERATURE (°C), RAIN (mm), WIND SPEED (kph)
|
||||
TEMPERATURE (C), RAIN (mm), WIND SPEED (kph)
|
||||
|
||||
HEAT COOL AVG
|
||||
MEAN DEG DEG WIND DOM
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
TEST MONTHLY CLIMATOLOGICAL SUMMARY for Sep 2010
|
||||
|
||||
|
||||
NAME: Ĺōćāţĩőń with UTF8 characters
|
||||
NAME: Location with UTF8 characters
|
||||
ELEV: 100 meters LAT: 45-41.16 N LONG: 121-33.96 W
|
||||
|
||||
|
||||
TEMPERATURE (°C), RAIN (mm), WIND SPEED (kph)
|
||||
TEMPERATURE (C), RAIN (mm), WIND SPEED (kph)
|
||||
|
||||
HEAT COOL AVG
|
||||
MEAN DEG DEG WIND DOM
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
# Reports that summarize "by month"
|
||||
#
|
||||
[[[by_month]]]
|
||||
encoding = utf8
|
||||
encoding = normalized_ascii
|
||||
template = bymonth-YYYY-MM.txt.tmpl
|
||||
|
||||
[[SummaryByYear]]
|
||||
|
||||
@@ -7,13 +7,26 @@ The utility wee_database has new option --add-column and --rename-column for
|
||||
adding and renaming columns in the database.
|
||||
|
||||
|
||||
4.4.1 MM/DD/YYYY
|
||||
|
||||
Changed NOAA reports to use the 'normalized_ascii' encoding instead of 'utf8'
|
||||
(which did not display correctly for most browsers). Fixes issue #646.
|
||||
|
||||
Plots longer than 2 years use a 6 month time increment.
|
||||
|
||||
Uploads to PWSWeather and WOW now use HTTPS. Fixes issue #650.
|
||||
|
||||
Fixed bug that prevented the Vantage driver from waiting before a wakeup retry.
|
||||
Thanks to user Les Niles!
|
||||
|
||||
|
||||
4.4.0 01/30/2021
|
||||
|
||||
StdWXCalculate can now do calculations for only LOOP packets, only archive
|
||||
records, or both. PR #630. Thanks to user g-eddy!
|
||||
|
||||
Introduced aggregate types "avg_ge" and "avg_le". PR #631. Thanks again to user
|
||||
g-eddy!
|
||||
Introduced aggregate types "avg_ge" and "avg_le". PR #631. Thanks to user
|
||||
edi-x!
|
||||
|
||||
NOAA reports now use a 'utf8' encoding instead of 'strict_ascii'. This will only
|
||||
affect new installations. Fixes issue #644.
|
||||
|
||||
@@ -1633,19 +1633,20 @@ db_manager.getSql("SELECT SUM(rain) FROM %s "\
|
||||
# The CheetahGenerator creates files from templates. This section
|
||||
# specifies which files will be generated from which template.
|
||||
|
||||
# Possible encodings are 'html_entities', 'utf8', 'strict_ascii', or 'normalized_ascii'
|
||||
# Possible encodings include 'html_entities', 'strict_ascii', 'normalized_ascii',
|
||||
# as well as those listed in https://docs.python.org/3/library/codecs.html#standard-encodings
|
||||
encoding = html_entities
|
||||
|
||||
[[SummaryByMonth]]
|
||||
# Reports that summarize "by month"
|
||||
[[[NOAA_month]]]
|
||||
encoding = utf8
|
||||
encoding = normalized_ascii
|
||||
template = NOAA/NOAA-%Y-%m.txt.tmpl
|
||||
|
||||
[[SummaryByYear]]
|
||||
# Reports that summarize "by year"
|
||||
[[[NOAA_year]]]
|
||||
encoding = utf8
|
||||
encoding = normalized_ascii
|
||||
template = NOAA/NOAA-%Y.txt.tmpl
|
||||
|
||||
[[ToDate]]
|
||||
@@ -1709,7 +1710,7 @@ db_manager.getSql("SELECT SUM(rain) FROM %s "\
|
||||
[[SummaryByYear]]
|
||||
# Reports that summarize "by year"
|
||||
[[[NOAA_year]]]
|
||||
encoding = utf8
|
||||
encoding = normalized_ascii
|
||||
template = NOAA/NOAA-%Y.txt.tmpl
|
||||
</pre>
|
||||
|
||||
@@ -1738,7 +1739,7 @@ $record.dateTime $record.outTemp $record.outHumidity
|
||||
[[SummaryByMonth]]
|
||||
# Reports that summarize "by month"
|
||||
[[[NOAA_month]]]
|
||||
encoding = utf8
|
||||
encoding = normalized_ascii
|
||||
template = NOAA/NOAA-%Y-%m.txt.tmpl
|
||||
</pre>
|
||||
|
||||
@@ -1767,7 +1768,7 @@ $record.dateTime $record.outTemp $record.outHumidity
|
||||
[[SummaryByDay]]
|
||||
# Reports that summarize "by day"
|
||||
[[[NOAA_day]]]
|
||||
encoding = utf8
|
||||
encoding = normalized_ascii
|
||||
template = NOAA/NOAA-%Y-%m-%d.txt.tmpl
|
||||
</pre>
|
||||
|
||||
@@ -3498,7 +3499,8 @@ class MyStats(SearchList): # 1
|
||||
# This section is used by the generator CheetahGenerator, and specifies
|
||||
# which files are to be generated from which template.
|
||||
|
||||
# Possible encodings are 'html_entities', 'utf8', 'strict_ascii', or 'normalized_ascii'
|
||||
# Possible encodings include 'html_entities', 'strict_ascii', 'normalized_ascii',
|
||||
# as well as those listed in https://docs.python.org/3/library/codecs.html#standard-encodings
|
||||
encoding = html_entities
|
||||
<span class="highlight">search_list_extensions = user.stats.MyStats</span>
|
||||
|
||||
@@ -5909,8 +5911,10 @@ growing_base = 50.0, degree_F</pre>
|
||||
|
||||
<p>
|
||||
As Cheetah goes through the template, it substitutes strings for all tag values. This option controls which
|
||||
encoding to use for the new strings. The encoding can be chosen on a per file basis. There are 3 possible
|
||||
choices:
|
||||
encoding to use for the new strings. The encoding can be chosen on a per file basis. All of the encodings
|
||||
listed in the Python documentation
|
||||
<a href="https://docs.python.org/3/library/codecs.html#standard-encodings"><em>Standard Encodings</em></a>
|
||||
are available, as well as these WeeWX-specific encodings:
|
||||
</p>
|
||||
<table class="indent">
|
||||
<tbody>
|
||||
@@ -5924,10 +5928,6 @@ growing_base = 50.0, degree_F</pre>
|
||||
represented as <span class="code">&#176;</span>)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="code first_col">utf8</td>
|
||||
<td>Non 7-bit characters will be represented in UTF-8.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="code first_col">strict_ascii</td>
|
||||
<td>Non 7-bit characters will be ignored.</td>
|
||||
@@ -5939,7 +5939,9 @@ growing_base = 50.0, degree_F</pre>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>
|
||||
The encoding <span class="code">html_entities</span> is the default.
|
||||
The encoding <span class="code">html_entities</span> is the default. Other common choices are <span
|
||||
class="code">utf8</span>, <span class="code">cp1252</span> (<em>a.k.a.</em> Windows-1252), and <span
|
||||
class="code">latin1</span>.
|
||||
</p>
|
||||
|
||||
<p class="config_option" id="option_template">template</p>
|
||||
|
||||
@@ -541,7 +541,7 @@ Version: 4.4
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text_highlight" rowspan="14">Oregon Scientific</td>
|
||||
<td class="text_highlight" rowspan="12">Oregon Scientific</td>
|
||||
<td>WMR88</td>
|
||||
<td>USB</td>
|
||||
<td class="code">pyusb</td>
|
||||
@@ -670,7 +670,7 @@ Version: 4.4
|
||||
<td>Tested</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text_highlight" rowspan="3">Radio Shack</td>
|
||||
<td class="text_highlight" rowspan="2">Radio Shack</td>
|
||||
<td>63-256</td>
|
||||
<td>USB</td>
|
||||
<td class="code">pyusb</td>
|
||||
|
||||
@@ -188,16 +188,24 @@ sudo apt-get install weewx</pre>
|
||||
Z : start a shell to examine the situation
|
||||
The default action is to keep your current version.
|
||||
*** weewx.conf (Y/I/N/O/D/Z) [default=N] ?</pre>
|
||||
<p>Choosing <span class='code'>I</span> (install the new version) will place the previous configuration in <span
|
||||
class='code'>/etc/weewx/weewx.conf.dpkg-old</span> where it can be compared with the new version <span
|
||||
class='code'>/etc/weewx/weewx.conf</span>
|
||||
|
||||
<p>
|
||||
Choosing <span class="code">Y</span> or <span class='code'>I</span> (install the new version) will place
|
||||
your old configuration in <span class='code'>/etc/weewx/weewx.conf.dpkg-old</span>, where it can be compared
|
||||
with the new version in <span class='code'>/etc/weewx/weewx.conf</span>.
|
||||
</p>
|
||||
|
||||
<p>Choosing <span class='code'>O</span> (keep the current version) will place the new configuration in <span
|
||||
class='code'>/etc/weewx/weewx.conf.dpkg-new</span> where it can be compared with the old version <span
|
||||
class='code'>/etc/weewx/weewx.conf</span>
|
||||
<p>
|
||||
Choosing <span class="code">N</span> or <span class='code'>O</span> (keep the current version) will place
|
||||
the new configuration in <span class='code'>/etc/weewx/weewx.conf.X.Y.Z</span>, where <span class="code">X.Y.Z</span>
|
||||
is the new version number. It can then be compared with your old version which will be in <span
|
||||
class='code'>/etc/weewx/weewx.conf</span>.
|
||||
</p>
|
||||
|
||||
<p class="note">
|
||||
The vast majority of the time you will want to choose <span class="code">N</span> (the default), and keep
|
||||
your old version of <span class="code">weewx.conf</span>.
|
||||
</p>
|
||||
|
||||
<h1><a id="Upgrading_using_RPM_package">Upgrading using RPM package</a></h1>
|
||||
|
||||
|
||||
@@ -56,19 +56,20 @@
|
||||
|
||||
[CheetahGenerator]
|
||||
|
||||
# Possible encodings are 'html_entities', 'utf8', 'strict_ascii', or 'normalized_ascii'
|
||||
# Possible encodings include 'html_entities', 'strict_ascii', 'normalized_ascii',
|
||||
# as well as those listed in https://docs.python.org/3/library/codecs.html#standard-encodings
|
||||
encoding = html_entities
|
||||
|
||||
[[SummaryByMonth]]
|
||||
# Reports that summarize "by month"
|
||||
[[[NOAA_month]]]
|
||||
encoding = utf8
|
||||
encoding = normalized_ascii
|
||||
template = NOAA/NOAA-%Y-%m.txt.tmpl
|
||||
|
||||
[[SummaryByYear]]
|
||||
# Reports that summarize "by year"
|
||||
[[[NOAA_year]]]
|
||||
encoding = utf8
|
||||
encoding = normalized_ascii
|
||||
template = NOAA/NOAA-%Y.txt.tmpl
|
||||
|
||||
[[ToDate]]
|
||||
|
||||
@@ -25,19 +25,20 @@
|
||||
|
||||
[CheetahGenerator]
|
||||
|
||||
# Possible encodings are 'html_entities', 'utf8', 'strict_ascii', or 'normalized_ascii'
|
||||
# Possible encodings include 'html_entities', 'utf8', 'strict_ascii', or 'normalized_ascii',
|
||||
# as well as those listed in https://docs.python.org/3/library/codecs.html#standard-encodings
|
||||
encoding = html_entities
|
||||
|
||||
[[SummaryByMonth]]
|
||||
# Reports that summarize "by month"
|
||||
[[[NOAA_month]]]
|
||||
encoding = utf8
|
||||
encoding = normalized_ascii
|
||||
template = NOAA/NOAA-%Y-%m.txt.tmpl
|
||||
|
||||
[[SummaryByYear]]
|
||||
# Reports that summarize "by year"
|
||||
[[[NOAA_year]]]
|
||||
encoding = utf8
|
||||
encoding = normalized_ascii
|
||||
template = NOAA/NOAA-%Y.txt.tmpl
|
||||
|
||||
[[ToDate]]
|
||||
|
||||
Reference in New Issue
Block a user