diff --git a/MANIFEST b/MANIFEST
index b54b485d..f95ffb25 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -50,15 +50,16 @@ bin/weewx/uwxutils.py
bin/weewx/wxengine.py
bin/weewx/wxformulas.py
bin/weewx/drivers/__init__.py
-bin/weewx/drivers/ads.py
+bin/weewx/drivers/cc3000.py
bin/weewx/drivers/fousb.py
-bin/weewx/drivers/peetbros.py
bin/weewx/drivers/simulator.py
bin/weewx/drivers/te923.py
+bin/weewx/drivers/ultimeter.py
bin/weewx/drivers/vantage.py
bin/weewx/drivers/wmr100.py
bin/weewx/drivers/wmr200.py
bin/weewx/drivers/wmr9x8.py
+bin/weewx/drivers/ws1.py
bin/weewx/drivers/ws23xx.py
bin/weewx/drivers/ws28xx.py
docs/changes.txt
diff --git a/bin/wee_config_vantage b/bin/wee_config_vantage
index ca2ab343..61b27f78 100755
--- a/bin/wee_config_vantage
+++ b/bin/wee_config_vantage
@@ -330,7 +330,7 @@ def set_rain_year_start(station, rain_year_start):
def set_time(station):
print "Setting time on console..."
- station.setTime(time.time())
+ station.setTime()
newtime_ts = station.getTime()
print "Current console time is %s" % weeutil.weeutil.timestamp_to_string(newtime_ts)
diff --git a/bin/wee_config_ws23xx b/bin/wee_config_ws23xx
index 9fbc65f7..7a3cd748 100755
--- a/bin/wee_config_ws23xx
+++ b/bin/wee_config_ws23xx
@@ -132,15 +132,13 @@ def setclock(station, prompt):
v = station.getTime()
vstr = weeutil.weeutil.timestamp_to_string(v)
print "Station clock is", vstr
- now = int(time.time() + 0.5)
- nstr = weeutil.weeutil.timestamp_to_string(now)
if prompt:
- ans = raw_input("Set station clock to %s (y/n)? " % nstr)
+ ans = raw_input("Set station clock (y/n)? ")
else:
- print "Setting station clock to %s" % nstr
+ print "Setting station clock"
ans = 'y'
if ans == 'y' :
- station.setTime(now)
+ station.setTime()
v = station.getTime()
vstr = weeutil.weeutil.timestamp_to_string(v)
print "Station clock is now", vstr
diff --git a/bin/wee_config_ws28xx b/bin/wee_config_ws28xx
index 618e319f..5ad52a96 100755
--- a/bin/wee_config_ws28xx
+++ b/bin/wee_config_ws28xx
@@ -23,6 +23,7 @@ issues between weather station console and transceiver.
import optparse
import syslog
import time
+import sys
import weewx.drivers.ws28xx
import weewx.units
@@ -49,16 +50,18 @@ def main():
help="pair the USB transceiver with a station console")
parser.add_option("--info", dest="info", action="store_true",
help="display weather station configuration")
+ parser.add_option("--set-interval", dest="interval", type=int, metavar="N",
+ help="set logging interval to N minutes")
parser.add_option("--current", dest="current", action="store_true",
help="get the current weather conditions")
parser.add_option("--history-since", dest="recmin", type=int, metavar="N",
help="display history records since N minutes ago")
parser.add_option("--history", dest="nrecords", type=int, metavar="N",
help="display N history records")
- parser.add_option("--format", dest="format", type=str, metavar="FORMAT",
- help="format for history, one of raw, table, or dict")
parser.add_option("--maxtries", dest="maxtries", type=int,
help="maximum number of retries, 0 indicates no max")
+ parser.add_option("-y", dest="noprompt", action="store_true",
+ help="answer yes to every prompt")
parser.add_option("--debug", dest="debug", action="store_true",
help="display diagnostic information while running")
@@ -75,26 +78,25 @@ def main():
station = weewx.drivers.ws28xx.WS28xx(altitude=altitude_m,
**config_dict['WS28xx'])
- if options.format is None:
- options.format = 'table'
- elif (options.format.lower() != 'raw' and
- options.format.lower() != 'table' and
- options.format.lower() != 'dict'):
- print "Unknown format '%s'. Known formats include 'raw', 'table', and 'dict'." % options.format
- exit(1)
+ if options.noprompt:
+ prompt = False
+ else:
+ prompt = True
maxtries = 3 if options.maxtries is None else int(options.maxtries)
if options.check:
check_transceiver(station, maxtries)
elif options.pair:
pair(station, maxtries)
+ elif options.interval is not None:
+ set_interval(station, maxtries, options.interval, prompt)
elif options.current:
current(station, maxtries)
elif options.nrecords is not None:
- history(station, maxtries, count=options.nrecords, fmt=options.format)
+ history(station, maxtries, count=options.nrecords)
elif options.recmin is not None:
ts = int(time.time()) - options.recmin * 60
- history(station, maxtries, ts=ts, fmt=options.format)
+ history(station, maxtries, ts=ts)
else:
info(station, maxtries)
@@ -106,139 +108,157 @@ def check_transceiver(station, maxtries):
"""See if the transceiver is installed and operational."""
print 'Checking for transceiver...'
ntries = 0
- try:
- while ntries < maxtries:
- ntries += 1
- if station.transceiver_is_present():
- print 'Transceiver is present'
- sn = station.transceiver_serial()
- print 'serial: ' % sn
- tid = station.transceiver_id()
- print 'id: %d (0x%04x)' % (tid, tid)
- break
- print 'Not found (attempt %d of %d) ...' % (ntries, maxtries)
- time.sleep(5)
- else:
- print 'Transceiver not responding.'
- except Exception, e:
- pass
+ while ntries < maxtries:
+ ntries += 1
+ if station.transceiver_is_present():
+ print 'Transceiver is present'
+ sn = station.get_transceiver_serial()
+ print 'serial: %s' % sn
+ tid = station.get_transceiver_id()
+ print 'id: %d (0x%04x)' % (tid, tid)
+ break
+ print 'Not found (attempt %d of %d) ...' % (ntries, maxtries)
+ time.sleep(5)
+ else:
+ print 'Transceiver not responding.'
def pair(station, maxtries):
"""Pair the transceiver with the station console."""
print 'Pairing transceiver with console...'
maxwait = 90 # how long to wait between button presses, in seconds
ntries = 0
- try:
- while ntries < maxtries or maxtries == 0:
- if station.transceiver_is_paired():
- print 'Transceiver is paired to console'
- break
- ntries += 1
- msg = 'Press and hold the [v] key until "PC" appears'
- if maxtries > 0:
- msg += ' (attempt %d of %d)' % (ntries, maxtries)
- else:
- msg += ' (attempt %d)' % ntries
- print msg
- now = start_ts = int(time.time())
- while now - start_ts < maxwait and not station.transceiver_is_paired():
- time.sleep(5)
- now = int(time.time())
+ while ntries < maxtries or maxtries == 0:
+ if station.transceiver_is_paired():
+ print 'Transceiver is paired to console'
+ break
+ ntries += 1
+ msg = 'Press and hold the [v] key until "PC" appears'
+ if maxtries > 0:
+ msg += ' (attempt %d of %d)' % (ntries, maxtries)
else:
- print 'Transceiver not paired to console.'
- except Exception, e:
- pass
+ msg += ' (attempt %d)' % ntries
+ print msg
+ now = start_ts = int(time.time())
+ while now - start_ts < maxwait and not station.transceiver_is_paired():
+ time.sleep(5)
+ now = int(time.time())
+ else:
+ print 'Transceiver not paired to console.'
+
+def get_interval(station, maxtries):
+ cfg = get_config(station, maxtries)
+ if cfg is None:
+ return None
+ return weewx.drivers.ws28xx.getHistoryInterval(cfg['history_interval'])
+
+def get_config(station, maxtries):
+ start_ts = None
+ ntries = 0
+ while ntries < maxtries or maxtries == 0:
+ cfg = station.get_config()
+ if cfg is not None:
+ return cfg
+ ntries += 1
+ if start_ts is None:
+ start_ts = int(time.time())
+ else:
+ dur = int(time.time()) - start_ts
+ print 'No data after %d seconds (press SET to sync)' % dur
+ time.sleep(30)
+ return None
+
+def set_interval(station, maxtries, interval, prompt):
+ """Set the station archive interval"""
+ print 'Querying the station...'
+ v = get_interval(station, maxtries)
+ if v is None:
+ return
+ ans = None
+ while ans not in ['y', 'n']:
+ print "Interval is", v
+ if prompt:
+ ans = raw_input("Set interval to %d minutes (y/n)? " % interval)
+ else:
+ print "Setting interval to %d minutes" % interval
+ ans = 'y'
+ if ans == 'y' :
+ station.set_interval(interval)
+ v = get_interval(station, maxtries)
+ if v is None:
+ print "Cannot confirm change of interval"
+ return
+ print "Interval is now", v
+ elif ans == 'n':
+ print "Set interval cancelled."
def info(station, maxtries):
"""Query the station then display the settings."""
print 'Querying the station for the configuration...'
- start_ts = None
- ntries = 0
- try:
- while ntries < maxtries or maxtries == 0:
- config = station.get_config()
- if config is not None:
- print_dict(config)
- break
- if start_ts is None:
- start_ts = int(time.time())
- else:
- dur = int(time.time()) - start_ts
- print 'No data after %d seconds (press SET to sync)' % dur
- time.sleep(30)
- except Exception:
- pass
+ cfg = get_config(station, maxtries)
+ if cfg is not None:
+ print_dict(cfg)
def current(station, maxtries):
"""Get current weather observation."""
print 'Querying the station for current weather data...'
start_ts = None
ntries = 0
- try:
- while ntries < maxtries or maxtries == 0:
- packet = station.get_observation()
- if packet is not None:
- print_dict(packet)
- break
- if start_ts is None:
- start_ts = int(time.time())
- else:
- dur = int(time.time()) - start_ts
- print 'No data after %d seconds (press SET to sync)' % dur
- time.sleep(30)
- except Exception:
- pass
+ while ntries < maxtries or maxtries == 0:
+ packet = station.get_observation()
+ if packet is not None:
+ print_dict(packet)
+ break
+ ntries += 1
+ if start_ts is None:
+ start_ts = int(time.time())
+ else:
+ dur = int(time.time()) - start_ts
+ print 'No data after %d seconds (press SET to sync)' % dur
+ time.sleep(30)
-def history(station, maxtries, ts=0, count=0, fmt='raw'):
+def history(station, maxtries, ts=0, count=0):
"""Display the indicated number of records or the records since the
specified timestamp (local time, in seconds)"""
print "Querying the station for historical records..."
- records = []
- start_ts = None
ntries = 0
- try:
- while ntries < maxtries or maxtries == 0:
- records = station.get_history(since_ts=ts, num_rec=count)
- if records is not None:
- break
- if start_ts is None:
- start_ts = int(time.time())
- else:
- dur = int(time.time()) - start_ts
- print 'No data after %d seconds (press SET to sync)' % dur
- time.sleep(30)
- except Exception:
- pass
-
- for i,r in enumerate(records):
- if fmt.lower() == 'raw':
- raw_dump(r['datetime'], r['ptr'], r['raw_data'])
- elif fmt.lower() == 'table':
- table_dump(r['datetime'], r['data'], i==0)
+ last_n = n = None
+ last_ts = now = int(time.time())
+ station.start_caching_history(since_ts=ts)
+ t = weewx.drivers.ws28xx.WS28xx.max_records
+ while n is None or n > 0:
+ if ntries >= maxtries:
+ print 'Giving up after %d tries' % ntries
+ break
+ time.sleep(30)
+ now = int(time.time())
+ n = station.get_num_history_scanned()
+ if n == last_n:
+ ntries += 1
+ dur = now - last_ts
+ print 'No data after %d seconds (press SET to sync)' % dur
else:
- print r['datetime'], r['data']
-
-def raw_dump(date, pos, data):
- print date,
- print "%04x" % pos,
- for item in data:
- print "%02x" % item,
- print
-
-def table_dump(date, data, showlabels=False):
- if showlabels:
- print '# date time',
- for key in data:
- print key,
- print
- print date,
- for key in data:
- print data[key],
+ ntries = 0
+ last_ts = now
+ last_n = n
+ ni = station.get_next_history_index()
+ li = station.get_latest_history_index()
+ msg = " scanned %s of %s: current=%s latest=%s\r" % (n, t, ni, li)
+ sys.stdout.write(msg)
+ sys.stdout.flush()
+ station.stop_caching_history()
+ records = station.get_history_cache_records()
+ station.clear_history_cache()
print
+ print 'Found a total of %d records' % len(records)
+ for r in records:
+ print r
def print_dict(data):
- for key in sorted(data, key=data.get):
- print '%s: %s' % (key, data[key])
+ for x in sorted(data.keys()):
+ if x == 'dateTime':
+ print '%s: %s' % (x, weeutil.weeutil.timestamp_to_string(data[x]))
+ else:
+ print '%s: %s' % (x, data[x])
if __name__=="__main__" :
diff --git a/bin/weewx/abstractstation.py b/bin/weewx/abstractstation.py
index a54e6555..4bfffbcf 100644
--- a/bin/weewx/abstractstation.py
+++ b/bin/weewx/abstractstation.py
@@ -32,7 +32,7 @@ class AbstractStation(object):
def getTime(self):
raise NotImplementedError("Method 'getTime' not implemented")
- def setTime(self, newtime_ts):
+ def setTime(self):
raise NotImplementedError("Method 'setTime' not implemented")
def closePort(self):
diff --git a/bin/weewx/drivers/cc3000.py b/bin/weewx/drivers/cc3000.py
index 9a3978b1..49bdb1e3 100644
--- a/bin/weewx/drivers/cc3000.py
+++ b/bin/weewx/drivers/cc3000.py
@@ -24,6 +24,7 @@ catchup on startup.
from __future__ import with_statement
import serial
+import string
import syslog
import time
@@ -37,7 +38,7 @@ INHG_PER_MBAR = 0.0295333727
METER_PER_FOOT = 0.3048
MILE_PER_KM = 0.621371
-DRIVER_VERSION = '0.6'
+DRIVER_VERSION = '0.7'
DEFAULT_PORT = '/dev/ttyS0'
def logmsg(level, msg):
@@ -67,18 +68,20 @@ class CC3000(weewx.abstractstation.AbstractStation):
'''weewx driver that communicates with a RainWise CC3000 data logger.'''
# map rainwise names to weewx names
- LABEL_MAP = { 'TIMESTAMP': 'TIMESTAMP',
- 'TEMP OUT': 'outTemp',
- 'HUMIDITY': 'outHumidity',
- 'WIND DIRECTION': 'windDir',
- 'WIND SPEED': 'windSpeed',
- 'WIND GUST': 'windGust',
- 'PRESSURE': 'pressure',
- 'TEMP IN': 'inTemp',
- 'RAIN': 'day_rain_total',
- 'STATION BATTERY': 'consBatteryVoltage',
- 'BATTERY BACKUP': 'bkupBatteryVoltage',
- }
+ DEFAULT_LABEL_MAP = { 'TIMESTAMP': 'TIMESTAMP',
+ 'TEMP OUT': 'outTemp',
+ 'HUMIDITY': 'outHumidity',
+ 'WIND DIRECTION': 'windDir',
+ 'WIND SPEED': 'windSpeed',
+ 'WIND GUST': 'windGust',
+ 'PRESSURE': 'pressure',
+ 'TEMP IN': 'inTemp',
+ 'RAIN': 'day_rain_total',
+ 'STATION BATTERY': 'consBatteryVoltage',
+ 'BATTERY BACKUP': 'bkupBatteryVoltage',
+ 'SOLAR RADIATION': 'radiation',
+ 'UV INDEX': 'UV',
+ }
def __init__(self, **stn_dict):
self.altitude = stn_dict['altitude']
@@ -91,6 +94,7 @@ class CC3000(weewx.abstractstation.AbstractStation):
self.use_station_time = stn_dict.get('use_station_time', True)
self.max_tries = int(stn_dict.get('max_tries', 5))
self.retry_wait = int(stn_dict.get('retry_wait', 60))
+ self.label_map = stn_dict.get('label_map', self.DEFAULT_LABEL_MAP)
self.last_rain = None
@@ -165,9 +169,9 @@ class CC3000(weewx.abstractstation.AbstractStation):
v = station.get_time()
return _to_ts(v)
- def setTime(self, ts):
+ def setTime(self):
with Station(self.port) as station:
- station.set_time(ts)
+ station.set_time()
def get_current(self):
with Station(self.port) as station:
@@ -299,7 +303,7 @@ class CC3000(weewx.abstractstation.AbstractStation):
for i,v in enumerate(values):
if i >= len(self.header):
continue
- label = self.LABEL_MAP.get(self.header[i])
+ label = self.label_map.get(self.header[i])
if label is None:
continue
if label == 'TIMESTAMP':
@@ -323,6 +327,9 @@ def _to_ts(tstr, fmt="%Y/%m/%d %H:%M:%S"):
def _format_bytes(buf):
return ' '.join(["%0.2X" % ord(c) for c in buf])
+def _fmt(buf):
+ return filter(lambda x: x in string.printable, buf)
+
# calculate the crc for a string using CRC-16-CCITT
# http://bytes.com/topic/python/insights/887357-python-check-crc-frame-crc-16-ccitt
def _crc16(data):
@@ -406,11 +413,10 @@ class Station(object):
def command(self, cmd):
self.write("%s\r" % cmd)
data = self.get_data()
- logdbg("station replied to command with '%s'" % data)
data = data.strip()
if data != cmd:
- raise weewx.WeeWxIOError("Command failed: cmd='%s' data='%s'" %
- (cmd, data))
+ raise weewx.WeeWxIOError("Command failed: cmd='%s' reply='%s' (%s)"
+ % (cmd, _fmt(data), _format_bytes(data)))
return self.get_data()
def send_cmd(self, cmd):
@@ -433,7 +439,10 @@ class Station(object):
break
else:
raise weewx.WeeWxIOError("Unexpected byte 0x%0.2X" % ord(c))
- buf.append(c)
+ if c in string.printable:
+ buf.append(c)
+ else:
+ loginf("skipping unprintable character 0x%0.2X" % ord(c))
data = ''.join(buf)
logdbg("got bytes: '%s'" % _format_bytes(data))
_check_crc(data)
@@ -443,7 +452,7 @@ class Station(object):
logdbg("set echo to %s" % cmd)
data = self.command('ECHO=%s' % cmd)
if data != 'OK':
- raise weewx.WeeWxIOError("Set ECHO failed: %s" % data)
+ raise weewx.WeeWxIOError("Set ECHO failed: %s" % _fmt(data))
def get_header(self):
data = self.command("HEADER")
@@ -462,13 +471,13 @@ class Station(object):
def get_memory_status(self):
data = self.command("MEM=?")
- logdbg("memory status: %s" % data)
+ logdbg("memory status: %s" % _fmt(data))
return data
def clear_memory(self):
data = self.command("MEM=CLEAR")
if data != 'OK':
- raise weewx.WeeWxIOError("Failed to clear memory: %s" % data)
+ raise weewx.WeeWxIOError("Failed to clear memory: %s" % _fmt(data))
def gen_records(self, nrec):
"""generator function for getting records from the device"""
@@ -499,13 +508,14 @@ class Station(object):
data = self.command("TIME=?")
return data
- def set_time(self, ts):
- tstr = time.strftime("%Y/%m/%d %H:%M:%S", time.localtime(ts))
- logdbg("set time to %s (%s)" % (tstr, ts))
+ def set_time(self):
+ tstr = time.strftime("%Y/%m/%d %H:%M:%S", time.localtime(time.time()))
+ logdbg("set time to %s (%s)" % (tstr, tstr))
s = "TIME=%s" % tstr
data = self.command(s)
if data != 'OK':
- raise weewx.WeeWxIOError("Failed to set time to %s: %s" % (s,data))
+ raise weewx.WeeWxIOError("Failed to set time to %s: %s" %
+ (s, _fmt(data)))
def get_units(self):
data = self.command("UNITS=?")
@@ -516,7 +526,7 @@ class Station(object):
data = self.command("UNITS=%s" % units)
if data != 'OK':
raise weewx.WeeWxIOError("Failed to set units to %s: %s" %
- (units, data))
+ (units, _fmt(data)))
def get_interval(self):
data = self.command("LOGINT=?")
@@ -527,7 +537,7 @@ class Station(object):
data = self.command("LOGINT=%d" % interval)
if data != 'OK':
raise weewx.WeeWxIOError("Failed to set logging interval: %s" %
- data)
+ _fmt(data))
def get_version(self):
data = self.command("VERSION")
@@ -607,7 +617,7 @@ if __name__ == '__main__':
if options.gettime:
print s.get_time()
if options.settime:
- s.set_time(time.time())
+ s.set_time()
if options.getint:
print s.get_interval()
if options.setint:
diff --git a/bin/weewx/drivers/fousb.py b/bin/weewx/drivers/fousb.py
index bfcc242e..1c07b78a 100644
--- a/bin/weewx/drivers/fousb.py
+++ b/bin/weewx/drivers/fousb.py
@@ -151,6 +151,20 @@ specified in weewx.conf, and 'temperature' is read from the sensors.
The 'barometer' value is reported to wunderground, cwop, etc.
+Illuminance and Radiation
+
+The 30xx stations include a sensor that reports illuminance (lux). The
+conversion from lux to radiation is a function of the angle of the sun and
+altitude, but this driver uses a single multiplier as an approximation.
+
+Apparently the display on fine offset stations is incorrect. The display
+reports radiation with a lux-to-W/m^2 multiplier of 0.001464. Apparently
+Cumulus and WeatherDisplay use a multiplier of 0.0079. The multiplier for
+sea level with sun directly overhead is 0.01075.
+
+This driver uses the sea level multiplier of 0.01075. Use an entry in
+StdCalibrate to adjust this for your location and altitude.
+
From Jim Easterbrook:
The weather station memory has two parts: a "fixed block" of 256 bytes
@@ -260,7 +274,7 @@ keymap = {
'windDir' : ('wind_dir', 22.5), # station is 0-15, weewx wants deg
'windGustDir' : ('wind_dir', 22.5), # station is 0-15, weewx wants deg
'rain' : ('rain', 0.1), # station is mm, weewx wants cm
- 'radiation' : ('illuminance', 0.001464), # lux, weewx wants W/m^2
+ 'radiation' : ('illuminance', 0.01075), # lux, weewx wants W/m^2
'UV' : ('uv', 1.0),
'dewpoint' : ('dewpoint', 1.0),
'heatindex' : ('heatindex', 1.0),
@@ -410,9 +424,10 @@ def pywws2weewx(p, ts, pressure_offset, altitude,
USB_RT_PORT = (usb.TYPE_CLASS | usb.RECIP_OTHER)
USB_PORT_FEAT_POWER = 8
-def power_cycle_station(self, hub, port):
+def power_cycle_station(hub, port):
'''Power cycle the port on the specified hub. This works only with USB
hubs that support per-port power switching such as the linksys USB2HUB4.'''
+ loginf("Attempting to power cycle")
busses = usb.busses()
if not busses:
raise weewx.WeeWxIOError("Power cycle failed: cannot find USB busses")
@@ -432,14 +447,18 @@ def power_cycle_station(self, hub, port):
request=usb.REQ_CLEAR_FEATURE,
value=USB_PORT_FEAT_POWER,
index=port, buffer=None, timeout=1000)
- time.sleep(10)
+ loginf("Waiting 30 seconds for station to power down")
+ time.sleep(30)
loginf("Power on port %d on hub %s" % (port, hub))
handle.controlMsg(requestType=USB_RT_PORT,
request=usb.REQ_SET_FEATURE,
value=USB_PORT_FEAT_POWER,
index=port, buffer=None, timeout=1000)
+ loginf("Waiting 60 seconds for station to power up")
+ time.sleep(60)
finally:
del handle
+ loginf("Power cycle complete")
# decode weather station raw data formats
def _signed_byte(raw, offset):
@@ -658,6 +677,7 @@ class FineOffsetUSB(weewx.abstractstation.AbstractStation):
# minimum interval between polling for data change
self.min_pause = 0.5
+ self.devh = None
self._arcint = None
self._last_rain_loop = None
self._last_rain_ts_loop = None
@@ -702,27 +722,39 @@ class FineOffsetUSB(weewx.abstractstation.AbstractStation):
def archive_interval(self):
return self._archive_interval_minutes() * 60
+ # if power cycling is enabled, loop forever until we get a response from
+ # the weather station.
def _archive_interval_minutes(self):
- if self._arcint is None:
- for i in range(self.max_tries):
+ if self._arcint is not None:
+ return self._arcint
+ if self.pc_hub is not None:
+ while True:
try:
- self._arcint = self.get_fixed_block(['read_period'])
+ self.openPort()
+ self._get_arcint()
break
- except usb.USBError, e:
- logcrt("get archive interval failed attempt %d of %d: %s"
- % (i+1, self.max_tries, e))
- else:
- msg = "Unable to read archive interval after %d tries" % self.max_tries
- if self.pc_hub is not None:
- logerr(msg)
- logerr("Attempting to power cycle")
+ except weewx.WeeWxIOError, e:
+ self.closePort()
power_cycle_station(self.pc_hub, self.pc_port)
- raise weewx.WeeWxIOError("Power cycle complete")
- else:
- raise weewx.WeeWxIOError(msg)
+ else:
+ self._get_arcint()
return self._arcint
+ def _get_arcint(self):
+ for i in range(self.max_tries):
+ try:
+ self._arcint = self.get_fixed_block(['read_period'])
+ return
+ except usb.USBError, e:
+ logcrt("get archive interval failed attempt %d of %d: %s"
+ % (i+1, self.max_tries, e))
+ else:
+ raise weewx.WeeWxIOError("Unable to read archive interval after %d tries" % self.max_tries)
+
def openPort(self):
+ if self.devh is not None:
+ return
+
dev = self._find_device()
if not dev:
logcrt("Cannot find USB device with Vendor=0x%04x ProdID=0x%04x Device=%s" % (self.vendor_id, self.product_id, self.device_id))
@@ -770,8 +802,8 @@ class FineOffsetUSB(weewx.abstractstation.AbstractStation):
# def getTime(self):
# return self.get_clock()
-# def setTime(self, ts):
-# self.set_clock(ts)
+# def setTime(self):
+# self.set_clock()
def genLoopPackets(self):
"""Generator function that continuously returns decoded packets."""
diff --git a/bin/weewx/drivers/simulator.py b/bin/weewx/drivers/simulator.py
index 614e5c8a..4d45eb02 100644
--- a/bin/weewx/drivers/simulator.py
+++ b/bin/weewx/drivers/simulator.py
@@ -186,7 +186,7 @@ class Rain(object):
n_rain_packets = total_rain / Rain.bucket_tip
self.period = int(npackets/n_rain_packets)
self.rain_start = 3600* rain_start
- self.rain_end = rain_start + 3600 * rain_length
+ self.rain_end = self.rain_start + 3600 * rain_length
self.packet_number = 0
def value_at(self, time_ts):
diff --git a/bin/weewx/drivers/te923.py b/bin/weewx/drivers/te923.py
index 4081d336..80eb8b72 100644
--- a/bin/weewx/drivers/te923.py
+++ b/bin/weewx/drivers/te923.py
@@ -161,7 +161,7 @@ import weewx.abstractstation
import weewx.units
import weewx.wxformulas
-DRIVER_VERSION = '0.9'
+DRIVER_VERSION = '0.10'
DEBUG_READ = 0
DEBUG_DECODE = 0
DEBUG_PRESSURE = 0
@@ -674,7 +674,7 @@ class BadRead(weewx.WeeWxIOError):
"""Bogus data length, CRC, header block, or other read failure"""
class Station(object):
- ENDPOINT_IN = 0x01
+ ENDPOINT_IN = 0x81
READ_LENGTH = 0x8
def __init__(self, vendor_id=0x1130, product_id=0x6801,
diff --git a/bin/weewx/drivers/ultimeter.py b/bin/weewx/drivers/ultimeter.py
index 3ec60072..e55c31ec 100644
--- a/bin/weewx/drivers/ultimeter.py
+++ b/bin/weewx/drivers/ultimeter.py
@@ -14,10 +14,44 @@
#
# See http://www.gnu.org/licenses/
-"""Driver for Peet Bros Ultimeter weather stations (except the Ultimeter II).
+"""Driver for Peet Bros Ultimeter weather stations (based on the
+ADS WS1 driver) except the Ultimeter II (now quite old from early 1990s).
-This driver assumes the Ultimeter is emitting data in Peet Bros Data Logger
-mode format.
+Thanks to Steve (sesykes71) for the testing that made this driver possible.
+
+Thanks to Jay Nugent (WB8TKL) and KRK6 for weather-2.kr6k-V2.1
+
+ http://server1.nuge.com/~weather/
+
+To use this driver, put this file in bin/user, then put this in weewx.conf:
+
+[Station]
+ ...
+ station_type = PeetBros
+
+[PeetBros]
+ port = /dev/ttyS0
+ driver = user.peetbros
+
+The driver assumes the Ultimeter is emitting data in Peet Bros Data Logger
+mode format:
+
+!!000000BE02EB000027700000023A023A0025005800000000
+ SSSSXXDDTTTTLLLLPPPPttttHHHHhhhhddddmmmmRRRRWWWW
+
+SSSS - wind speed (0.1 km/h)
+XX - wind direction calibration
+DD - wind direction (0-255)
+TTTT - outdoor temperature (0.1 F)
+LLLL - long term rain (0.01 in)
+PPPP - pressure (0.1 mbar)
+tttt - indoor temperature (0.1 F)
+HHHH - outdoor humidity (0.1 %)
+hhhh - indoor humidity (0.1 %)
+dddd - date (day of year)
+mmmm - time (minute of day)
+RRRR - daily rain (0.01 in)
+WWWW - one minute wind average (0.1 km/h)
Resources for the Ultimeter stations
@@ -27,9 +61,6 @@ Ultimeter Models 2100, 2000, 800, & 100 serial specifications:
Ultimeter 2000 Pinouts and Parsers:
http://www.webaugur.com/ham-radio/52-ultimeter-2000-pinouts-and-parsers.html
-Ultimeter II:
- not supported by this driver
-
All models communicate over an RS-232 compatible serial port using three
wires--RXD, TXD, and Ground (except Ultimeter II which omits TXD). Port
parameters are 2400, 8N1, with no flow control.
@@ -40,17 +71,16 @@ and time of the Ultimeter upon initialization and then sets it into Data
Logger mode for continuous updates.
Modem Mode commands used by the driver
-
>Addddmmmm Set Date and Time (decimal digits dddd = day of year,
mmmm = minute of day; Jan 1 = 0000, Midnight = 0000)
>I Set output mode to Data Logger Mode (continuous output)
+
"""
-# FIXME: eliminate the weewx.XXX classes from the station level
-
from __future__ import with_statement
+import optparse
import serial
import syslog
import time
@@ -61,16 +91,20 @@ import weewx.units
import weewx.uwxutils
import weewx.wxformulas
-INHG_PER_MBAR = 0.0295333727
-METER_PER_FOOT = 0.3048
-MILE_PER_KM = 0.621371
-
-DRIVER_VERSION = '0.11.0'
+DRIVER_VERSION = '0.9.4'
DEFAULT_PORT = '/dev/ttyS0'
-DEBUG_READ = 1
+DEBUG_READ = 0
+
+def _is_hex(c):
+ """Test character for a valid hexadecimal digit."""
+ try:
+ int(c, 16)
+ return True
+ except ValueError:
+ return False
def logmsg(level, msg):
- syslog.syslog(level, 'ultimeter: %s' % msg)
+ syslog.syslog(level, 'peetbros: %s' % msg)
def logdbg(msg):
logmsg(syslog.LOG_DEBUG, msg)
@@ -81,10 +115,14 @@ def loginf(msg):
def logerr(msg):
logmsg(syslog.LOG_ERR, msg)
+def logcrt(msg):
+ logmsg(syslog.LOG_CRIT, msg)
+
def loader(config_dict, engine):
"""Get the altitude, in feet, from the Station section of the dict."""
altitude_m = weewx.units.getAltitudeM(config_dict)
- altitude_ft = altitude_m / METER_PER_FOOT
+ altitude_vt = (altitude_m, 'meter', 'group_altitude')
+ altitude_ft = weewx.units.convert(altitude_vt, 'foot')[0]
station = Ultimeter(altitude=altitude_ft, **config_dict['Ultimeter'])
return station
@@ -94,9 +132,6 @@ class Ultimeter(weewx.abstractstation.AbstractStation):
port - serial port
[Required. Default is /dev/ttyS0]
- model - station model, e.g., 'Ultimeter 2000' or 'Ultimeter 100'
- [Optional. Default is Ultimeter]
-
polling_interval - how often to query the serial interface, seconds
[Optional. Default is 1]
@@ -113,65 +148,16 @@ class Ultimeter(weewx.abstractstation.AbstractStation):
self.polling_interval = float(stn_dict.get('polling_interval', 1))
self.max_tries = int(stn_dict.get('max_tries', 5))
self.pressure_offset = float(stn_dict.get('pressure_offset', 0))
- self.model = stn_dict.get('model', 'Ultimeter')
self.last_rain = None
+ self.last_rain_ts = None
loginf('driver version is %s' % DRIVER_VERSION)
loginf('using serial port %s' % self.port)
- loginf('polling interval is %s' % self.polling_interval)
- loginf('pressure offset is %s' % self.pressure_offset)
+ loginf('polling interval is %s' % str(self.polling_interval))
global DEBUG_READ
DEBUG_READ = int(stn_dict.get('debug_read', DEBUG_READ))
- def getTime(self):
- with Station(self.port) as station:
- return station.get_time()
-
- def setTime(self, ts):
- with Station(self.port) as station:
- station.set_time(ts)
-
def genLoopPackets(self):
- return self.glp1()
-
- def glp1(self):
- # this version of genLoopPackets does the maxtries at station level
- # and keeps the serial port open for an extended time.
- with Station(self.port) as station:
- station.set_logger_mode()
- while True:
- buf = station.get_readings_with_retry()
- data = Station.parse_readings(buf)
- packet = {'dateTime': int(time.time()+0.5),
- 'usUnits' : weewx.US }
- packet.update(data)
- self._augment_packet(packet)
- yield packet
- if self.polling_interval:
- time.sleep(self.polling_interval)
-
- def glp2(self):
- # this version of genLoopPackets does the maxtries at station level
- # and opens the serial port for each data read.
- with Station(self.port) as station:
- station.set_logger_mode()
- while True:
- with Station(self.port) as station:
- buf = station.get_readings_with_retry()
- data = Station.parse_readings(buf)
- packet = {'dateTime': int(time.time()+0.5),
- 'usUnits' : weewx.US }
- packet.update(data)
- self._augment_packet(packet)
- yield packet
- if self.polling_interval:
- time.sleep(self.polling_interval)
-
- def glp3(self):
- # this version of genLoopPackets does the maxtries at driver level
- # and opens the serial port for each data read.
ntries = 0
- with Station(self.port) as station:
- station.set_logger_mode()
while ntries < self.max_tries:
ntries += 1
try:
@@ -179,8 +165,8 @@ class Ultimeter(weewx.abstractstation.AbstractStation):
'usUnits' : weewx.US }
# open a new connection to the station for each reading
with Station(self.port) as station:
- buf = station.get_readings()
- data = Station.parse_readings(buf)
+ bytes = station.get_readings()
+ data = Station.parse_readings(bytes)
packet.update(data)
self._augment_packet(packet)
ntries = 0
@@ -197,17 +183,14 @@ class Ultimeter(weewx.abstractstation.AbstractStation):
@property
def hardware_name(self):
- return self.model
+ return Station.getName()
def _augment_packet(self, packet):
"""add derived metrics to a packet"""
- # the ultimeter appears to report a (calculated) sea-level pressure
- # rather than a raw station (sensor) pressure. so we must
- # back-calculate to find the station pressure.
adjp = packet['barometer']
if self.pressure_offset is not None and adjp is not None:
- adjp += self.pressure_offset * INHG_PER_MBAR # convert to inHg
- # FIXME: second temperature should be 12-hour mean temperature
+ adjp += self.pressure_offset * 0.0295333727 # convert to inHg
+ # FIXME: this is supposed to use mean temperature
packet['pressure'] = weewx.uwxutils.TWxUtilsUS.SeaLevelToStationPressure(adjp, self.altitude, packet['outTemp'], packet['outTemp'], packet['outHumidity'])
packet['altimeter'] = weewx.wxformulas.altimeter_pressure_US(
packet['pressure'], self.altitude, algorithm='aaNOAA')
@@ -225,31 +208,10 @@ class Ultimeter(weewx.abstractstation.AbstractStation):
packet['rain'] = None
self.last_rain = packet['long_term_rain']
- # no wind direction when wind speed is zero
- if not packet['windSpeed']:
- packet['windDir'] = None
-
-def _is_valid_char(c):
- '''See whether a character is a valid hexadecimal digit or hyphen.'''
- if c == '-':
- return True
- try:
- int(c, 16)
- return True
- except ValueError:
- return False
-
-def _hex2int(s, multiplier=None):
- '''Ultimeter puts hyphens in the string when a sensor is not installed.
- When we get a hyphen or any other non-hex character, return None.'''
- v = None
- try:
- v = int(s, 16)
- if multiplier is not None:
- v *= multiplier
- except ValueError:
- pass
- return v
+ # calculate the rain rate
+ packet['rainRate'] = weewx.wxformulas.calculate_rain_rate(
+ packet['rain'], packet['dateTime'], self.last_rain_ts)
+ self.last_rain_ts = packet['dateTime']
class Station(object):
def __init__(self, port):
@@ -257,7 +219,6 @@ class Station(object):
self.baudrate = 2400
self.timeout = 30
self.serial_port = None
- self.max_tries = 5
def __enter__(self):
self.open()
@@ -266,15 +227,30 @@ class Station(object):
def __exit__(self, type, value, traceback):
self.close()
+ @staticmethod
+ def getName(self):
+ return "Ultimeter"
+
def open(self):
logdbg("open serial port %s" % self.port)
self.serial_port = serial.Serial(self.port, self.baudrate,
timeout=self.timeout)
-# self.set_logger_mode()
+
+ # Set date and time as internal clock skews.
+ self.serial_port.write(">A%04d%04d\r"
+ % (time.localtime().tm_yday - 1, time.localtime().tm_min
+ + time.localtime().tm_hour * 60))
+
+ # Set to Data Logger Mode
+ self.serial_port.write(">I\r")
def close(self):
if self.serial_port is not None:
logdbg("close serial port %s" % self.port)
+
+ # Set to Modem Mode (stops Data Logger output)
+ self.serial_port.write(">\r")
+
self.serial_port.close()
self.serial_port = None
@@ -285,7 +261,7 @@ class Station(object):
raise weewx.WeeWxIOError(e)
n = len(buf)
if n != nchar:
- if DEBUG_READ and n:
+ if DEBUG_READ:
logdbg("partial buffer: '%s'" %
' '.join(["%0.2X" % ord(c) for c in buf]))
raise weewx.WeeWxIOError("Read expected %d chars, got %d" %
@@ -298,86 +274,37 @@ class Station(object):
raise weewx.WeeWxIOError("Write expected %d chars, sent %d" %
(len(data), n))
- def flush(self):
- logdbg("flush serial buffer")
- self.serial_port.flushInput()
-
- def get_time(self):
- self.set_logger_mode()
- buf = self.get_readings_with_retry()
- data = Station.parse_readings(buf)
- d = data['day_of_year']
- m = data['minute_of_day']
- tstr = time.localtime()
- y = tstr.tm_year
- s = tstr.tm_sec
- ts = time.mktime((y,0,0,0,0,s,0,0,0)) + d * 86400 + m * 60
- return ts
-
- def set_time(self, ts):
- self.set_modem_mode()
- tstr = time.localtime(ts)
- tcmd = ">A%04d%04d\r" % (
- tstr.tm_yday - 1, tstr.tm_min + tstr.tm_hour * 60)
- logdbg("set station time to %d (%s)" % (ts, tcmd))
- self.write(tcmd)
-
- # year works only for models 2004 and later
- y = tstr.tm_year
- ycmd = ">U%s" % y
- logdbg("set station year to %s (%s)" % (y, ycmd))
- self.write(ycmd)
-
- def set_logger_mode(self):
- # in logger mode, station sends logger mode records continuously
- logdbg("set station to logger mode")
- self.write(">I\r")
-
- def set_modem_mode(self):
- # modem mode is available only on models 2004 and later
- # not available on pre-2004 models 50/100/500/700/800
- logdbg("set station to modem mode")
- self.write(">\r")
-
- def get_readings_with_retry(self):
- ntries = 0
- while ntries < self.max_tries:
- ntries += 1
- try:
- return self.get_readings()
- except weewx.WeeWxIOError, e:
- logerr("Failed attempt %d of %d to get readings: %s" %
- (ntries, self.max_tries, e))
- else:
- msg = "Max retries (%d) exceeded for readings" % self.max_tries
- logerr(msg)
- raise weewx.RetriesExceeded(msg)
- return []
-
def get_readings(self):
- buf = []
+ bytes = []
while True:
c = self.read(1)
if c == "\r" or c == "\n":
break
- elif c == '!' and len(buf) > 0:
+ elif c == '!' and len(bytes) > 0:
break
elif c == '!':
- buf = []
- elif _is_valid_char(c):
- buf.append(c)
+ bytes = []
+ elif c == '-':
+ # Ultimeter may put hyphens in the string if a sensor
+ # is not installed. Make the reading zero instead.
+ bytes.append('0')
+ elif _is_hex(c) is True:
+ # Ultimeter uses hexadecimal characters for its values.
+ # Guard against garbage.
+ bytes.append(c)
else:
- raise weewx.WeeWxIOError("Invalid character %0.2X" % ord(c))
+ bytes = []
if DEBUG_READ:
- logdbg("bytes: '%s'" % ' '.join(["%0.2X" % ord(c) for c in buf]))
- if len(buf) != 48:
- raise weewx.WeeWxIOError("Got %d bytes, expected 48" % len(buf))
- return ''.join(buf)
+ logdbg("bytes: '%s'" % ' '.join(["%0.2X" % ord(c) for c in bytes]))
+ if len(bytes) != 48:
+ raise weewx.WeeWxIOError("Got %d bytes, expected 48" % len(bytes))
+ return ''.join(bytes)
@staticmethod
- def parse_readings(buf):
- '''Parse the bytes in data logger format. Each line has 2 header
- bytes, 48 data bytes, and a carriage return and newline:
+ def parse_readings(bytes):
+ '''Ultimeter stations emit data in PeetBros format. Each line has 52
+ characters - 2 header bytes, 48 data bytes, and a carriage return
+ and line feed (new line):
!!000000BE02EB000027700000023A023A0025005800000000\r\n
SSSSXXDDTTTTLLLLPPPPttttHHHHhhhhddddmmmmRRRRWWWW
@@ -396,24 +323,30 @@ class Station(object):
RRRR - daily rain (0.01 in)
WWWW - one minute wind average (0.1 kph)
+ For date, time, and other non-standard readings use labels that
+ will not interfere with weewx/wview conventions.
+
"pressure" reported by the Ultimeter 2000 is correlated to the local
official barometer reading as part of the setup of the station
console so this value is assigned to the 'barometer' key and
the pressure and altimeter values are calculated from it.
+
+ My Ultimeter 2000 puts hyphens, '-', in the place of the indoor
+ humidity (hhhh) since there is no indoor humidty sensor installed.
+ The driver will identify the hyphens and replace them with the '0'
+ character.
'''
data = {}
- data['windSpeed'] = _hex2int(buf[0:4], 0.1 * MILE_PER_KM) # mph
- data['windDir'] = _hex2int(buf[6:8], 1.411764) # compass degrees
- data['outTemp'] = _hex2int(buf[8:12], 0.1) # degree_F
- data['long_term_rain'] = _hex2int(buf[12:16], 0.01) # inch
- data['barometer'] = _hex2int(buf[16:20], 0.1 * INHG_PER_MBAR) # inHg
- data['inTemp'] = _hex2int(buf[20:24], 0.1) # degree_F
- data['outHumidity'] = _hex2int(buf[24:28], 0.1) # percent
- data['inHumidity'] = _hex2int(buf[28:32], 0.1) # percent
- data['day_of_year'] = _hex2int(buf[32:36])
- data['minute_of_day'] = _hex2int(buf[36:40])
- data['daily_rain'] = _hex2int(buf[40:44], 0.01) # inch
- data['wind_average'] = _hex2int(buf[44:48], 0.1 * MILE_PER_KM) # mph
+ data['windSpeed'] = int(bytes[0:4], 16) * 0.1 * 0.621371 # mph
+ data['windDir'] = int(bytes[6:8], 16) * 1.411764 # compass degrees
+ data['outTemp'] = int(bytes[8:12], 16) * 0.1 # degree_F
+ data['long_term_rain'] = int(bytes[12:16], 16) * 0.01 # inch
+ data['barometer'] = int(bytes[16:20], 16) * 0.1 * 0.0295333727 # inHg
+ data['inTemp'] = int(bytes[20:24], 16) * 0.1 # degree_F
+ data['outHumidity'] = int(bytes[24:28], 16) * 0.1 # percent
+ data['inHumidity'] = int(bytes[28:32], 16) * 0.1 # percent
+ data['daily_rain'] = int(bytes[40:44], 16) * 0.01 # inch
+ data['wind_average'] = int(bytes[44:48], 16) * 0.1 * 0.621371 # mph
return data
# define a main entry point for basic testing of the station without weewx
@@ -422,7 +355,6 @@ class Station(object):
# PYTHONPATH=bin python bin/weewx/drivers/ultimeter.py
if __name__ == '__main__':
- import optparse
usage = """%prog [options] [--help]"""
@@ -435,26 +367,14 @@ if __name__ == '__main__':
parser.add_option('--port', dest='port', metavar='PORT',
help='serial port to which the station is connected',
default=DEFAULT_PORT)
- parser.add_option('--get-current', dest='getcur', action='store_true',
- help='display current readings')
- parser.add_option('--get-time', dest='gettime', action='store_true',
- help='display station time')
(options, args) = parser.parse_args()
if options.version:
- print "PeetBros Ultimeter driver version %s" % DRIVER_VERSION
+ print "ultimeter driver version %s" % DRIVER_VERSION
exit(0)
with Station(options.port) as s:
- if options.getcur:
- s.set_logger_mode()
- buf = s.get_readings_with_retry()
- print buf
- data = Station.parse_readings(buf)
- print data
- if options.gettime:
- ts = s.get_time()
- print ts
+ print s.get_readings()
if __name__ == '__main__':
main()
diff --git a/bin/weewx/drivers/vantage.py b/bin/weewx/drivers/vantage.py
index cecd5825..b0509d12 100644
--- a/bin/weewx/drivers/vantage.py
+++ b/bin/weewx/drivers/vantage.py
@@ -637,24 +637,26 @@ class Vantage(weewx.abstractstation.AbstractStation):
syslog.syslog(syslog.LOG_ERR, "vantage: Max retries exceeded while getting time")
raise weewx.RetriesExceeded("While getting console time")
- def setTime(self, newtime_ts):
- """Set the clock on the Davis Vantage console
+ def setTime(self):
+ """Set the clock on the Davis Vantage console"""
- newtime_ts: The time the internal clock should be set to in unix epoch time."""
-
- # Unfortunately, this algorithm takes a little while to execute, so the clock
- # usually ends up a few hundred milliseconds slow
- newtime_tt = time.localtime(int(newtime_ts + 0.5))
-
- # The Davis expects the time in reversed order, and the year is since 1900
- _buffer = struct.pack("Customizing weewx
- Version: 3.0.0a1
+ Version: 2.6.4
Table of Contents
@@ -157,8 +157,9 @@ table#stattypes td {
that it they do not actually generate anything. Instead, they use the
reporting service engine to arrange for things to be transferred to a
remote server.
Each report has a Skin associated with it. For most reports, +
Each report has a skin associated with it. For most reports, the relationship with the skin is an obvious one: it contains the templates, any auxiliary files such as background GIFs or CSS style sheets, and a skin configuration file, skin.conf. @@ -190,12 +191,22 @@ table#stattypes td { }); +
A template is a text file that is processed by + weewx to create a new file. A template may + be used to generate HTML, XML, CSV, javascript, or any other type of + text file. A template typically contains variables that are replaced + by when creating the new file. Templates may also contain programming + logic.
+Each template file lives in the skin directory of the skin that uses + it. By convention, a template file ends with the .tmpl extension.
+To create their output, skins rely on one or more Generators, code +
To create their output, skins rely on one or more Generators that actually create useful things such as HTML files or plot images. Generators can also copy files around or FTP/rsync them to remote - locations. The default install of weewx includes - the following generators:
+ locations. The default install of weewx + includes the following generators:| Comment | ||||
| (no tag) | +(no tag) | Value is returned as a string, formatted using an appropriate string format from skin.conf. A unit label (e.g., °F) from skin.conf is also attached @@ -644,7 +661,7 @@ or in foobar units: $day.barometer.min.foobar | ||
| .nolabel(string_format, NONE_string) | +.nolabel(string_format, NONE_string) | Value is returned as a string, using the string format specified with string_format. If the value is None, the string NONE_string will be @@ -677,7 +694,7 @@ or in foobar units: $day.barometer.min.foobar | Returned Value | |
| (no tag) | +(no tag) | From skin.conf | From skin.conf | From skin.conf | @@ -843,8 +860,8 @@ or in foobar units: $day.barometer.min.foobar
Note:
- To enable uploads such as Weather Underground or to customize reports, modify the configuration file /etc/weewx.conf. See the User Guide and Customization Guide for details. + To enable uploads such as Weather Underground or to customize reports, modify the configuration file /etc/weewx/weewx.conf. See the User Guide and Customization Guide for details.
weewx must be restarted for configuration diff --git a/docs/redhat.htm b/docs/redhat.htm index 167c04d1..00c35f3a 100644 --- a/docs/redhat.htm +++ b/docs/redhat.htm @@ -123,7 +123,7 @@
- To enable uploads such as Weather Underground or to customize reports, modify the configuration file /etc/weewx.conf. See the User Guide and Customization Guide for details. + To enable uploads such as Weather Underground or to customize reports, modify the configuration file /etc/weewx/weewx.conf. See the User Guide and Customization Guide for details.
weewx must be restarted for configuration file diff --git a/docs/setup.htm b/docs/setup.htm index 78bd7a05..f901b05c 100644 --- a/docs/setup.htm +++ b/docs/setup.htm @@ -230,9 +230,9 @@ function showstartup(id) {
Run the main program from the command line:
+Run the main program directly:
cd /home/weewx - ./bin/weewxd weewx.conf
+ sudo ./bin/weewxd weewx.confOr as a daemon automatically when the computer starts:

- To enable uploads such as Weather Underground or to customize reports, modify the configuration file /etc/weewx.conf. See the User Guide and Customization Guide for details. + To enable uploads such as Weather Underground or to customize reports, modify the configuration file /home/weewx/weewx.conf. See the User Guide and Customization Guide for details.
weewx must be restarted for configuration file diff --git a/docs/suse.htm b/docs/suse.htm index 493936f5..bd29da22 100644 --- a/docs/suse.htm +++ b/docs/suse.htm @@ -121,7 +121,7 @@
- To enable uploads such as Weather Underground or to customize reports, modify the configuration file /etc/weewx.conf. See the User Guide and Customization Guide for details. + To enable uploads such as Weather Underground or to customize reports, modify the configuration file /etc/weewx/weewx.conf. See the User Guide and Customization Guide for details.
weewx must be restarted for configuration file diff --git a/docs/upgrading.htm b/docs/upgrading.htm index 46cff942..90c5d19e 100644 --- a/docs/upgrading.htm +++ b/docs/upgrading.htm @@ -15,7 +15,7 @@
This section is for configuring the StdConvert - service. This service acts as a filter, converting the unit system coming off - your hardware to a target output unit system. Everything that follows, including - the archiving service, will use the target unit system. Hence, your data - will be stored using your chosen unit system.
-Once chosen, it cannot be changed! Weewx does not allow you to mix - unit systems within the databases. You must chose one or the other and then - stick with it. This means that users coming from wview (which uses US Customary) - should not change the default setting. Having said this, there is a way of reconfiguring - the database to use another unit system. See the section +
This section is for configuring the StdConvert + service.
+Note!
+ If you would like to change the units that are displayed
+ in plots or files, you should make changes to the skin as described in
+ the Customizing Guide, under section
+ Changing options.
+
The StdConvert service acts as a filter, + converting the unit system coming off your hardware to a target output + unit system. Everything that follows, including the archiving service, + will use the target unit system. Hence, your data will be stored using + your chosen unit system.
+Once chosen, it cannot be changed! Weewx does not allow you to + mix unit systems within the databases. You must chose one or the other + and then stick with it. This means that users coming from wview (which + uses US Customary) should not change the default setting. Having said + this, there is a way of reconfiguring the database to use another unit + system. See the section Changing the unit system in the Customizing Guide.
-Note that whatever you choose here, it does not affect your options for the - unit system to be used for reporting. Because of this, unless you - have a special purpose application, there is really no good reason to change - from the default, which is US.
-Warning!
- If, despite these precautions, you do
- decide to change to Metric, be sure to read the sections
- [StdCalibrate] and
- [StdQC] below, and change the units there as well!
Note that whatever you choose here, it does not affect your options for + the unit system to be used for reporting. Because of this, unless + you have a special purpose application, there is really no good reason to + change from the default, which is US.
+Warning!
+ If, despite these precautions, you do decide to change the units of data
+ stored in the database, be sure to read the sections
+ [StdCalibrate] and
+ [StdQC], and change the
+ units there as well!
target_unit
Set to either US, METRICWX, or METRIC. The difference between @@ -2003,7 +2014,7 @@ report_services = weewx.wxengine.StdPrint, weewx.wxengine.StdReport configuration utilities supplied with weewx. Directions follow for
The configuration utility wee_config_fousb is designed to diagnose and configure Fine Offset stations.
Run it with --help as an option to see its usage:
@@ -2536,7 +2547,7 @@ Mutating actions will request confirmation before proceeding. option.$BIN_ROOT/wee_config_cc3000 --info
This will result in something like this:
-firmware: Rainwise CC-3000 Version: 1.3 Build 002 Jun 05 2013
+ firmware: Rainwise CC-3000 Version: 2.6.4
time: 2014/06/02 08:22:17
units: ENGLISH
memory: 251372 bytes, 4334 records, 12%
@@ -2590,14 +2601,13 @@ mysql> GRANT select, update, create, delete, insert ON stats.* TO weewx@local
[StdArchive] for details.
Running weewx
- Weewx can be run either from the command line
- (useful for diagnostic purposes because it will print out a summary of
- every LOOP data), or as a daemon. When first trying
- weewx, it is best to run it from the command
- line because you will be able to see command line diagnostics, as well
+
Weewx can be run either directly,
+ or as a daemon. When first trying
+ weewx, it is best to run it directly
+ because you will be able to see sensor output and diagnostics, as well
as log messages. Once everything is working properly, run it as a
daemon.
- Running from the command line
+ Running directly
To run weewx directly, invoke
the main program, weewxd, giving
the configuration file as its only parameter:
@@ -2610,7 +2620,8 @@ mysql> GRANT select, update, create, delete, insert ON stats.* TO weewx@local
Weewx will then start monitoring live sensor
data (also referrred to as 'LOOP' data),
printing a short version of the received data on standard output, about
- once every two seconds.
+ once every two seconds for a Vantage station, or considerably longer
+ for some other stations.
You can tell a running instance of weewx to
reread its configuration file by sending it the
HUP signal.
@@ -2821,21 +2832,27 @@ sudo /etc/init.d/apache2 restart
weewx.
- Configuration.
+ It is not necessary to backup the images and HTML files generated from
+ templates, since weewx will easily create those again. This includes
+ the NOAA reports in some skins.
+
+ Configuration
+
Save the weewx.conf file.
| setup.py | +setup.py: | /home/weewx/weewx.conf |
| DEB/RPM | +DEB/RPM: | /etc/weewx/weewx.conf |
- Weather data. Meteorological ata are saved in the + Meteorological data are saved in the archive database. For a Sqlite configuration, simply save the weewx.sdb file. For a MySQL configuration, save a dump of the archive database. @@ -2844,49 +2861,48 @@ sudo /etc/init.d/apache2 restart
| setup.py | +setup.py: | /home/weewx/archive/weewx.sdb |
| DEB/RPM | +DEB/RPM: | /var/lib/weewx/weewx.sdb |
- Skins and templates. - Save the contents of the skins directory. + Save the contents of the skins directory if you have modified the default + skin or if you have added any new skins or template files.
| setup.py | +setup.py: | /home/weewx/skins |
| DEB/RPM | +DEB/RPM: | /etc/weewx/skins |
- Other customizations. Save the contents of the + Save the contents of the user directory if you have modified the database schema or added any extensions. If the extensions save data to a database you should backup those databases as well.
| setup.py | +setup.py: | /home/weewx/bin/user |
| DEB/RPM | +DEB/RPM: | /usr/share/weewx/user |
- It is not necessary to backup the images and HTML files generated from - templates, since weewx will easily create those again. This includes - the NOAA reports in some skins. -
+ +To restore from backup, do a fresh install of weewx then replace the default files with @@ -2907,13 +2923,13 @@ sudo /etc/init.d/apache2 restart
tail -f /var/log/messages
+sudo tail -f /var/log/syslog
$BIN_ROOT/weewxd $CONFIG_ROOT/weewx.conf
+sudo $BIN_ROOT/weewxd $CONFIG_ROOT/weewx.conf
These are errors in the configuration file. Two are very common. Incidentally, these errors are far easier to diagnose when - weewx is run from the command line.
+ weewx is run directly than when it is run + as a daemon.This error is caused by using an identifier more than once in the configuration file. For example, you may have inadvertently listed @@ -3558,8 +3575,8 @@ port = /dev/cuaU0 rate of V3.X this is unlikely to happen anytime soon. In any case, I doubt the transition will affect the average weewx user.
All writes to the databases are protected by transactions. You can kill the - program at any time (either Control-C if run from the command line or "/etc/init.d/weewx - stop" if a daemon) without fear of corrupting the databases.
+ program at any time (either Control-C if run directly or "/etc/init.d/weewx + stop" if run as a daemon) without fear of corrupting the databases.The code makes ample use of exceptions to insure graceful recovery from problems such as network outages. It also monitors socket and console timeouts, restarting whatever it was working on several times before giving up. In the case of an @@ -3690,7 +3707,9 @@ port = /dev/cuaU0 stations use an odd mix of US and metric. The Fine Offset stations are metric. The LaCrosse stations are metric. The Hideki stations are a mix of US and metric. One-wire devices - can be either US or metric. + can be either US or metric. RainWise data loggers can be configured + to use either US or metric. PeetBros devices use a mix of US and + metric.
Click image for expanded radar loop
+ #end if$current.dateTime
+ #if $Extras.has_key('radar_url') + + #end if +$current.dateTime