From 68f83cea26e8cca99792e28b1746f38bf5dc7ccd Mon Sep 17 00:00:00 2001 From: Tom Keffer Date: Mon, 28 Mar 2011 00:30:10 +0000 Subject: [PATCH 01/11] From c10174a7cc2854e61a268ae6277dd2954b2343f6 Mon Sep 17 00:00:00 2001 From: Tom Keffer Date: Mon, 28 Mar 2011 14:43:42 +0000 Subject: [PATCH 02/11] Integrating almanac into the unit conversion and formatting machinery. --- bin/weeutil/{Almanac.py => weeephem.py} | 93 ++++++++++++------------- bin/weewx/almanachelper.py | 73 +++++++++++++++++++ docs/customizing.htm | 11 +++ docs/readme.htm | 18 ++++- 4 files changed, 145 insertions(+), 50 deletions(-) rename bin/weeutil/{Almanac.py => weeephem.py} (80%) create mode 100644 bin/weewx/almanachelper.py diff --git a/bin/weeutil/Almanac.py b/bin/weeutil/weeephem.py similarity index 80% rename from bin/weeutil/Almanac.py rename to bin/weeutil/weeephem.py index ccc0106c..5107c553 100644 --- a/bin/weeutil/Almanac.py +++ b/bin/weeutil/weeephem.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. # @@ -27,14 +27,9 @@ import sys import Moon -# If the user has installed ephem, use it. Otherwise, fall back to the weeutil algorithms: -try: - import ephem - import math -except: - import Sun +import ephem -class Almanac(object): +class Ephem(object): """Almanac data. time_ts: A timestamp within the date for which sunrise/sunset is desired. @@ -50,7 +45,7 @@ class Almanac(object): 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. + timeformat: A strftime style format to be used to format attributes sunrise and sunset. [optional. If not given, then "%H:%M" will be used. ATTRIBUTES. @@ -63,21 +58,23 @@ class Almanac(object): moon_fullness: Percent fullness of the moon (0=new moon, 100=full moon) If the module 'ephem' is used, 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) + >>> almanac = Ephem(t, 46.0, -122.0) Test backwards compatiblity with attributes 'sunrise' and 'sunset' >>> print "Sunrise, sunset:", almanac.sunrise, almanac.sunset @@ -88,31 +85,41 @@ class Almanac(object): 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% 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 + >>> print "Sunrise, sun transit, sunset:\\n%s\\n%s\\n%s" % (timestamp_to_string(almanac.sun.rise), + ... timestamp_to_string(almanac.sun.transit), + ... timestamp_to_string(almanac.sun.set)) + Sunrise, sun transit, sunset: + 2009-03-27 06:56:36 PDT (1238162196) + 2009-03-27 13:13:13 PDT (1238184793) + 2009-03-27 19:30:41 PDT (1238207441) 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:\\n%s\\n%s\\n%s" % (timestamp_to_string(almanac.moon.rise), + ... timestamp_to_string(almanac.moon.transit), + ... timestamp_to_string(almanac.moon.set)) + Moon rise, transit, set: + 2009-03-27 06:59:14 PDT (1238162354) + 2009-03-27 14:01:57 PDT (1238187717) + 2009-03-27 21:20:06 PDT (1238214006) Exercise equinox, solstice routines - >>> print weeutil.timestamp_to_string(almanac.next_vernal_equinox) + >>> print timestamp_to_string(almanac.next_vernal_equinox) 2010-03-20 10:32:10 PDT (1269106330) - >>> print weeutil.timestamp_to_string(almanac.next_autumnal_equinox) + >>> print timestamp_to_string(almanac.next_autumnal_equinox) 2009-09-22 14:18:38 PDT (1253654318) - >>> print weeutil.timestamp_to_string(almanac.next_summer_solstice) + >>> print timestamp_to_string(almanac.next_summer_solstice) 2009-06-20 22:45:40 PDT (1245563140) - >>> print weeutil.timestamp_to_string(almanac.next_winter_solstice) + >>> print timestamp_to_string(almanac.next_winter_solstice) 2009-12-21 09:46:38 PST (1261417598) Exercise moon state routines - >>> print weeutil.timestamp_to_string(almanac.next_full_moon) + >>> print timestamp_to_string(almanac.next_full_moon) 2009-04-09 07:55:49 PDT (1239288949) - >>> print weeutil.timestamp_to_string(almanac.next_new_moon) + >>> print timestamp_to_string(almanac.next_new_moon) 2009-04-24 20:22:33 PDT (1240629753) Now location of the sun and moon @@ -122,21 +129,15 @@ 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"): + def __init__(self, time_ts, lat, lon, + altitude=0.0, temperature=15.0, pressure=1010.0): 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) - self.moon_phases = moon_phases - self.moon_phase = '' - self.moon_fullness = None - self.hasExtras = False self.setTime(time_ts) @@ -150,8 +151,7 @@ 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, _moon_fullness) = Moon.moon_phase(y, m, d) # Check to see whether the user has module 'ephem'. If so, use it. if sys.modules.has_key('ephem'): @@ -180,10 +180,6 @@ class Almanac(object): # 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) - self.hasExtras = True else: @@ -193,8 +189,8 @@ class Almanac(object): (sunrise_utc, sunset_utc) = 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) + sunrise_tt = Ephem._adjustTime(y, m, d, sunrise_utc) + sunset_tt = Ephem._adjustTime(y, m, d, sunset_utc) self._sunrise = time.strftime(self.timeformat, sunrise_tt) self._sunset = time.strftime(self.timeformat, sunset_tt) @@ -207,10 +203,12 @@ class Almanac(object): # Short cuts, used for backwards compatibility @property def sunrise(self): - return self.sun.rise if self.hasExtras else self._sunrise + time_tt = time.localtime(self.sun.rise) + return time.strftime(self.timeformat, time_tt) if self.hasExtras else self._sunrise @property def sunset(self): - return self.sun.set if self.hasExtras else self._sunset + time_tt = time.localtime(self.sun.set) + return time.strftime(self.timeformat, time_tt) if self.hasExtras else self._sunset def __getattr__(self, attr): if self.hasExtras and attr in ['next_autumnal_equinox', 'next_vernal_equinox', @@ -262,7 +260,6 @@ class BodyWrapper(object): """ self.body_factory = body_factory self.observer = observer - self.timeformat = timeformat 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))) @@ -283,7 +280,7 @@ class BodyWrapper(object): # 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) + return j1899_to_timestamp(time_j1899) 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 @@ -291,7 +288,7 @@ class BodyWrapper(object): # 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) + return j1899_to_timestamp(time_j1899) else: return getattr(self.body, attr) @@ -312,7 +309,7 @@ def j1899_to_string(j1899, timeformat="%H:%M"): if __name__ == '__main__': import doctest - import weeutil #@UnusedImport + from weeutil import timestamp_to_string #@UnusedImport doctest.testmod() diff --git a/bin/weewx/almanachelper.py b/bin/weewx/almanachelper.py new file mode 100644 index 00000000..4ba1f05b --- /dev/null +++ b/bin/weewx/almanachelper.py @@ -0,0 +1,73 @@ +# +# Copyright (c) 2009, 2011 Tom Keffer +# +# See the file LICENSE.txt for your full rights. +# +# $Revision$ +# $Author$ +# $Date$ +# +"""Wraps almanac ephem data, making it accessible through the units machinery""" + +# If the user has installed ephem, use it. Otherwise, fall back to the weeutil algorithms: +try: + import ephem + import math +except: + import weeutil.Sun + +import weeutil.weeephem +import weeutil.Moon +import weewx.units + +class Almanac(object): + + def __init__(self, time_ts, lat, lon, formatter, + altitude=0.0, temperature=15.0, pressure=1010.0, + moon_phases=weeutil.Moon.moon_phases): + + self.ephem = weeutil.weeephem.Ephem(time_ts, lat, lon, + altitude, temperature, pressure) + self.formatter = formatter + self.moon_phases = moon_phases + self.moon_phase = self.moon_phases[self.ephem.moon_index] if self.moon_phases is not None else '' + + def setTime(self, time_ts): + self.ephem.setTime(time_ts) + self.moon_phase = self.moon_phases[self.ephem.moon_index] if self.moon_phases is not None else '' + + @property + def sunrise(self): + if self.ephem.hasExtras: + time_ts = self.ephem.sun.rise + else: + + def __getattr__(self, attr): + if attr in ['next_autumnal_equinox', 'next_vernal_equinox', + 'next_winter_solstice', 'next_summer_solstice', + 'next_full_moon', 'next_new_moon']: + time_ts = getattr(self.ephem, attr) + vt = (time_ts, "unix_epoch", "group_time") + vh = weewx.units.ValueHelper(vt, context='current', formatter=self.formatter) + return vh + else: + body = getattr(self.ephem, attr) + return BodyHelper(body, self.formatter) + + +class BodyHelper(object): + + def __init__(self, body, formatter): + self.body = body + self.formatter = formatter + + def __getattr__(self, attr): + if attr in ['next_rising', 'next_setting', 'next_transit', 'next_antitransit', + 'previous_rising', 'previous_setting', 'previous_transit', 'previous_antitransit', + 'rise', 'set', 'transit']: + time_ts = getattr(self.body, attr) + vt = (time_ts, "unix_epoch", "group_time") + vh = weewx.units.ValueHelper(vt, context='current', formatter=self.formatter) + return vh + else: + return getattr(self.body, attr) \ No newline at end of file diff --git a/docs/customizing.htm b/docs/customizing.htm index 30ded011..16c606c1 100644 --- a/docs/customizing.htm +++ b/docs/customizing.htm @@ -781,6 +781,17 @@ 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. Here is a sampling:

+
Sunrise, transit, sunset: $almanac.sun.rise $almanac.sun.transit $almanac.sun.set
+
Moonrise, transit, moonset: $almanac.moon.rise $almanac.moon.transit $almanac.moon.set
+
Mars rise, transit, set: $almanac.mars.rise $almanac.mars.transit $almanac.mars.set
+
Azimuth, altitude of mars: $almanac.mars.az $almanac.mars.alt
+
Next new, full moon: $almanac.next_new_moon $almanac.next_full_moon
+
Next summer, winter solstice: $almanac.next_summer_solstice $almanac.next_winter_solstice
+
 

Writing a custom generator

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

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:

+
    +
  • pyephem (Version V3.7.3 + or greater). For extended almanac information. If not installed, + fallback information will be used. As of the time of this writing, this + package could only be installed using easy_install.
  • +

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 From 24eb3fa508363b6dca80c642f09894706bef4df4 Mon Sep 17 00:00:00 2001 From: Tom Keffer Date: Mon, 28 Mar 2011 14:48:47 +0000 Subject: [PATCH 03/11] Moved almanac.py to the package weewx. --- bin/{weeutil/weeephem.py => weewx/almanac.py} | 35 +++++---- bin/weewx/almanachelper.py | 73 ------------------- 2 files changed, 21 insertions(+), 87 deletions(-) rename bin/{weeutil/weeephem.py => weewx/almanac.py} (96%) delete mode 100644 bin/weewx/almanachelper.py diff --git a/bin/weeutil/weeephem.py b/bin/weewx/almanac.py similarity index 96% rename from bin/weeutil/weeephem.py rename to bin/weewx/almanac.py index 5107c553..ab140b00 100644 --- a/bin/weeutil/weeephem.py +++ b/bin/weewx/almanac.py @@ -12,6 +12,20 @@ This module can optionally use PyEphem, which offers high quality astronomical calculations. See http://rhodesmill.org/pyephem. """ +import calendar +import time +import sys + +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 weeutil.Sun + #=============================================================================== # Architectural notes # @@ -20,16 +34,8 @@ astronomical calculations. See http://rhodesmill.org/pyephem. """ # 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 ephem - -class Ephem(object): +class Almanac(object): """Almanac data. time_ts: A timestamp within the date for which sunrise/sunset is desired. @@ -74,7 +80,7 @@ class Ephem(object): >>> t = time.mktime((2009, 3, 27, 12, 0, 0, 0, 0, -1)) >>> print timestamp_to_string(t) 2009-03-27 12:00:00 PDT (1238180400) - >>> almanac = Ephem(t, 46.0, -122.0) + >>> almanac = Almanac(t, 46.0, -122.0) Test backwards compatiblity with attributes 'sunrise' and 'sunset' >>> print "Sunrise, sunset:", almanac.sunrise, almanac.sunset @@ -130,7 +136,8 @@ class Ephem(object): """ def __init__(self, time_ts, lat, lon, - altitude=0.0, temperature=15.0, pressure=1010.0): + altitude=0.0, temperature=15.0, pressure=1010.0, + formatter=weewx.units.Formatter()): self.lat = lat self.lon = lon self.altitude = altitude @@ -151,7 +158,7 @@ class Ephem(object): if _newdate_tt[0:6] != self.date_tt[0:6] : (y,m,d) = _newdate_tt[0:3] - (self.moon_index, _moon_fullness) = Moon.moon_phase(y, m, d) + (self.moon_index, _moon_fullness) = weeutil.Moon.moon_phase(y, m, d) # Check to see whether the user has module 'ephem'. If so, use it. if sys.modules.has_key('ephem'): @@ -189,8 +196,8 @@ class Ephem(object): (sunrise_utc, sunset_utc) = 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 = Ephem._adjustTime(y, m, d, sunrise_utc) - sunset_tt = Ephem._adjustTime(y, m, d, sunset_utc) + 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) diff --git a/bin/weewx/almanachelper.py b/bin/weewx/almanachelper.py deleted file mode 100644 index 4ba1f05b..00000000 --- a/bin/weewx/almanachelper.py +++ /dev/null @@ -1,73 +0,0 @@ -# -# Copyright (c) 2009, 2011 Tom Keffer -# -# See the file LICENSE.txt for your full rights. -# -# $Revision$ -# $Author$ -# $Date$ -# -"""Wraps almanac ephem data, making it accessible through the units machinery""" - -# If the user has installed ephem, use it. Otherwise, fall back to the weeutil algorithms: -try: - import ephem - import math -except: - import weeutil.Sun - -import weeutil.weeephem -import weeutil.Moon -import weewx.units - -class Almanac(object): - - def __init__(self, time_ts, lat, lon, formatter, - altitude=0.0, temperature=15.0, pressure=1010.0, - moon_phases=weeutil.Moon.moon_phases): - - self.ephem = weeutil.weeephem.Ephem(time_ts, lat, lon, - altitude, temperature, pressure) - self.formatter = formatter - self.moon_phases = moon_phases - self.moon_phase = self.moon_phases[self.ephem.moon_index] if self.moon_phases is not None else '' - - def setTime(self, time_ts): - self.ephem.setTime(time_ts) - self.moon_phase = self.moon_phases[self.ephem.moon_index] if self.moon_phases is not None else '' - - @property - def sunrise(self): - if self.ephem.hasExtras: - time_ts = self.ephem.sun.rise - else: - - def __getattr__(self, attr): - if attr in ['next_autumnal_equinox', 'next_vernal_equinox', - 'next_winter_solstice', 'next_summer_solstice', - 'next_full_moon', 'next_new_moon']: - time_ts = getattr(self.ephem, attr) - vt = (time_ts, "unix_epoch", "group_time") - vh = weewx.units.ValueHelper(vt, context='current', formatter=self.formatter) - return vh - else: - body = getattr(self.ephem, attr) - return BodyHelper(body, self.formatter) - - -class BodyHelper(object): - - def __init__(self, body, formatter): - self.body = body - self.formatter = formatter - - def __getattr__(self, attr): - if attr in ['next_rising', 'next_setting', 'next_transit', 'next_antitransit', - 'previous_rising', 'previous_setting', 'previous_transit', 'previous_antitransit', - 'rise', 'set', 'transit']: - time_ts = getattr(self.body, attr) - vt = (time_ts, "unix_epoch", "group_time") - vh = weewx.units.ValueHelper(vt, context='current', formatter=self.formatter) - return vh - else: - return getattr(self.body, attr) \ No newline at end of file From 943d4dbe49465f51ce8528410edaef136d348c6f Mon Sep 17 00:00:00 2001 From: Tom Keffer Date: Mon, 28 Mar 2011 15:51:57 +0000 Subject: [PATCH 04/11] almanac now uses weewx.units formatting machinery. --- bin/weewx/almanac.py | 167 +++++++++++++++++++------------------------ 1 file changed, 75 insertions(+), 92 deletions(-) diff --git a/bin/weewx/almanac.py b/bin/weewx/almanac.py index ab140b00..6f432dc1 100644 --- a/bin/weewx/almanac.py +++ b/bin/weewx/almanac.py @@ -25,15 +25,7 @@ try: import math except: import weeutil.Sun - -#=============================================================================== -# 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 -#=============================================================================== + timeformat = "%H:%M" class Almanac(object): """Almanac data. @@ -82,11 +74,7 @@ class Almanac(object): 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)] @@ -94,39 +82,33 @@ class Almanac(object): >>> 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:\\n%s\\n%s\\n%s" % (timestamp_to_string(almanac.sun.rise), - ... timestamp_to_string(almanac.sun.transit), - ... timestamp_to_string(almanac.sun.set)) - Sunrise, sun transit, sunset: - 2009-03-27 06:56:36 PDT (1238162196) - 2009-03-27 13:13:13 PDT (1238184793) - 2009-03-27 19:30:41 PDT (1238207441) + >>> 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, transit, set:\\n%s\\n%s\\n%s" % (timestamp_to_string(almanac.moon.rise), - ... timestamp_to_string(almanac.moon.transit), - ... timestamp_to_string(almanac.moon.set)) - Moon rise, transit, set: - 2009-03-27 06:59:14 PDT (1238162354) - 2009-03-27 14:01:57 PDT (1238187717) - 2009-03-27 21:20:06 PDT (1238214006) + >>> 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 timestamp_to_string(almanac.next_vernal_equinox) - 2010-03-20 10:32:10 PDT (1269106330) - >>> print timestamp_to_string(almanac.next_autumnal_equinox) - 2009-09-22 14:18:38 PDT (1253654318) - >>> print timestamp_to_string(almanac.next_summer_solstice) - 2009-06-20 22:45:40 PDT (1245563140) - >>> print 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 timestamp_to_string(almanac.next_full_moon) - 2009-04-09 07:55:49 PDT (1239288949) - >>> print 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) @@ -137,14 +119,17 @@ class Almanac(object): 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()): - self.lat = lat - self.lon = lon - self.altitude = altitude + self.lat = lat + self.lon = lon + self.altitude = altitude self.temperature = temperature - self.pressure = pressure + 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) @@ -158,51 +143,41 @@ class Almanac(object): if _newdate_tt[0:6] != self.date_tt[0:6] : (y,m,d) = _newdate_tt[0:3] - (self.moon_index, _moon_fullness) = weeutil.Moon.moon_phase(y, m, d) + (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) - # 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) + # 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(timeformat, sunrise_tt) + self._sunset = time.strftime(timeformat, sunset_tt) - self.moon_fullness = _moon_fullness - self.hasExtras = False self.date_tt = _newdate_tt @@ -210,12 +185,13 @@ class Almanac(object): # Short cuts, used for backwards compatibility @property def sunrise(self): - time_tt = time.localtime(self.sun.rise) - return time.strftime(self.timeformat, time_tt) if self.hasExtras else self._sunrise + return self.sun.rise if self.hasExtras else self._sunrise @property def sunset(self): - time_tt = time.localtime(self.sun.set) - return time.strftime(self.timeformat, time_tt) if self.hasExtras else self._sunset + 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', @@ -224,7 +200,8 @@ class Almanac(object): # 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 + vt = (t, "unix_epoch", "group_time") + return weewx.units.ValueHelper(vt, context="year", formatter=self.formatter) else: raise AttributeError, "Unknown attribute "+attr @@ -251,10 +228,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 @@ -262,12 +240,15 @@ 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.formatter = formatter self.body = body_factory(observer) + + # Calculate and store the start-of-day in J1899: (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))) @@ -275,28 +256,34 @@ class BodyWrapper(object): 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_timestamp(time_j1899) - 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_ts = j1899_to_timestamp(time_j1899) + vh = weewx.units.ValueHelper((time_ts, "unix_epoch", "group_time"), context="day", formatter=self.formatter) + return vh + 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] + # Call the function, with a second argument giving the start-of-day time_j1899 = getattr(self.observer, fn)(temp_body, self.sod_j1899) - return j1899_to_timestamp(time_j1899) + time_ts = j1899_to_timestamp(time_j1899) + vh = weewx.units.ValueHelper((time_ts, "unix_epoch", "group_time"), context="day", formatter=self.formatter) + return vh else: + # Just return the result unchanged. return getattr(self.body, attr) def timestamp_to_j1899(time_ts): @@ -309,14 +296,10 @@ 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) - if __name__ == '__main__': import doctest - from weeutil import timestamp_to_string #@UnusedImport + from weeutil.weeutil import timestamp_to_string #@UnusedImport doctest.testmod() From ec648df9debde2302cd1f58f132d1a0feb4a6f77 Mon Sep 17 00:00:00 2001 From: Tom Keffer Date: Mon, 28 Mar 2011 16:04:11 +0000 Subject: [PATCH 05/11] Introduced Dublin Julian Days. --- bin/weewx/almanac.py | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/bin/weewx/almanac.py b/bin/weewx/almanac.py index 6f432dc1..bd48d3df 100644 --- a/bin/weewx/almanac.py +++ b/bin/weewx/almanac.py @@ -156,7 +156,7 @@ class Almanac(object): 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) # The various celestial bodies offered by the almanac: self.sun = BodyWrapper(ephem.Sun, stn, self.formatter) #@UndefinedVariable @@ -198,8 +198,8 @@ class Almanac(object): '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) + djd = ephem.__dict__[attr](self.time_djd) #@UndefinedVariable + t = djd_to_timestamp(djd) vt = (t, "unix_epoch", "group_time") return weewx.units.ValueHelper(vt, context="year", formatter=self.formatter) else: @@ -248,9 +248,9 @@ class BodyWrapper(object): self.formatter = formatter self.body = body_factory(observer) - # Calculate and store the start-of-day in J1899: - (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', @@ -265,8 +265,8 @@ class BodyWrapper(object): # 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) - time_ts = j1899_to_timestamp(time_j1899) + time_djd = getattr(self.observer, attr)(temp_body) + time_ts = djd_to_timestamp(time_djd) vh = weewx.units.ValueHelper((time_ts, "unix_epoch", "group_time"), context="day", formatter=self.formatter) return vh elif attr in fn_map: @@ -278,23 +278,24 @@ class BodyWrapper(object): # Look up the function to be called for this attribute (eg, call 'next_rising' for 'rise') fn = fn_map[attr] # Call the function, with a second argument giving the start-of-day - time_j1899 = getattr(self.observer, fn)(temp_body, self.sod_j1899) - time_ts = j1899_to_timestamp(time_j1899) + time_djd = getattr(self.observer, fn)(temp_body, self.sod_djd) + time_ts = djd_to_timestamp(time_djd) vh = weewx.units.ValueHelper((time_ts, "unix_epoch", "group_time"), context="day", formatter=self.formatter) return vh 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 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__': From 3cf646594ad4048fffc21596502708440d36d59b Mon Sep 17 00:00:00 2001 From: Tom Keffer Date: Mon, 28 Mar 2011 17:08:15 +0000 Subject: [PATCH 06/11] Now uses weewx.units machinery to do conversion from Dublin Julian Days to unix epoch time. --- bin/weewx/almanac.py | 59 ++++++------- bin/weewx/filegenerator.py | 17 ++-- bin/weewx/units.py | 6 +- skins/Standard/index.html.tmpl | 152 ++++++++++++++++++++------------- 4 files changed, 132 insertions(+), 102 deletions(-) diff --git a/bin/weewx/almanac.py b/bin/weewx/almanac.py index bd48d3df..8a690b8f 100644 --- a/bin/weewx/almanac.py +++ b/bin/weewx/almanac.py @@ -25,27 +25,10 @@ try: import math except: import weeutil.Sun - timeformat = "%H:%M" 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 attributes sunrise and sunset. - [optional. If not given, then "%H:%M" will be used. - ATTRIBUTES. As a minimum, the following attributes are available: @@ -55,7 +38,7 @@ 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.rise: Time upper limb of sun will rise above the horizon today in unix epoch time @@ -121,6 +104,24 @@ class Almanac(object): altitude=0.0, temperature=15.0, pressure=1010.0, moon_phases=weeutil.Moon.moon_phases, formatter=weewx.units.Formatter()): + """Initialize an instance of Almanac + + 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 @@ -175,14 +176,14 @@ class Almanac(object): # 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(timeformat, sunrise_tt) - self._sunset = time.strftime(timeformat, sunset_tt) + self._sunrise = time.strftime("%H:%M", sunrise_tt) + self._sunset = time.strftime("%H:%M", sunset_tt) 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 @@ -194,14 +195,14 @@ class Almanac(object): 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: djd = ephem.__dict__[attr](self.time_djd) #@UndefinedVariable - t = djd_to_timestamp(djd) - vt = (t, "unix_epoch", "group_time") - return weewx.units.ValueHelper(vt, context="year", formatter=self.formatter) + return weewx.units.ValueHelper((djd, "dublin_jd", "group_time"), + context="year", formatter=self.formatter) else: raise AttributeError, "Unknown attribute "+attr @@ -266,9 +267,7 @@ class BodyWrapper(object): # being examined. So, create a temporary body and then throw it away temp_body = self.body_factory() time_djd = getattr(self.observer, attr)(temp_body) - time_ts = djd_to_timestamp(time_djd) - vh = weewx.units.ValueHelper((time_ts, "unix_epoch", "group_time"), context="day", formatter=self.formatter) - return vh + return weewx.units.ValueHelper((time_djd, "dublin_jd", "group_time"), context="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. @@ -279,9 +278,7 @@ class BodyWrapper(object): fn = fn_map[attr] # Call the function, with a second argument giving the start-of-day time_djd = getattr(self.observer, fn)(temp_body, self.sod_djd) - time_ts = djd_to_timestamp(time_djd) - vh = weewx.units.ValueHelper((time_ts, "unix_epoch", "group_time"), context="day", formatter=self.formatter) - return vh + return weewx.units.ValueHelper((time_djd, "dublin_jd", "group_time"), context="day", formatter=self.formatter) else: # Just return the result unchanged. return getattr(self.body, attr) 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..a53795a5 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 @@ -336,7 +338,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/skins/Standard/index.html.tmpl b/skins/Standard/index.html.tmpl index 4f703bb3..31294d84 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,97 @@

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 + #set $sun_az = "%.1f°" % $almanac.sun.az + #set $sun_alt= "%.1f°" % $almanac.sun.alt + + + + + + + + + + + + + + + #end if +
Sun
Sunrise:$almanac.sun.rise
Transit:$almanac.sun.transit
Sunset:$almanac.sun.set
Sunrise:$almanac.sunrise
Sunset:$almanac.sunset
Azimuth:$sun_az
Altitude:$sun_alt
Equinox:$almanac.next_equinox +
Solstice:$almanac.next_solstice +
+
+
+ + + + + + + #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
Full moon:$almanac.next_full_moon +
New moon:$almanac.next_new_moon +
+
+
From cc2f1700a593c59e08e7c059e535aac2010de44d Mon Sep 17 00:00:00 2001 From: Tom Keffer Date: Tue, 29 Mar 2011 16:34:50 +0000 Subject: [PATCH 07/11] Refined formatting of almanac data. Added time contexts 'ephem_day' and 'ephem_year'. --- bin/weewx/almanac.py | 6 +- bin/weewx/units.py | 17 ++- docs/customizing.htm | 10 +- skins/Standard/index.html.tmpl | 14 +-- skins/Standard/skin.conf | 14 ++- skins/Standard/weewx.css | 203 +++++++++++++++++++++++++++++++-- 6 files changed, 230 insertions(+), 34 deletions(-) diff --git a/bin/weewx/almanac.py b/bin/weewx/almanac.py index 8a690b8f..607c9ead 100644 --- a/bin/weewx/almanac.py +++ b/bin/weewx/almanac.py @@ -202,7 +202,7 @@ class Almanac(object): # This is how you call a function on an instance when all you have is its name: djd = ephem.__dict__[attr](self.time_djd) #@UndefinedVariable return weewx.units.ValueHelper((djd, "dublin_jd", "group_time"), - context="year", formatter=self.formatter) + context="ephem_year", formatter=self.formatter) else: raise AttributeError, "Unknown attribute "+attr @@ -267,7 +267,7 @@ class BodyWrapper(object): # being examined. So, create a temporary body and then throw it away temp_body = self.body_factory() time_djd = getattr(self.observer, attr)(temp_body) - return weewx.units.ValueHelper((time_djd, "dublin_jd", "group_time"), context="day", formatter=self.formatter) + 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. @@ -278,7 +278,7 @@ class BodyWrapper(object): fn = fn_map[attr] # 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="day", formatter=self.formatter) + 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) diff --git a/bin/weewx/units.py b/bin/weewx/units.py index a53795a5..0b2b5d96 100644 --- a/bin/weewx/units.py +++ b/bin/weewx/units.py @@ -239,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"} #=============================================================================== @@ -301,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): diff --git a/docs/customizing.htm b/docs/customizing.htm index 16c606c1..f8f04add 100644 --- a/docs/customizing.htm +++ b/docs/customizing.htm @@ -791,7 +791,8 @@ December: Min, max temperatures: N/A N/A
Azimuth, altitude of mars: $almanac.mars.az $almanac.mars.alt
Next new, full moon: $almanac.next_new_moon $almanac.next_full_moon
Next summer, winter solstice: $almanac.next_summer_solstice $almanac.next_winter_solstice
-
 
+

The included almanac includes information for the Sun, Moon, Venus, Mars, + and Jupiter.

Writing a custom generator

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

@@ -1050,6 +1051,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/skins/Standard/index.html.tmpl b/skins/Standard/index.html.tmpl index 31294d84..b8722b4b 100644 --- a/skins/Standard/index.html.tmpl +++ b/skins/Standard/index.html.tmpl @@ -348,15 +348,13 @@ #end if #if $almanac.hasExtras - #set $sun_az = "%.1f°" % $almanac.sun.az - #set $sun_alt= "%.1f°" % $almanac.sun.alt Azimuth: - $sun_az + $("%.1f°" % $almanac.sun.az) Altitude: - $sun_alt + $("%.1f°" % $almanac.sun.alt) Equinox: @@ -374,7 +372,7 @@ Moon Phase: - $almanac.moon_phase ($almanac.moon_fullness% full) + $almanac.moon_phase
($almanac.moon_fullness% full) #if $almanac.hasExtras @@ -389,15 +387,13 @@ Set: $almanac.moon.set - #set $moon_az = "%.1f°" % $almanac.moon.az - #set $moon_alt= "%.1f°" % $almanac.moon.alt Azimuth: - $moon_az + $("%.1f°" % $almanac.moon.az) Altitude: - $moon_alt + $("%.1f°" % $almanac.moon.alt) Full moon: 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; } - From 72ac97444f189b079ba280f1c40d2e6a2550a4f5 Mon Sep 17 00:00:00 2001 From: Tom Keffer Date: Tue, 29 Mar 2011 18:50:46 +0000 Subject: [PATCH 08/11] v1.10.0b1 --- MANIFEST | 2 +- bin/weewx/__init__.py | 2 +- docs/customizing.htm | 45 +++++++++++++++++++++++++++------- skins/Standard/index.html.tmpl | 8 +++--- weewx.conf | 2 +- 5 files changed, 43 insertions(+), 16 deletions(-) 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..27d15b95 100644 --- a/bin/weewx/__init__.py +++ b/bin/weewx/__init__.py @@ -12,7 +12,7 @@ """ import time -__version__="1.10.0a6" +__version__="1.10.0b1" # Holds the program launch time in unix epoch seconds: # Useful for calculating 'uptime.' diff --git a/docs/customizing.htm b/docs/customizing.htm index f8f04add..78e74ee9 100644 --- a/docs/customizing.htm +++ b/docs/customizing.htm @@ -784,15 +784,42 @@ December: Min, max temperatures: N/A N/A

Almanac

If module pyephem has been installed, then weewx can generate extensive - almanac information. Here is a sampling:

-
Sunrise, transit, sunset: $almanac.sun.rise $almanac.sun.transit $almanac.sun.set
-
Moonrise, transit, moonset: $almanac.moon.rise $almanac.moon.transit $almanac.moon.set
-
Mars rise, transit, set: $almanac.mars.rise $almanac.mars.transit $almanac.mars.set
-
Azimuth, altitude of mars: $almanac.mars.az $almanac.mars.alt
-
Next new, full moon: $almanac.next_new_moon $almanac.next_full_moon
-
Next summer, winter solstice: $almanac.next_summer_solstice $almanac.next_winter_solstice
-

The included almanac includes information for the Sun, Moon, Venus, Mars, - and Jupiter.

+ 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.

diff --git a/skins/Standard/index.html.tmpl b/skins/Standard/index.html.tmpl index b8722b4b..461c47d6 100644 --- a/skins/Standard/index.html.tmpl +++ b/skins/Standard/index.html.tmpl @@ -370,10 +370,6 @@
- - - - #if $almanac.hasExtras @@ -404,6 +400,10 @@ #end if + + + +
Moon
Phase:$almanac.moon_phase
($almanac.moon_fullness% full)
Rise:$almanac.next_new_moon
Phase:$almanac.moon_phase
($almanac.moon_fullness% full)
diff --git a/weewx.conf b/weewx.conf index 9dc2cea4..8d3825a5 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.0b1 ############################################################################################ From 449d63b9c030b069da324de7ccb61158e7e9baeb Mon Sep 17 00:00:00 2001 From: Tom Keffer Date: Tue, 29 Mar 2011 19:23:18 +0000 Subject: [PATCH 09/11] Fixed a collation problem when comparing 'v1.9' to 'v1.10' in setup.py --- bin/weewx/__init__.py | 2 +- setup.py | 8 +++++++- weewx.conf | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/bin/weewx/__init__.py b/bin/weewx/__init__.py index 27d15b95..8bc16415 100644 --- a/bin/weewx/__init__.py +++ b/bin/weewx/__init__.py @@ -12,7 +12,7 @@ """ import time -__version__="1.10.0b1" +__version__="1.10.0" # Holds the program launch time in unix epoch seconds: # Useful for calculating 'uptime.' 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/weewx.conf b/weewx.conf index 8d3825a5..ed44643b 100644 --- a/weewx.conf +++ b/weewx.conf @@ -29,7 +29,7 @@ debug = 0 socket_timeout = 20 # Current version -version = 1.10.0b1 +version = 1.10.0 ############################################################################################ From 051c9f696ddd3ce6f9adb4b6b0f9fa9b6a8c4ab0 Mon Sep 17 00:00:00 2001 From: Tom Keffer Date: Tue, 29 Mar 2011 19:24:51 +0000 Subject: [PATCH 10/11] Updated CHANGES.TXT --- CHANGES.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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. From c04aaba4c65667a0a675fe9961b535bb0953e43d Mon Sep 17 00:00:00 2001 From: Tom Keffer Date: Tue, 29 Mar 2011 19:27:01 +0000 Subject: [PATCH 11/11] Updated CHANGES.TXT