diff --git a/CHANGES.txt b/CHANGES.txt index e6cf8969..1213da1e 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,7 +1,10 @@ CHANGE HISTORY -------------------------------- -1.10.0a6 02/26/11 +1.10.0 03/29/11 + +Added extensive almanac information if the optional package 'pyephem' has been +installed Added a weewx "favorite icon" favicon.ico that displays in your browser toolbar. diff --git a/MANIFEST b/MANIFEST index 70183a75..086b446f 100644 --- a/MANIFEST +++ b/MANIFEST @@ -19,7 +19,6 @@ bin/user/schemas.py bin/weeplot/__init__.py bin/weeplot/genplot.py bin/weeplot/utilities.py -bin/weeutil/Almanac.py bin/weeutil/Moon.py bin/weeutil/Sun.py bin/weeutil/__init__.py @@ -29,6 +28,7 @@ bin/weeutil/weeutil.py bin/weewx/VantagePro.py bin/weewx/__init__.py bin/weewx/accum.py +bin/weewx/almanac.py bin/weewx/archive.py bin/weewx/crc16.py bin/weewx/filegenerator.py diff --git a/bin/weewx/__init__.py b/bin/weewx/__init__.py index ffaf820e..8bc16415 100644 --- a/bin/weewx/__init__.py +++ b/bin/weewx/__init__.py @@ -12,7 +12,7 @@ """ import time -__version__="1.10.0a6" +__version__="1.10.0" # Holds the program launch time in unix epoch seconds: # Useful for calculating 'uptime.' diff --git a/bin/weeutil/Almanac.py b/bin/weewx/almanac.py similarity index 52% rename from bin/weeutil/Almanac.py rename to bin/weewx/almanac.py index ccc0106c..607c9ead 100644 --- a/bin/weeutil/Almanac.py +++ b/bin/weewx/almanac.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2009 Tom Keffer +# Copyright (c) 2009, 2011 Tom Keffer # # See the file LICENSE.txt for your full rights. # @@ -12,47 +12,23 @@ This module can optionally use PyEphem, which offers high quality astronomical calculations. See http://rhodesmill.org/pyephem. """ -#=============================================================================== -# Architectural notes -# -# Unfortunately, sunrise and sunset have to be calculated dynamically when -# using ephem because of its unfortunate design decision to change the -# state of the body when calling next_rising() or next_setting(). This leads -# to some complications in the class BodyWrapper -#=============================================================================== - import calendar import time import sys -import Moon +import weeutil.Moon +import weewx.units # If the user has installed ephem, use it. Otherwise, fall back to the weeutil algorithms: try: import ephem import math except: - import Sun + import weeutil.Sun class Almanac(object): """Almanac data. - time_ts: A timestamp within the date for which sunrise/sunset is desired. - - lat, lon: Location for which sunrise/sunset is desired. - - altitude: Elevation in **meters**. [Optional. Default is 0 (sea level)] - - temperature: The temperature in **degrees Celsius**. [Optional. Default is 15.0] - - pressure: The atmospheric pressure in **mBars**. [Optional. Default is 1010] - - moon_phases: An array of 8 strings with descriptions of the moon - phase. [optional. If not given, then weeutil.Moon.moon_phases will be used] - - timeformat: A strftime style format to be used to format sunrise and sunset. - [optional. If not given, then "%H:%M" will be used. - ATTRIBUTES. As a minimum, the following attributes are available: @@ -62,58 +38,60 @@ class Almanac(object): moon_phase: A description of the moon phase(eg. "new moon", Waxing crescent", etc.) moon_fullness: Percent fullness of the moon (0=new moon, 100=full moon) - If the module 'ephem' is used, many other attributes are available. + If the module 'ephem' is used, them many other attributes are available. + Here are a few examples: - sun.transit: Time of transit (sun over meridian) - sun.previous_sunrise: Time of last sunrise + sun.rise: Time upper limb of sun will rise above the horizon today in unix epoch time + sun.transit: Time of transit today (sun over meridian) in unix epoch time + sun.previous_sunrise: Time of last sunrise in unix epoch time sun.az: Azimuth (in degrees) of sun sun.alt: Altitude (in degrees) of sun - mars.rise: Time of mars rising + mars.rise: Time when upper limb of mars will rise above horizon today in unix epoch time mars.ra: Right ascension of mars etc. EXAMPLES: >>> t = time.mktime((2009, 3, 27, 12, 0, 0, 0, 0, -1)) - >>> print weeutil.timestamp_to_string(t) + >>> print timestamp_to_string(t) 2009-03-27 12:00:00 PDT (1238180400) >>> almanac = Almanac(t, 46.0, -122.0) - Test backwards compatiblity with attributes 'sunrise' and 'sunset' - >>> print "Sunrise, sunset:", almanac.sunrise, almanac.sunset - Sunrise, sunset: 06:56 19:30 - - Test backwards compatiblity with attribute 'moon_fullness': + Test backwards compatibility with attribute 'moon_fullness': >>> print "Fullness of the moon (rounded) is %.2f%% [%s]" % (almanac.moon_fullness, almanac.moon_phase) Fullness of the moon (rounded) is 2.00% [new (totally dark)] Now get a more precise result for fullness of the moon: - >>> print "Fullness of the moon (more precise) is %.2f" % almanac.moon.moon_phase - Fullness of the moon (more precise) is 1.70 + >>> print "Fullness of the moon (more precise) is %.2f%%" % almanac.moon.moon_phase + Fullness of the moon (more precise) is 1.70% + + Test backwards compatibility with attributes 'sunrise' and 'sunset' + >>> print "Sunrise, sunset:", almanac.sunrise, almanac.sunset + Sunrise, sunset: 06:56 19:30 Get sunrise, sun transit, and sunset using the new 'ephem' syntax: >>> print "Sunrise, sun transit, sunset:", almanac.sun.rise, almanac.sun.transit, almanac.sun.set Sunrise, sun transit, sunset: 06:56 13:13 19:30 Do the same with the moon: - >>> print "Moon rise, moon transit, moon set:", almanac.moon.rise, almanac.moon.transit, almanac.moon.set - Moon rise, moon transit, moon set: 06:59 14:01 21:20 + >>> print "Moon rise, transit, set:", almanac.moon.rise, almanac.moon.transit, almanac.moon.set + Moon rise, transit, set: 06:59 14:01 21:20 Exercise equinox, solstice routines - >>> print weeutil.timestamp_to_string(almanac.next_vernal_equinox) - 2010-03-20 10:32:10 PDT (1269106330) - >>> print weeutil.timestamp_to_string(almanac.next_autumnal_equinox) - 2009-09-22 14:18:38 PDT (1253654318) - >>> print weeutil.timestamp_to_string(almanac.next_summer_solstice) - 2009-06-20 22:45:40 PDT (1245563140) - >>> print weeutil.timestamp_to_string(almanac.next_winter_solstice) - 2009-12-21 09:46:38 PST (1261417598) + >>> print almanac.next_vernal_equinox + 20-Mar-2010 10:32 + >>> print almanac.next_autumnal_equinox + 22-Sep-2009 14:18 + >>> print almanac.next_summer_solstice + 20-Jun-2009 22:45 + >>> print almanac.next_winter_solstice + 21-Dec-2009 09:46 Exercise moon state routines - >>> print weeutil.timestamp_to_string(almanac.next_full_moon) - 2009-04-09 07:55:49 PDT (1239288949) - >>> print weeutil.timestamp_to_string(almanac.next_new_moon) - 2009-04-24 20:22:33 PDT (1240629753) + >>> print almanac.next_full_moon + 09-Apr-2009 07:55 + >>> print almanac.next_new_moon + 24-Apr-2009 20:22 Now location of the sun and moon >>> print "Solar azimuth, altitude = (%.2f, %.2f)" % (almanac.sun.az, almanac.sun.alt) @@ -122,21 +100,37 @@ class Almanac(object): Moon azimuth, altitude = (133.55, 47.89) """ - def __init__(self, time_ts, lat, lon, - altitude=0, temperature=15.0, pressure=1010.0, - moon_phases=Moon.moon_phases, timeformat="%H:%M"): - self.lat = lat - self.lon = lon - self.altitude = altitude - self.temperature = temperature - self.pressure = pressure - self.timeformat = timeformat - self.date_tt = (0, 0, 0, 0, 0, 0) + def __init__(self, time_ts, lat, lon, + altitude=0.0, temperature=15.0, pressure=1010.0, + moon_phases=weeutil.Moon.moon_phases, + formatter=weewx.units.Formatter()): + """Initialize an instance of Almanac - self.moon_phases = moon_phases - self.moon_phase = '' - self.moon_fullness = None + time_ts: A unix epoch timestamp for which the almanac will be current. + lat, lon: Observer's location + + altitude: Observer's elevation in **meters**. [Optional. Default is 0 (sea level)] + + temperature: Observer's temperature in **degrees Celsius**. [Optional. Default is 15.0] + + pressure: Observer's atmospheric pressure in **mBars**. [Optional. Default is 1010] + + moon_phases: An array of 8 strings with descriptions of the moon + phase. [optional. If not given, then weeutil.Moon.moon_phases will be used] + + formatter: An instance of weewx.units.Formatter() with the formatting information + to be used. + """ + self.lat = lat + self.lon = lon + self.altitude = altitude + self.temperature = temperature + self.pressure = pressure + self.moon_phases = moon_phases + self.formatter = formatter + + self.date_tt = (0, 0, 0, 0, 0, 0) self.hasExtras = False self.setTime(time_ts) @@ -150,76 +144,65 @@ class Almanac(object): if _newdate_tt[0:6] != self.date_tt[0:6] : (y,m,d) = _newdate_tt[0:3] - (moon_index, _moon_fullness) = Moon.moon_phase(y, m, d) - self.moon_phase = self.moon_phases[moon_index] if self.moon_phases is not None else '' + (self.moon_index, self._moon_fullness) = weeutil.Moon.moon_phase(y, m, d) + self.moon_phase = self.moon_phases[self.moon_index] # Check to see whether the user has module 'ephem'. If so, use it. if sys.modules.has_key('ephem'): # Set up an observer object holding the location and time: stn = ephem.Observer() - stn.long = math.radians(self.lon) stn.lat = math.radians(self.lat) + stn.long = math.radians(self.lon) stn.elev = self.altitude stn.temp = self.temperature stn.pressure = self.pressure - stn.date = self.time_j1899 = timestamp_to_j1899(time_ts) + stn.date = self.time_djd = timestamp_to_djd(time_ts) - # Sun calculations: - self.sun = BodyWrapper(ephem.Sun, stn, self.timeformat) #@UndefinedVariable - - # Moon calculations: - self.moon = BodyWrapper(ephem.Moon, stn, self.timeformat) - - # Venus calculations: - self.venus = BodyWrapper(ephem.Venus, stn, self.timeformat) #@UndefinedVariable - - # Mars calculations: - self.mars = BodyWrapper(ephem.Mars, stn, self.timeformat) #@UndefinedVariable - - # Jupiter calculations: - self.jupiter = BodyWrapper(ephem.Jupiter, stn, self.timeformat) - - # This attribute is here for backwards compatiblity. - # For full precision, use attribute moon.moon_phase - self.moon_fullness = int(self.moon.moon_phase+0.5) + # The various celestial bodies offered by the almanac: + self.sun = BodyWrapper(ephem.Sun, stn, self.formatter) #@UndefinedVariable + self.moon = BodyWrapper(ephem.Moon, stn, self.formatter) + self.venus = BodyWrapper(ephem.Venus, stn, self.formatter) #@UndefinedVariable + self.mars = BodyWrapper(ephem.Mars, stn, self.formatter) #@UndefinedVariable + self.jupiter = BodyWrapper(ephem.Jupiter, stn, self.formatter) self.hasExtras = True else: - # No ephem package. Use the weeutil algorithms. Less accurate, but they get the - # job done. - (sunrise_utc, sunset_utc) = Sun.sunRiseSet(y, m, d, self.lon, self.lat) + # No ephem package. Use the weeutil algorithms, which supply a minimum of functionality + (sunrise_utc, sunset_utc) = weeutil.Sun.sunRiseSet(y, m, d, self.lon, self.lat) # The above function returns its results in UTC hours. Convert # to a local time tuple sunrise_tt = Almanac._adjustTime(y, m, d, sunrise_utc) sunset_tt = Almanac._adjustTime(y, m, d, sunset_utc) - self._sunrise = time.strftime(self.timeformat, sunrise_tt) - self._sunset = time.strftime(self.timeformat, sunset_tt) + self._sunrise = time.strftime("%H:%M", sunrise_tt) + self._sunset = time.strftime("%H:%M", sunset_tt) - self.moon_fullness = _moon_fullness - self.hasExtras = False self.date_tt = _newdate_tt - # Short cuts, used for backwards compatibility + # Shortcuts, used for backwards compatibility @property def sunrise(self): return self.sun.rise if self.hasExtras else self._sunrise @property def sunset(self): return self.sun.set if self.hasExtras else self._sunset + @property + def moon_fullness(self): + return int(self.moon.moon_phase+0.5) if self.hasExtras else self._moon_fullness def __getattr__(self, attr): - if self.hasExtras and attr in ['next_autumnal_equinox', 'next_vernal_equinox', + if self.hasExtras and attr in ['next_equinox', 'next_solstice', + 'next_autumnal_equinox', 'next_vernal_equinox', 'next_winter_solstice', 'next_summer_solstice', 'next_full_moon', 'next_new_moon']: # This is how you call a function on an instance when all you have is its name: - j1899 = ephem.__dict__[attr](self.time_j1899) #@UndefinedVariable - t = j1899_to_timestamp(j1899) - return t + djd = ephem.__dict__[attr](self.time_djd) #@UndefinedVariable + return weewx.units.ValueHelper((djd, "dublin_jd", "group_time"), + context="ephem_year", formatter=self.formatter) else: raise AttributeError, "Unknown attribute "+attr @@ -246,10 +229,11 @@ fn_map = {'rise' : 'next_rising', class BodyWrapper(object): """This class wraps a celestial body. It returns results in degrees (instead of radians) - and percent (instead of fractions). It also deals with the unfortunately side-effect - of changing the state of the body with certain functions.""" + and percent (instead of fractions). For times, it returns the results as a ValueHelper. + It also deals with the unfortunate design decision in pyephem to change + the state of the celestial body when using it as an argument in certain functions.""" - def __init__(self, body_factory, observer, timeformat="%H:%M"): + def __init__(self, body_factory, observer, formatter): """Initialize a wrapper body_factory: A function that returns an instance of the body @@ -257,62 +241,63 @@ class BodyWrapper(object): observer: An instance of ephem.Observer, containing the observer's lat, lon, time, etc. - timeformat: A strftime style format to be used to format sunrise and sunset. - [optional. If not given, then "%H:%M" will be used. + formatter: An instance of weewx.units.Formatter(), containing the formatting + to be used for times. """ self.body_factory = body_factory self.observer = observer - self.timeformat = timeformat + self.formatter = formatter self.body = body_factory(observer) - (y,m,d) = time.localtime(j1899_to_timestamp(observer.date))[0:3] - self.sod_j1899 = timestamp_to_j1899(time.mktime((y,m,d,0,0,0,0,0,-1))) + + # Calculate and store the start-of-day in Dublin Julian Days: + (y,m,d) = time.localtime(djd_to_timestamp(observer.date))[0:3] + self.sod_djd = timestamp_to_djd(time.mktime((y,m,d,0,0,0,0,0,-1))) def __getattr__(self, attr): if attr in ['az', 'alt', 'a_ra', 'a_dec', 'g_ra', 'ra', 'g_dec', 'dec', 'elong', 'radius', 'hlong', 'hlat', 'sublat', 'sublong']: # Return the results in degrees rather than radians - v = getattr(self.body, attr) - return math.degrees(v) + return math.degrees(getattr(self.body, attr)) elif attr=='moon_phase': # Return the result in percent - v = getattr(self.body, attr) - return 100.0 * v + return 100.0 * self.body.moon_phase elif attr in ['next_rising', 'next_setting', 'next_transit', 'next_antitransit', 'previous_rising', 'previous_setting', 'previous_transit', 'previous_antitransit']: # These functions have the unfortunate side effect of changing the state of the body # being examined. So, create a temporary body and then throw it away temp_body = self.body_factory() - time_j1899 = getattr(self.observer, attr)(temp_body) - return j1899_to_string(time_j1899, self.timeformat) - elif attr in ['rise', 'set', 'transit']: - # These functions have the unfortunate side effect of changing the state of the body - # being examined. So, create a temporary body and then throw it away + time_djd = getattr(self.observer, attr)(temp_body) + return weewx.units.ValueHelper((time_djd, "dublin_jd", "group_time"), context="ephem_day", formatter=self.formatter) + elif attr in fn_map: + # These attribute names have to be mapped to a different function name. Like the + # attributes above, they also have the side effect of changing the state of the body. + # Finally, they return the time of the event anywhere in the day (not just the next + # event), so they take a second argument in the function call. temp_body = self.body_factory(self.observer) # Look up the function to be called for this attribute (eg, call 'next_rising' for 'rise') fn = fn_map[attr] - time_j1899 = getattr(self.observer, fn)(temp_body, self.sod_j1899) - return j1899_to_string(time_j1899, self.timeformat) + # Call the function, with a second argument giving the start-of-day + time_djd = getattr(self.observer, fn)(temp_body, self.sod_djd) + return weewx.units.ValueHelper((time_djd, "dublin_jd", "group_time"), context="ephem_day", formatter=self.formatter) else: + # Just return the result unchanged. return getattr(self.body, attr) -def timestamp_to_j1899(time_ts): - """Convert from a unix time stamp to the number of days since 12/31/1899 12:00 UTC""" +def timestamp_to_djd(time_ts): + """Convert from a unix time stamp to the number of days since 12/31/1899 12:00 UTC + (aka "Dublin Julian Days")""" # The number 25567.5 is the start of the Unix epoch (1/1/1970). Just add on the # number of days since then return 25567.5 + time_ts/86400.0 -def j1899_to_timestamp(j1899): - """Convert from number of days since 12/31/1899 12:00 UTC to unix time stamp""" - return (j1899-25567.5) * 86400.0 - -def j1899_to_string(j1899, timeformat="%H:%M"): - time_tt = time.localtime(j1899_to_timestamp(j1899)) - return time.strftime(timeformat, time_tt) +def djd_to_timestamp(djd): + """Convert from number of days since 12/31/1899 12:00 UTC ("Dublin Julian Days") to unix time stamp""" + return (djd-25567.5) * 86400.0 if __name__ == '__main__': import doctest - import weeutil #@UnusedImport + from weeutil.weeutil import timestamp_to_string #@UnusedImport doctest.testmod() diff --git a/bin/weewx/filegenerator.py b/bin/weewx/filegenerator.py index 4ba1e5b3..82d94a5f 100644 --- a/bin/weewx/filegenerator.py +++ b/bin/weewx/filegenerator.py @@ -17,8 +17,8 @@ import time import Cheetah.Template import Cheetah.Filters -import weeutil.Almanac import weeutil.weeutil +import weewx.almanac import weewx.archive import weewx.reportengine import weewx.station @@ -304,13 +304,14 @@ class FileGenerator(weewx.reportengine.ReportGenerator): if temperature_C is None: temperature_C = 15.0 if pressure_mbar is None: pressure_mbar = 1010.0 - self.almanac = weeutil.Almanac.Almanac(celestial_ts, - self.station.latitude_f, - self.station.longitude_f, - altitude_vt[0], - temperature_C, - pressure_mbar, - self.moonphases) + self.almanac = weewx.almanac.Almanac(celestial_ts, + self.station.latitude_f, + self.station.longitude_f, + altitude_vt[0], + temperature_C, + pressure_mbar, + self.moonphases, + self.formatter) def _prepGen(self, subskin_dict): diff --git a/bin/weewx/units.py b/bin/weewx/units.py index 6f3ba1df..0b2b5d96 100644 --- a/bin/weewx/units.py +++ b/bin/weewx/units.py @@ -168,7 +168,9 @@ conversionDict = { 'mm' : lambda x : x * 10.0}, 'mm' : {'inch' : lambda x : x * .0393700787, 'cm' : lambda x : x * 0.10}, - 'meter' : {'foot' : lambda x : x * 3.2808399 } } + 'meter' : {'foot' : lambda x : x * 3.2808399 }, + 'dublin_jd' : {'unix_epoch' : lambda x : (x-25567.5) * 86400.0}, + 'unix_epoch' : {'dublin_jd' : lambda x : x/86400.0 + 25567.5}} # Default unit formatting to be used in the absence of a skin configuration file @@ -237,12 +239,14 @@ default_unit_label_dict = { "centibar" : " cb", # Default strftime formatting to be used in the absence of a skin # configuration file: -default_time_format_dict = {"day" : "%H:%M", - "week" : "%H:%M on %A", - "month" : "%d-%b-%Y %H:%M", - "year" : "%d-%b-%Y %H:%M", - "rainyear" : "%d-%b-%Y %H:%M", - "current" : "%d-%b-%Y %H:%M"} +default_time_format_dict = {"day" : "%H:%M", + "week" : "%H:%M on %A", + "month" : "%d-%b-%Y %H:%M", + "year" : "%d-%b-%Y %H:%M", + "rainyear" : "%d-%b-%Y %H:%M", + "current" : "%d-%b-%Y %H:%M", + "ephem_day" : "%H:%M", + "ephem_year" : "%d-%b-%Y %H:%M"} #=============================================================================== @@ -299,6 +303,9 @@ class Formatter(object): self.unit_format_dict = unit_format_dict self.unit_label_dict = unit_label_dict self.time_format_dict = time_format_dict + # Add new keys for backwards compatibility on old skin dictionaries: + self.time_format_dict.setdefault('ephem_day', "%H:%M") + self.time_format_dict.setdefault('ephem_year', "%d-%b-%Y %H:%M") @staticmethod def fromSkinDict(skin_dict): @@ -336,7 +343,7 @@ class Formatter(object): if useThisFormat: val_str = time.strftime(useThisFormat, time.localtime(val_t[0])) else: - val_str = time.strftime(self.time_format_dict[context], time.localtime(val_t[0])) + val_str = time.strftime(self.time_format_dict.get(context, "%d-%b-%Y %H:%M"), time.localtime(val_t[0])) except (KeyError, TypeError): # If all else fails, use this weeutil utility: val_str = weeutil.weeutil.timestamp_to_string(val_t[0]) diff --git a/docs/customizing.htm b/docs/customizing.htm index 30ded011..78e74ee9 100644 --- a/docs/customizing.htm +++ b/docs/customizing.htm @@ -781,6 +781,45 @@ December: Min, max temperatures: N/A N/A

See the NOAA template files NOAA/NOAA-YYYY.txt.tmpl and NOAA/NOAA-YYYY-MM.txt.tmpl for examples using iteration, as well as explicit formatting.

+

Almanac

+

If module pyephem has been + installed, then weewx can generate extensive + almanac information for the Sun, Moon, Venus, Mars, and Jupiter, including + their rise, transit and set times, as well as their azimuth and altitude. + Other information is also available.

+

Here is a small sampling:

+
<html>
+<head>
+<title>Almanac data</title>
+</head>
+<body>
+<p>Current time is $current.dateTime<p>
+#if $almanac.hasExtras
+<p>Sunrise, transit, sunset: $almanac.sun.rise $almanac.sun.transit $almanac.sun.set</p>
+<p>Moonrise, transit, moonset: $almanac.moon.rise $almanac.moon.transit $almanac.moon.set</p>
+<p>Mars rise, transit, set: $almanac.mars.rise $almanac.mars.transit $almanac.mars.set</p>
+<p>Azimuth, altitude of mars: $almanac.mars.az $almanac.mars.alt</p>
+<p>Next new, full moon: $almanac.next_new_moon $almanac.next_full_moon</p>
+<p>Next summer, winter solstice: $almanac.next_summer_solstice $almanac.next_winter_solstice</p>
+#else
+<p>Sunrise, sunset: $almanac.sunrise $almanac.sunset</p>
+#end if
+</body>
+</html>
+

If your installation has pyephem installed this would result in:

+
Current time is 29-Mar-2011 09:20
+Sunrise, transit, sunset: 06:51 13:11 19:30
+Moonrise, transit, moonset: 04:33 09:44 15:04
+Mars rise, transit, set: 06:35 12:30 18:26
+Azimuth, altitude of mars: 124.354959275 26.4808431952
+Next new, full moon: 03-Apr-2011 07:32 17-Apr-2011 19:43
+Next summer, winter solstice: 21-Jun-2011 10:16 21-Dec-2011 21:29
+

Otherwise, a fallback position is used, resulting in

+
Current time is 29-Mar-2011 09:20
+Sunrise, sunset: 06:51 19:30
+
+

As shown in the example, you can test whether this extended almanac information is available with + the value $almanac.hasExtras.

Writing a custom generator

To do more sophisticated customization it may be necessary to extend an existing generator, or write your own.

@@ -1039,6 +1078,13 @@ month = %d-%b-%Y %H:%M

would specify that week data should use a format such as "15:20 on Sunday", while month data should look like "06-Oct-2009 15:20"

+

It also allows the formatting to be set for almanac times:

+
ephem_day  = %H:%M
+ephem_year = %d-%b-%Y %H:%M
+

The first of these, ephem_day, is used for + almanac times within the day, such as sunrise or sunset. The second, + ephem_year, is used for almanac times within the + year, such as the next equinox or full moon.

[[DegreeDays]]

heating_base
cooling_base

diff --git a/docs/readme.htm b/docs/readme.htm index ab5c857f..b996f2df 100644 --- a/docs/readme.htm +++ b/docs/readme.htm @@ -99,7 +99,7 @@ Version 1.10

Prerequisites

Python

Python V2.5 or V2.6 is required. The newer V3.0 distribution will not work.

-

Required packages

+

External packages

The following external packages are required to use weewx.

  1. sqlite3 (Version 3.5 or greater) @@ -118,6 +118,13 @@ Version 1.10 (Version 1.1.6 or greater) Also known as PIL, this is included in many Python distributions.
+

In addition, there is one optional package:

+

There are two general strategies for installing these prerequisites:

  1. Use operating system tools, such as apt-get @@ -127,7 +134,11 @@ Version 1.10 easy_install.

Option #1 is easier, but if your Linux distribution does not come with such - tools, you may have to use easy_install. Brief instructions + tools, you may have to use easy_install. If you + choose to install pyephem, then + it can only be installed using easy_install (see + instructions below).

+

Brief instructions for both approaches are given below.

Installation on Debian distributions (including Ubuntu) using apt-get

@@ -214,6 +225,9 @@ Version 1.10

My version of Python came with V1.1.6, which works great, but if you need to install

easy_install pil
+

If you choose to install the optional + package pyephem:

+
easy_install pyephem

System requirements

I run weewx on a 500MHz system with an AMD Geode processor and 512 MB of memory.  Configured this way, it consumes about diff --git a/setup.py b/setup.py index c8aa350e..5bad6546 100755 --- a/setup.py +++ b/setup.py @@ -175,6 +175,8 @@ class My_install_data(install_data): new_config = configobj.ConfigObj(f) new_config.indent_type = ' ' new_version_number = VERSION.split('.') + if len(new_version_number[1]) < 2: + new_version_number[1] = '0'+new_version_number[1] # Sometimes I forget to turn the debug flag off: new_config['debug'] = 0 @@ -192,10 +194,14 @@ class My_install_data(install_data): # assume a very old version: if not old_version: old_version = '1.0.0' old_version_number = old_version.split('.') + # Take care of the collation problem when comparing things like + # version '1.9' to '1.10' by prepending a '0' to the former: + if len(old_version_number[1]) < 2: + old_version_number[1] = '0'+old_version_number[1] # If the user has a version >= 1.7, then merge in the old # config file. - if old_version_number[0:2] >= ['1','7']: + if old_version_number[0:2] >= ['1','07']: # Any user changes in old_config will overwrite values in new_config # with this merge new_config.merge(old_config) diff --git a/skins/Standard/index.html.tmpl b/skins/Standard/index.html.tmpl index 4f703bb3..461c47d6 100644 --- a/skins/Standard/index.html.tmpl +++ b/skins/Standard/index.html.tmpl @@ -2,7 +2,6 @@ ## $Revision$ ## $Author$ ## $Date$ -#set $short_time time.strftime("%H:%M" @@ -321,66 +320,93 @@

Today's Almanac
- - - - - - - #if $almanac.hasExtras - - - - - #end if - - - - - #if $almanac.hasExtras - #set $sun_az = "%.1f°" % $almanac.sun.az - #set $sun_alt= "%.1f°" % $almanac.sun.alt - - - - - - - - - #end if -
Sun
Sunrise:$almanac.sunrise
Transit:$almanac.sun.transit
Sunset:$almanac.sunset
Azimuth:$sun_az
Altitude:$sun_alt
- - - - - - - #if $almanac.hasExtras - - - - - - - - - - #set $moon_az = "%.1f°" % $almanac.moon.az - #set $moon_alt= "%.1f°" % $almanac.moon.alt - - - - - - - - - #end if -
Moon
Phase:$almanac.moon_phase ($almanac.moon_fullness% full)
Rise:$almanac.moon.rise -
Transit:$almanac.moon.transit -
Set:$almanac.moon.set -
Azimuth:$moon_az
Altitude:$moon_alt
+
+
+ + + #if $almanac.hasExtras + + + + + + + + + + + + + #else + + + + + + + + + #end if + #if $almanac.hasExtras + + + + + + + + + + + + + + + #end if +
Sun
Sunrise:$almanac.sun.rise
Transit:$almanac.sun.transit
Sunset:$almanac.sun.set
Sunrise:$almanac.sunrise
Sunset:$almanac.sunset
Azimuth:$("%.1f°" % $almanac.sun.az)
Altitude:$("%.1f°" % $almanac.sun.alt)
Equinox:$almanac.next_equinox +
Solstice:$almanac.next_solstice +
+
+
+ + + #if $almanac.hasExtras + + + + + + + + + + + + + + + + + + + + + + + + #end if + + + + +
Moon
Rise:$almanac.moon.rise +
Transit:$almanac.moon.transit +
Set:$almanac.moon.set +
Azimuth:$("%.1f°" % $almanac.moon.az)
Altitude:$("%.1f°" % $almanac.moon.alt)
Full moon:$almanac.next_full_moon +
New moon:$almanac.next_new_moon +
Phase:$almanac.moon_phase
($almanac.moon_fullness% full)
+
+
diff --git a/skins/Standard/skin.conf b/skins/Standard/skin.conf index dacb3970..d6754dcb 100644 --- a/skins/Standard/skin.conf +++ b/skins/Standard/skin.conf @@ -136,12 +136,14 @@ # This section sets the string format to be used # each time scale. # - day = %H:%M - week = %H:%M on %A - month = %d-%b-%Y %H:%M - year = %d-%b-%Y %H:%M - rainyear = %d-%b-%Y %H:%M - current = %d-%b-%Y %H:%M + day = %H:%M + week = %H:%M on %A + month = %d-%b-%Y %H:%M + year = %d-%b-%Y %H:%M + rainyear = %d-%b-%Y %H:%M + current = %d-%b-%Y %H:%M + ephem_day = %H:%M + ephem_year = %d-%b-%Y %H:%M [[DegreeDays]] # diff --git a/skins/Standard/weewx.css b/skins/Standard/weewx.css index 28ee8568..f3c9eef4 100644 --- a/skins/Standard/weewx.css +++ b/skins/Standard/weewx.css @@ -102,6 +102,189 @@ body { text-align: center; } +#content .header { + font-size: 14pt; + font-weight: bolder; + color: #3d6c87; + margin-bottom: 10px; +} + + +#content .caption { + font-weight: bold; + color: #3d6c87; +} + +#content .label { + text-align: right; + font-style: italic; +} + +#content .data { + text-align: left; +} + +#about, #almanac { + margin-bottom: 30px; +} + +#almanac { + width:80%; + margin-left: auto; + margin-right: auto; +} + +.celestial_group { +} + +.celestial_body { + width: 48%; + vertical-align: top; +} + +#plots { + width: 90%; + display: block; + margin-left: auto; + margin-right: auto; +} + +#plots img { + margin: 3px; + border: thin solid #3d6c87; + padding: 3px; +} + +#radar_img { + width: 90%; + display: block; + margin-left: auto; + margin-right: auto; +} + +#radar_img img { + width: 90%; + padding: 3px; + margin: 3px; +} + +/* + * Navigation bar (week, month, etc.) at the bottom + */ +#navbar { + margin: 0 1% 1% 1%; + padding: 5px; + text-align: center; + clear: both; + border-top: 1px solid #dcdcdc; + border-right: 1px solid #a9a9a9; + border-bottom: 1px solid #808080; + border-left: 1px solid #a9a9a9; + background-color: #fafaff; +} + +/*************** Global Styles ***************/ + +h2, h3, h4, h5, h6 { + color: #3d6c87; +} + +body { + margin: 0; + padding: 0; + border: 0; + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 10pt; + background-color: #f2f2f7; + background-image: url('backgrounds/band.gif'); + background-repeat: repeat; + background-attachment: scroll; +} + +#container { + margin: 0; + padding: 0; + border: 0; +} + +/* + * This is the big header at the top of the page + */ +#masthead { + margin: 1% 1% 0 1%; + padding: 5px; + text-align: center; + border-top: 1px solid #dcdcdc; + border-right: 1px solid #a9a9a9; + border-bottom: 1px solid #808080; + border-left: 1px solid #a9a9a9; + background-color: #fafaff; +} + +#masthead h1 { + color: #3d6c87; +} +#masthead h3 { + color: #5f8ea9; +} + +/* + * This holds the statistics (daily high/low, etc.) on the left: + */ +#stats_group { + width: 30%; + min-height: 500px; + margin: 1%; + padding: 5px; + float: left; + border-top: 1px solid #dcdcdc; + border-right: 1px solid #a9a9a9; + border-bottom: 1px solid #808080; + border-left: 1px solid #a9a9a9; + background-color: #fafaff; +} + +.stats table { + border: thin solid #000000; + width: 100%; +} +.stats td { + border: thin solid #000000; + padding: 2px; +} + +.stats_header { + background-color: #000000; + color: #a8b8c8; + font-size: 14pt; + font-weight: bolder; +} + +.stats_label { + color: green; +} + +.stats_data { + color: red; +} + +/* + * This holds the "About", "Almanac", and plots on the right + */ +#content { + width: 62%; + min-height: 500px; + margin: 1%; + padding: 5px; + float: right; + border-top: 1px solid #dcdcdc; + border-right: 1px solid #a9a9a9; + border-bottom: 1px solid #808080; + border-left: 1px solid #a9a9a9; + background-color: #fafaff; + text-align: center; +} + #content .header { text-align: center; font-size: 14pt; @@ -122,35 +305,38 @@ body { #content td { width: 50%; - padding: 0; - margin: 0; } #content .label { text-align: right; font-style: italic; + padding-right: 2px; } #content .data { text-align: left; + padding-left: 2px; } #about, #almanac { margin-bottom: 30px; } -.celestial_group { +#almanac { +# border: thin solid #3d6c87; + width:60%; margin-left: auto; margin-right: auto; } +.celestial_group { +} .celestial_body { width: 48%; -# border: thin solid #3d6c87; - border-top: 1px solid #3d6c87; - border-left:1px solid #3d6c87; - border-bottom: 2px solid #3d6c87; - border-right: 2px solid #3d6c87; +# border-top: 1px solid #3d6c87; +# border-left:1px solid #3d6c87; +# border-bottom: 2px solid #3d6c87; +# border-right: 2px solid #3d6c87; display:inline-block; vertical-align: top; } @@ -201,4 +387,3 @@ body { h2, h3, h4, h5, h6 { color: #3d6c87; } - diff --git a/weewx.conf b/weewx.conf index 9dc2cea4..ed44643b 100644 --- a/weewx.conf +++ b/weewx.conf @@ -29,7 +29,7 @@ debug = 0 socket_timeout = 20 # Current version -version = 1.10.0a6 +version = 1.10.0 ############################################################################################