mirror of
https://github.com/weewx/weewx.git
synced 2026-04-22 18:46:59 -04:00
1052 lines
44 KiB
Python
1052 lines
44 KiB
Python
# coding: utf-8
|
|
#
|
|
# Copyright (c) 2009-2023 Tom Keffer <tkeffer@gmail.com>
|
|
#
|
|
# See the file LICENSE.txt for your rights.
|
|
#
|
|
"""Utilities that update and merge ConfigObj objects"""
|
|
|
|
import os.path
|
|
import sys
|
|
|
|
import weecfg
|
|
|
|
import weeutil.config
|
|
|
|
|
|
def update_and_merge(config_dict, template_dict):
|
|
"""First update a configuration file, then merge it with the distribution template"""
|
|
|
|
update_config(config_dict)
|
|
merge_config(config_dict, template_dict)
|
|
|
|
|
|
def update_config(config_dict):
|
|
"""Update a (possibly old) configuration dictionary to the latest format.
|
|
|
|
Raises exception of type ValueError if it cannot be done.
|
|
"""
|
|
|
|
major, minor = weecfg.get_version_info(config_dict)
|
|
|
|
# I don't know how to merge older, V1.X configuration files, only
|
|
# newer V2.X ones.
|
|
if major == '1':
|
|
raise ValueError("Cannot update version V%s.%s. Too old" % (major, minor))
|
|
|
|
update_to_v25(config_dict)
|
|
|
|
update_to_v26(config_dict)
|
|
|
|
update_to_v30(config_dict)
|
|
|
|
update_to_v32(config_dict)
|
|
|
|
update_to_v36(config_dict)
|
|
|
|
update_to_v39(config_dict)
|
|
|
|
update_to_v40(config_dict)
|
|
|
|
update_to_v42(config_dict)
|
|
|
|
update_to_v43(config_dict)
|
|
|
|
|
|
def merge_config(config_dict, template_dict):
|
|
"""Merge the template (distribution) dictionary into the user's dictionary.
|
|
|
|
config_dict: An existing, older configuration dictionary.
|
|
|
|
template_dict: A newer dictionary supplied by the installer.
|
|
"""
|
|
|
|
# All we need to do is update the version number:
|
|
config_dict['version'] = template_dict['version']
|
|
|
|
|
|
def update_to_v25(config_dict):
|
|
"""Major changes for V2.5:
|
|
|
|
- Option webpath is now station_url
|
|
- Drivers are now in their own package
|
|
- Introduction of the station registry
|
|
|
|
"""
|
|
major, minor = weecfg.get_version_info(config_dict)
|
|
|
|
if major + minor >= '205':
|
|
return
|
|
|
|
try:
|
|
# webpath is now station_url
|
|
webpath = config_dict['Station'].get('webpath')
|
|
station_url = config_dict['Station'].get('station_url')
|
|
if webpath is not None and station_url is None:
|
|
config_dict['Station']['station_url'] = webpath
|
|
config_dict['Station'].pop('webpath', None)
|
|
except KeyError:
|
|
pass
|
|
|
|
# Drivers are now in their own Python package. Change the names.
|
|
|
|
# --- Davis Vantage series ---
|
|
try:
|
|
if config_dict['Vantage']['driver'].strip() == 'weewx.VantagePro':
|
|
config_dict['Vantage']['driver'] = 'weewx.drivers.vantage'
|
|
except KeyError:
|
|
pass
|
|
|
|
# --- Oregon Scientific WMR100 ---
|
|
|
|
# The section name has changed from WMR-USB to WMR100
|
|
if 'WMR-USB' in config_dict:
|
|
if 'WMR100' in config_dict:
|
|
sys.exit("\n*** Configuration file has both a 'WMR-USB' "
|
|
"section and a 'WMR100' section. Aborting ***\n\n")
|
|
config_dict.rename('WMR-USB', 'WMR100')
|
|
# If necessary, reflect the section name in the station type:
|
|
try:
|
|
if config_dict['Station']['station_type'].strip() == 'WMR-USB':
|
|
config_dict['Station']['station_type'] = 'WMR100'
|
|
except KeyError:
|
|
pass
|
|
# Finally, the name of the driver has been changed
|
|
try:
|
|
if config_dict['WMR100']['driver'].strip() == 'weewx.wmrx':
|
|
config_dict['WMR100']['driver'] = 'weewx.drivers.wmr100'
|
|
except KeyError:
|
|
pass
|
|
|
|
# --- Oregon Scientific WMR9x8 series ---
|
|
|
|
# The section name has changed from WMR-918 to WMR9x8
|
|
if 'WMR-918' in config_dict:
|
|
if 'WMR9x8' in config_dict:
|
|
sys.exit("\n*** Configuration file has both a 'WMR-918' "
|
|
"section and a 'WMR9x8' section. Aborting ***\n\n")
|
|
config_dict.rename('WMR-918', 'WMR9x8')
|
|
# If necessary, reflect the section name in the station type:
|
|
try:
|
|
if config_dict['Station']['station_type'].strip() == 'WMR-918':
|
|
config_dict['Station']['station_type'] = 'WMR9x8'
|
|
except KeyError:
|
|
pass
|
|
# Finally, the name of the driver has been changed
|
|
try:
|
|
if config_dict['WMR9x8']['driver'].strip() == 'weewx.WMR918':
|
|
config_dict['WMR9x8']['driver'] = 'weewx.drivers.wmr9x8'
|
|
except KeyError:
|
|
pass
|
|
|
|
# --- Fine Offset instruments ---
|
|
|
|
try:
|
|
if config_dict['FineOffsetUSB']['driver'].strip() == 'weewx.fousb':
|
|
config_dict['FineOffsetUSB']['driver'] = 'weewx.drivers.fousb'
|
|
except KeyError:
|
|
pass
|
|
|
|
# --- The weewx Simulator ---
|
|
|
|
try:
|
|
if config_dict['Simulator']['driver'].strip() == 'weewx.simulator':
|
|
config_dict['Simulator']['driver'] = 'weewx.drivers.simulator'
|
|
except KeyError:
|
|
pass
|
|
|
|
if 'StdArchive' in config_dict:
|
|
# Option stats_types is no longer used. Get rid of it.
|
|
config_dict['StdArchive'].pop('stats_types', None)
|
|
|
|
try:
|
|
# V2.5 saw the introduction of the station registry:
|
|
if 'StationRegistry' not in config_dict['StdRESTful']:
|
|
stnreg_dict = weeutil.config.config_from_str("""[StdRESTful]
|
|
|
|
[[StationRegistry]]
|
|
# Uncomment the following line to register this weather station.
|
|
#register_this_station = True
|
|
|
|
# Specify a station URL, otherwise the station_url from [Station]
|
|
# will be used.
|
|
#station_url = http://example.com/weather/
|
|
|
|
# Specify a description of the station, otherwise the location from
|
|
# [Station] will be used.
|
|
#description = The greatest station on earth
|
|
|
|
driver = weewx.restful.StationRegistry
|
|
|
|
""")
|
|
config_dict.merge(stnreg_dict)
|
|
except KeyError:
|
|
pass
|
|
|
|
config_dict['version'] = '2.5.0'
|
|
|
|
|
|
def update_to_v26(config_dict):
|
|
"""Update a configuration diction to V2.6.
|
|
|
|
Major changes:
|
|
|
|
- Addition of "model" option for WMR100, WMR200, and WMR9x8
|
|
- New option METRICWX
|
|
- Engine service list now broken up into separate sublists
|
|
- Introduction of 'log_success' and 'log_failure' options
|
|
- Introduction of rapidfire
|
|
- Support of uploaders for WOW and AWEKAS
|
|
- CWOP option 'interval' changed to 'post_interval'
|
|
- CWOP option 'server' changed to 'server_list' (and is not in default weewx.conf)
|
|
"""
|
|
|
|
major, minor = weecfg.get_version_info(config_dict)
|
|
|
|
if major + minor >= '206':
|
|
return
|
|
|
|
try:
|
|
if 'model' not in config_dict['WMR100']:
|
|
config_dict['WMR100']['model'] = 'WMR100'
|
|
config_dict['WMR100'].comments['model'] = \
|
|
["", " # The station model, e.g., WMR100, WMR100N, WMRS200"]
|
|
except KeyError:
|
|
pass
|
|
|
|
try:
|
|
if 'model' not in config_dict['WMR200']:
|
|
config_dict['WMR200']['model'] = 'WMR200'
|
|
config_dict['WMR200'].comments['model'] = \
|
|
["", " # The station model, e.g., WMR200, WMR200A, Radio Shack W200"]
|
|
except KeyError:
|
|
pass
|
|
|
|
try:
|
|
if 'model' not in config_dict['WMR9x8']:
|
|
config_dict['WMR9x8']['model'] = 'WMR968'
|
|
config_dict['WMR9x8'].comments['model'] = \
|
|
["", " # The station model, e.g., WMR918, Radio Shack 63-1016"]
|
|
except KeyError:
|
|
pass
|
|
|
|
# Option METRICWX was introduced. Include it in the inline comment
|
|
try:
|
|
config_dict['StdConvert'].inline_comments[
|
|
'target_unit'] = "# Options are 'US', 'METRICWX', or 'METRIC'"
|
|
except KeyError:
|
|
pass
|
|
|
|
# New default values for inHumidity, rain, and windSpeed Quality Controls
|
|
try:
|
|
if 'inHumidity' not in config_dict['StdQC']['MinMax']:
|
|
config_dict['StdQC']['MinMax']['inHumidity'] = [0, 100]
|
|
if 'rain' not in config_dict['StdQC']['MinMax']:
|
|
config_dict['StdQC']['MinMax']['rain'] = [0, 60, "inch"]
|
|
if 'windSpeed' not in config_dict['StdQC']['MinMax']:
|
|
config_dict['StdQC']['MinMax']['windSpeed'] = [0, 120, "mile_per_hour"]
|
|
if 'inTemp' not in config_dict['StdQC']['MinMax']:
|
|
config_dict['StdQC']['MinMax']['inTemp'] = [10, 20, "degree_F"]
|
|
except KeyError:
|
|
pass
|
|
|
|
service_map_v2 = {'weewx.wxengine.StdTimeSynch': 'prep_services',
|
|
'weewx.wxengine.StdConvert': 'process_services',
|
|
'weewx.wxengine.StdCalibrate': 'process_services',
|
|
'weewx.wxengine.StdQC': 'process_services',
|
|
'weewx.wxengine.StdArchive': 'archive_services',
|
|
'weewx.wxengine.StdPrint': 'report_services',
|
|
'weewx.wxengine.StdReport': 'report_services'}
|
|
|
|
# See if the engine configuration section has the old-style "service_list":
|
|
if 'Engines' in config_dict and 'service_list' in config_dict['Engines']['WxEngine']:
|
|
# It does. Break it up into five, smaller lists. If a service
|
|
# does not appear in the dictionary "service_map_v2", meaning we
|
|
# do not know what it is, then stick it in the last group we
|
|
# have seen. This should get its position about right.
|
|
last_group = 'prep_services'
|
|
|
|
# Set up a bunch of empty groups in the right order. Option 'data_services' was actually introduced
|
|
# in v3.0, but it can be included without harm here.
|
|
for group in ['prep_services', 'data_services', 'process_services', 'archive_services',
|
|
'restful_services', 'report_services']:
|
|
config_dict['Engines']['WxEngine'][group] = list()
|
|
|
|
# Add a helpful comment
|
|
config_dict['Engines']['WxEngine'].comments['prep_services'] = \
|
|
['', ' # The list of services the main weewx engine should run:']
|
|
|
|
# Now map the old service names to the right group
|
|
for _svc_name in config_dict['Engines']['WxEngine']['service_list']:
|
|
svc_name = _svc_name.strip()
|
|
# Skip the no longer needed StdRESTful service:
|
|
if svc_name == 'weewx.wxengine.StdRESTful':
|
|
continue
|
|
# Do we know about this service?
|
|
if svc_name in service_map_v2:
|
|
# Yes. Get which group it belongs to, and put it there
|
|
group = service_map_v2[svc_name]
|
|
config_dict['Engines']['WxEngine'][group].append(svc_name)
|
|
last_group = group
|
|
else:
|
|
# No. Put it in the last group.
|
|
config_dict['Engines']['WxEngine'][last_group].append(svc_name)
|
|
|
|
# Now add the restful services, using the old driver name to help us
|
|
for section in config_dict['StdRESTful'].sections:
|
|
svc = config_dict['StdRESTful'][section]['driver']
|
|
# weewx.restful has changed to weewx.restx
|
|
if svc.startswith('weewx.restful'):
|
|
svc = 'weewx.restx.Std' + section
|
|
# awekas is in weewx.restx since 2.6
|
|
if svc.endswith('AWEKAS'):
|
|
svc = 'weewx.restx.AWEKAS'
|
|
config_dict['Engines']['WxEngine']['restful_services'].append(svc)
|
|
|
|
# Depending on how old a version the user has, the station registry
|
|
# may have to be included:
|
|
if 'weewx.restx.StdStationRegistry' not in config_dict['Engines']['WxEngine'][
|
|
'restful_services']:
|
|
config_dict['Engines']['WxEngine']['restful_services'].append(
|
|
'weewx.restx.StdStationRegistry')
|
|
|
|
# Get rid of the no longer needed service_list:
|
|
config_dict['Engines']['WxEngine'].pop('service_list', None)
|
|
|
|
# V2.6 introduced "log_success" and "log_failure" options.
|
|
# The "driver" option was removed.
|
|
for section in config_dict['StdRESTful']:
|
|
# Save comments before popping driver
|
|
comments = config_dict['StdRESTful'][section].comments.get('driver', [])
|
|
if 'log_success' not in config_dict['StdRESTful'][section]:
|
|
config_dict['StdRESTful'][section]['log_success'] = True
|
|
if 'log_failure' not in config_dict['StdRESTful'][section]:
|
|
config_dict['StdRESTful'][section]['log_failure'] = True
|
|
config_dict['StdRESTful'][section].comments['log_success'] = comments
|
|
config_dict['StdRESTful'][section].pop('driver', None)
|
|
|
|
# Option 'rapidfire' was new:
|
|
try:
|
|
if 'rapidfire' not in config_dict['StdRESTful']['Wunderground']:
|
|
config_dict['StdRESTful']['Wunderground']['rapidfire'] = False
|
|
config_dict['StdRESTful']['Wunderground'].comments['rapidfire'] = \
|
|
['',
|
|
' # Set the following to True to have weewx use the WU "Rapidfire"',
|
|
' # protocol']
|
|
except KeyError:
|
|
pass
|
|
|
|
# Support for the WOW uploader was introduced
|
|
try:
|
|
if 'WOW' not in config_dict['StdRESTful']:
|
|
config_dict.merge(weeutil.config.config_from_str("""[StdRESTful]
|
|
|
|
[[WOW]]
|
|
# This section is for configuring posts to WOW
|
|
|
|
# If you wish to do this, uncomment the following station and password
|
|
# lines and fill them with your station and password:
|
|
#station = your WOW station ID
|
|
#password = your WOW password
|
|
|
|
log_success = True
|
|
log_failure = True
|
|
|
|
"""))
|
|
config_dict['StdRESTful'].comments['WOW'] = ['']
|
|
except KeyError:
|
|
pass
|
|
|
|
# Support for the AWEKAS uploader was introduced
|
|
try:
|
|
if 'AWEKAS' not in config_dict['StdRESTful']:
|
|
config_dict.merge(weeutil.config.config_from_str("""[StdRESTful]
|
|
|
|
[[AWEKAS]]
|
|
# This section is for configuring posts to AWEKAS
|
|
|
|
# If you wish to do this, uncomment the following username and password
|
|
# lines and fill them with your username and password:
|
|
#username = your AWEKAS username
|
|
#password = your AWEKAS password
|
|
|
|
log_success = True
|
|
log_failure = True
|
|
|
|
"""))
|
|
config_dict['StdRESTful'].comments['AWEKAS'] = ['']
|
|
except KeyError:
|
|
pass
|
|
|
|
# The CWOP option "interval" has changed to "post_interval"
|
|
try:
|
|
if 'interval' in config_dict['StdRESTful']['CWOP']:
|
|
comment = config_dict['StdRESTful']['CWOP'].comments['interval']
|
|
config_dict['StdRESTful']['CWOP']['post_interval'] = \
|
|
config_dict['StdRESTful']['CWOP']['interval']
|
|
config_dict['StdRESTful']['CWOP'].pop('interval')
|
|
config_dict['StdRESTful']['CWOP'].comments['post_interval'] = comment
|
|
except KeyError:
|
|
pass
|
|
|
|
try:
|
|
if 'server' in config_dict['StdRESTful']['CWOP']:
|
|
# Save the old comments, as they are useful for setting up CWOP
|
|
comments = [c for c in config_dict['StdRESTful']['CWOP'].comments.get('server') if
|
|
'Comma' not in c]
|
|
# Option "server" has become "server_list". It is also no longer
|
|
# included in the default weewx.conf, so just pop it.
|
|
config_dict['StdRESTful']['CWOP'].pop('server', None)
|
|
# Put the saved comments in front of the first scalar.
|
|
key = config_dict['StdRESTful']['CWOP'].scalars[0]
|
|
config_dict['StdRESTful']['CWOP'].comments[key] = comments
|
|
except KeyError:
|
|
pass
|
|
|
|
config_dict['version'] = '2.6.0'
|
|
|
|
|
|
def update_to_v30(config_dict):
|
|
"""Update a configuration file to V3.0
|
|
|
|
- Introduction of the new database structure
|
|
- Introduction of StdWXCalculate
|
|
"""
|
|
|
|
major, minor = weecfg.get_version_info(config_dict)
|
|
|
|
if major + minor >= '300':
|
|
return
|
|
|
|
old_database = None
|
|
|
|
if 'StdReport' in config_dict:
|
|
# The key "data_binding" is now used instead of these:
|
|
config_dict['StdReport'].pop('archive_database', None)
|
|
config_dict['StdReport'].pop('stats_database', None)
|
|
if 'data_binding' not in config_dict['StdReport']:
|
|
config_dict['StdReport']['data_binding'] = 'wx_binding'
|
|
config_dict['StdReport'].comments['data_binding'] = \
|
|
['', " # The database binding indicates which data should be used in reports"]
|
|
|
|
if 'Databases' in config_dict:
|
|
# The stats database no longer exists. Remove it from the [Databases]
|
|
# section:
|
|
config_dict['Databases'].pop('stats_sqlite', None)
|
|
config_dict['Databases'].pop('stats_mysql', None)
|
|
# The key "database" changed to "database_name"
|
|
for stanza in config_dict['Databases']:
|
|
if 'database' in config_dict['Databases'][stanza]:
|
|
config_dict['Databases'][stanza].rename('database',
|
|
'database_name')
|
|
|
|
if 'StdArchive' in config_dict:
|
|
# Save the old database, if it exists
|
|
old_database = config_dict['StdArchive'].pop('archive_database', None)
|
|
# Get rid of the no longer needed options
|
|
config_dict['StdArchive'].pop('stats_database', None)
|
|
config_dict['StdArchive'].pop('archive_schema', None)
|
|
config_dict['StdArchive'].pop('stats_schema', None)
|
|
# Add the data_binding option
|
|
if 'data_binding' not in config_dict['StdArchive']:
|
|
config_dict['StdArchive']['data_binding'] = 'wx_binding'
|
|
config_dict['StdArchive'].comments['data_binding'] = \
|
|
['', " # The data binding to be used"]
|
|
|
|
if 'DataBindings' not in config_dict:
|
|
# Insert a [DataBindings] section. First create it
|
|
c = weeutil.config.config_from_str("""[DataBindings]
|
|
# This section binds a data store to a database
|
|
|
|
[[wx_binding]]
|
|
# The database must match one of the sections in [Databases]
|
|
database = archive_sqlite
|
|
# The name of the table within the database
|
|
table_name = archive
|
|
# The manager handles aggregation of data for historical summaries
|
|
manager = weewx.manager.DaySummaryManager
|
|
# The schema defines the structure of the database.
|
|
# It is *only* used when the database is created.
|
|
schema = schemas.wview.schema
|
|
|
|
""")
|
|
# Now merge it in:
|
|
config_dict.merge(c)
|
|
# For some reason, ConfigObj strips any leading comments. Put them back:
|
|
config_dict.comments['DataBindings'] = weecfg.major_comment_block
|
|
# Move the new section to just before [Databases]
|
|
weecfg.reorder_sections(config_dict, 'DataBindings', 'Databases')
|
|
# No comments between the [DataBindings] and [Databases] sections:
|
|
config_dict.comments['Databases'] = [""]
|
|
config_dict.inline_comments['Databases'] = []
|
|
|
|
# If there was an old database, add it in the new, correct spot:
|
|
if old_database:
|
|
try:
|
|
config_dict['DataBindings']['wx_binding']['database'] = old_database
|
|
except KeyError:
|
|
pass
|
|
|
|
# StdWXCalculate is new
|
|
if 'StdWXCalculate' not in config_dict:
|
|
c = weeutil.config.config_from_str("""[StdWXCalculate]
|
|
# Derived quantities are calculated by this service. Possible values are:
|
|
# hardware - use the value provided by hardware
|
|
# software - use the value calculated by weewx
|
|
# prefer_hardware - use value provide by hardware if available,
|
|
# otherwise use value calculated by weewx
|
|
|
|
pressure = prefer_hardware
|
|
barometer = prefer_hardware
|
|
altimeter = prefer_hardware
|
|
windchill = prefer_hardware
|
|
heatindex = prefer_hardware
|
|
dewpoint = prefer_hardware
|
|
inDewpoint = prefer_hardware
|
|
rainRate = prefer_hardware""")
|
|
# Now merge it in:
|
|
config_dict.merge(c)
|
|
# For some reason, ConfigObj strips any leading comments. Put them back:
|
|
config_dict.comments['StdWXCalculate'] = weecfg.major_comment_block
|
|
# Move the new section to just before [StdArchive]
|
|
weecfg.reorder_sections(config_dict, 'StdWXCalculate', 'StdArchive')
|
|
|
|
# Section ['Engines'] got renamed to ['Engine']
|
|
if 'Engine' not in config_dict and 'Engines' in config_dict:
|
|
config_dict.rename('Engines', 'Engine')
|
|
# Subsection [['WxEngine']] got renamed to [['Services']]
|
|
if 'WxEngine' in config_dict['Engine']:
|
|
config_dict['Engine'].rename('WxEngine', 'Services')
|
|
|
|
# Finally, module "wxengine" got renamed to "engine". Go through
|
|
# each of the service lists, making the change
|
|
for list_name in config_dict['Engine']['Services']:
|
|
service_list = config_dict['Engine']['Services'][list_name]
|
|
# If service_list is not already a list (it could be just a
|
|
# single name), then make it a list:
|
|
if not isinstance(service_list, (tuple, list)):
|
|
service_list = [service_list]
|
|
config_dict['Engine']['Services'][list_name] = \
|
|
[this_item.replace('wxengine', 'engine') for this_item in service_list]
|
|
try:
|
|
# Finally, make sure the new StdWXCalculate service is in the list:
|
|
if 'weewx.wxservices.StdWXCalculate' not in config_dict['Engine']['Services'][
|
|
'process_services']:
|
|
config_dict['Engine']['Services']['process_services'].append(
|
|
'weewx.wxservices.StdWXCalculate')
|
|
except KeyError:
|
|
pass
|
|
|
|
config_dict['version'] = '3.0.0'
|
|
|
|
|
|
def update_to_v32(config_dict):
|
|
"""Update a configuration file to V3.2
|
|
|
|
- Introduction of section [DatabaseTypes]
|
|
- New option in [Databases] points to DatabaseType
|
|
"""
|
|
|
|
major, minor = weecfg.get_version_info(config_dict)
|
|
|
|
if major + minor >= '302':
|
|
return
|
|
|
|
# For interpolation to work, it's critical that WEEWX_ROOT not end
|
|
# with a trailing slash ('/'). Convert it to the normative form:
|
|
config_dict['WEEWX_ROOT'] = os.path.normpath(config_dict['WEEWX_ROOT'])
|
|
|
|
# Add a default database-specific top-level stanzas if necessary
|
|
if 'DatabaseTypes' not in config_dict:
|
|
# Do SQLite first. Start with a sanity check:
|
|
try:
|
|
assert (config_dict['Databases']['archive_sqlite']['driver'] == 'weedb.sqlite')
|
|
except KeyError:
|
|
pass
|
|
# Set the default [[SQLite]] section. Turn off interpolation first, so the
|
|
# symbol for WEEWX_ROOT does not get lost.
|
|
save, config_dict.interpolation = config_dict.interpolation, False
|
|
# The section must be built step by step so we get the order of the entries correct
|
|
config_dict['DatabaseTypes'] = {}
|
|
config_dict['DatabaseTypes']['SQLite'] = {}
|
|
config_dict['DatabaseTypes']['SQLite']['driver'] = 'weedb.sqlite'
|
|
config_dict['DatabaseTypes']['SQLite']['SQLITE_ROOT'] = '%(WEEWX_ROOT)s/archive'
|
|
config_dict['DatabaseTypes'].comments['SQLite'] = \
|
|
['', ' # Defaults for SQLite databases']
|
|
config_dict['DatabaseTypes']['SQLite'].comments['SQLITE_ROOT'] \
|
|
= " # Directory in which the database files are located"
|
|
config_dict.interpolation = save
|
|
try:
|
|
root = config_dict['Databases']['archive_sqlite']['root']
|
|
database_name = config_dict['Databases']['archive_sqlite']['database_name']
|
|
fullpath = os.path.join(root, database_name)
|
|
dirname = os.path.dirname(fullpath)
|
|
# By testing to see if they end up resolving to the same thing,
|
|
# we can keep the interpolation used to specify SQLITE_ROOT above.
|
|
if dirname != config_dict['DatabaseTypes']['SQLite']['SQLITE_ROOT']:
|
|
config_dict['DatabaseTypes']['SQLite']['SQLITE_ROOT'] = dirname
|
|
config_dict['DatabaseTypes']['SQLite'].comments['SQLITE_ROOT'] = \
|
|
[' # Directory in which the database files are located']
|
|
config_dict['Databases']['archive_sqlite']['database_name'] = os.path.basename(
|
|
fullpath)
|
|
config_dict['Databases']['archive_sqlite']['database_type'] = 'SQLite'
|
|
config_dict['Databases']['archive_sqlite'].pop('root', None)
|
|
config_dict['Databases']['archive_sqlite'].pop('driver', None)
|
|
except KeyError:
|
|
pass
|
|
|
|
# Now do MySQL. Start with a sanity check:
|
|
try:
|
|
assert (config_dict['Databases']['archive_mysql']['driver'] == 'weedb.mysql')
|
|
except KeyError:
|
|
pass
|
|
config_dict['DatabaseTypes']['MySQL'] = {}
|
|
config_dict['DatabaseTypes'].comments['MySQL'] = ['', ' # Defaults for MySQL databases']
|
|
try:
|
|
config_dict['DatabaseTypes']['MySQL']['host'] = \
|
|
config_dict['Databases']['archive_mysql'].get('host', 'localhost')
|
|
config_dict['DatabaseTypes']['MySQL']['user'] = \
|
|
config_dict['Databases']['archive_mysql'].get('user', 'weewx')
|
|
config_dict['DatabaseTypes']['MySQL']['password'] = \
|
|
config_dict['Databases']['archive_mysql'].get('password', 'weewx')
|
|
config_dict['DatabaseTypes']['MySQL']['driver'] = 'weedb.mysql'
|
|
config_dict['DatabaseTypes']['MySQL'].comments['host'] = [
|
|
" # The host where the database is located"]
|
|
config_dict['DatabaseTypes']['MySQL'].comments['user'] = [
|
|
" # The user name for logging into the host"]
|
|
config_dict['DatabaseTypes']['MySQL'].comments['password'] = [
|
|
" # The password for the user name"]
|
|
config_dict['Databases']['archive_mysql'].pop('host', None)
|
|
config_dict['Databases']['archive_mysql'].pop('user', None)
|
|
config_dict['Databases']['archive_mysql'].pop('password', None)
|
|
config_dict['Databases']['archive_mysql'].pop('driver', None)
|
|
config_dict['Databases']['archive_mysql']['database_type'] = 'MySQL'
|
|
config_dict['Databases'].comments['archive_mysql'] = ['']
|
|
except KeyError:
|
|
pass
|
|
|
|
# Move the new section to just before [Engine]
|
|
weecfg.reorder_sections(config_dict, 'DatabaseTypes', 'Engine')
|
|
# Add a major comment deliminator:
|
|
config_dict.comments['DatabaseTypes'] = \
|
|
weecfg.major_comment_block + \
|
|
['# This section defines defaults for the different types of databases', '']
|
|
|
|
# Version 3.2 introduces the 'enable' keyword for RESTful protocols. Set
|
|
# it appropriately
|
|
def set_enable(c, service, keyword):
|
|
# Check to see whether this config file has the service listed
|
|
try:
|
|
c['StdRESTful'][service]
|
|
except KeyError:
|
|
# It does not. Nothing to do.
|
|
return
|
|
|
|
# Now check to see whether it already has the option 'enable':
|
|
if 'enable' in c['StdRESTful'][service]:
|
|
# It does. No need to proceed
|
|
return
|
|
|
|
# The option 'enable' is not present. Add it,
|
|
# and set based on whether the keyword is present:
|
|
if keyword in c['StdRESTful'][service]:
|
|
c['StdRESTful'][service]['enable'] = 'true'
|
|
else:
|
|
c['StdRESTful'][service]['enable'] = 'false'
|
|
# Add a comment for it
|
|
c['StdRESTful'][service].comments['enable'] = ['',
|
|
' # Set to true to enable this uploader']
|
|
|
|
set_enable(config_dict, 'AWEKAS', 'username')
|
|
set_enable(config_dict, 'CWOP', 'station')
|
|
set_enable(config_dict, 'PWSweather', 'station')
|
|
set_enable(config_dict, 'WOW', 'station')
|
|
set_enable(config_dict, 'Wunderground', 'station')
|
|
|
|
config_dict['version'] = '3.2.0'
|
|
|
|
|
|
def update_to_v36(config_dict):
|
|
"""Update a configuration file to V3.6
|
|
|
|
- New subsection [[Calculations]]
|
|
"""
|
|
|
|
major, minor = weecfg.get_version_info(config_dict)
|
|
|
|
if major + minor >= '306':
|
|
return
|
|
|
|
# Perform the following only if the dictionary has a StdWXCalculate section
|
|
if 'StdWXCalculate' in config_dict:
|
|
# No need to update if it already has a 'Calculations' section:
|
|
if 'Calculations' not in config_dict['StdWXCalculate']:
|
|
# Save the comment attached to the first scalar
|
|
try:
|
|
first = config_dict['StdWXCalculate'].scalars[0]
|
|
comment = config_dict['StdWXCalculate'].comments[first]
|
|
config_dict['StdWXCalculate'].comments[first] = ''
|
|
except IndexError:
|
|
comment = """ # Derived quantities are calculated by this service. Possible values are:
|
|
# hardware - use the value provided by hardware
|
|
# software - use the value calculated by weewx
|
|
# prefer_hardware - use value provide by hardware if available,
|
|
# otherwise use value calculated by weewx"""
|
|
# Create a new 'Calculations' section:
|
|
config_dict['StdWXCalculate']['Calculations'] = {}
|
|
# Now transfer over the options. Make a copy of them first: we will be
|
|
# deleting some of them.
|
|
scalars = list(config_dict['StdWXCalculate'].scalars)
|
|
for scalar in scalars:
|
|
# These scalars don't get moved:
|
|
if not scalar in ['ignore_zero_wind', 'rain_period',
|
|
'et_period', 'wind_height', 'atc',
|
|
'nfac', 'max_delta_12h']:
|
|
config_dict['StdWXCalculate']['Calculations'][scalar] = \
|
|
config_dict['StdWXCalculate'][scalar]
|
|
config_dict['StdWXCalculate'].pop(scalar)
|
|
# Insert the old comment at the top of the new stanza:
|
|
try:
|
|
first = config_dict['StdWXCalculate']['Calculations'].scalars[0]
|
|
config_dict['StdWXCalculate']['Calculations'].comments[first] = comment
|
|
except IndexError:
|
|
pass
|
|
|
|
config_dict['version'] = '3.6.0'
|
|
|
|
|
|
def update_to_v39(config_dict):
|
|
"""Update a configuration file to V3.9
|
|
|
|
- New top-level options log_success and log_failure
|
|
- New subsections [[SeasonsReport]], [[SmartphoneReport]], and [[MobileReport]]
|
|
- New section [StdReport][[Defaults]]. Prior to V4.6, it had lots of entries. With the
|
|
introduction of V4.6, it has been pared back to the minimum.
|
|
"""
|
|
|
|
major, minor = weecfg.get_version_info(config_dict)
|
|
|
|
if major + minor >= '309':
|
|
return
|
|
|
|
# Add top-level log_success and log_failure if missing
|
|
if 'log_success' not in config_dict:
|
|
config_dict['log_success'] = True
|
|
config_dict.comments['log_success'] = ['', '# Whether to log successful operations']
|
|
weecfg.reorder_scalars(config_dict.scalars, 'log_success', 'socket_timeout')
|
|
if 'log_failure' not in config_dict:
|
|
config_dict['log_failure'] = True
|
|
config_dict.comments['log_failure'] = ['', '# Whether to log unsuccessful operations']
|
|
weecfg.reorder_scalars(config_dict.scalars, 'log_failure', 'socket_timeout')
|
|
|
|
if 'StdReport' in config_dict:
|
|
|
|
#
|
|
# The logic below will put the subsections in the following order:
|
|
#
|
|
# [[StandardReport]]
|
|
# [[SeasonsReport]]
|
|
# [[SmartphoneReport]]
|
|
# [[MobileReport]]
|
|
# [[FTP]]
|
|
# [[RSYNC]
|
|
# [[Defaults]]
|
|
#
|
|
# NB: For an upgrade, we want StandardReport first, because that's
|
|
# what the user is already using.
|
|
#
|
|
|
|
# Work around a ConfigObj limitation that can cause comments to be dropped.
|
|
# Save the original comment, then restore it later.
|
|
std_report_comment = config_dict.comments['StdReport']
|
|
|
|
if 'Defaults' not in config_dict['StdReport']:
|
|
defaults_dict = weeutil.config.config_from_str(DEFAULTS)
|
|
weeutil.config.merge_config(config_dict, defaults_dict)
|
|
weecfg.reorder_sections(config_dict['StdReport'], 'Defaults', 'RSYNC', after=True)
|
|
|
|
if 'SeasonsReport' not in config_dict['StdReport']:
|
|
seasons_options_dict = weeutil.config.config_from_str(SEASONS_REPORT)
|
|
weeutil.config.merge_config(config_dict, seasons_options_dict)
|
|
weecfg.reorder_sections(config_dict['StdReport'], 'SeasonsReport', 'FTP')
|
|
|
|
if 'SmartphoneReport' not in config_dict['StdReport']:
|
|
smartphone_options_dict = weeutil.config.config_from_str(SMARTPHONE_REPORT)
|
|
weeutil.config.merge_config(config_dict, smartphone_options_dict)
|
|
weecfg.reorder_sections(config_dict['StdReport'], 'SmartphoneReport', 'FTP')
|
|
|
|
if 'MobileReport' not in config_dict['StdReport']:
|
|
mobile_options_dict = weeutil.config.config_from_str(MOBILE_REPORT)
|
|
weeutil.config.merge_config(config_dict, mobile_options_dict)
|
|
weecfg.reorder_sections(config_dict['StdReport'], 'MobileReport', 'FTP')
|
|
|
|
if 'StandardReport' in config_dict['StdReport'] \
|
|
and 'enable' not in config_dict['StdReport']['StandardReport']:
|
|
config_dict['StdReport']['StandardReport']['enable'] = True
|
|
|
|
# Put the comment for [StdReport] back in
|
|
config_dict.comments['StdReport'] = std_report_comment
|
|
|
|
# Remove all comments before each report section
|
|
for report in config_dict['StdReport'].sections:
|
|
if report == 'Defaults':
|
|
continue
|
|
config_dict['StdReport'].comments[report] = ['']
|
|
|
|
# Special comment for the first report section:
|
|
first_section_name = config_dict['StdReport'].sections[0]
|
|
config_dict['StdReport'].comments[first_section_name] \
|
|
= ['',
|
|
'####',
|
|
'',
|
|
'# Each of the following subsections defines a report that will be run.',
|
|
'# See the customizing guide to change the units, plot types and line',
|
|
'# colors, modify the fonts, display additional sensor data, and other',
|
|
'# customizations. Many of those changes can be made here by overriding',
|
|
'# parameters, or by modifying templates within the skin itself.',
|
|
''
|
|
]
|
|
|
|
config_dict['version'] = '3.9.0'
|
|
|
|
|
|
def update_to_v40(config_dict):
|
|
"""Update a configuration file to V4.0
|
|
|
|
- Add option loop_request for Vantage users.
|
|
- Fix problems with DegreeDays and Trend in weewx.conf
|
|
- Add new option growing_base
|
|
- Add new option WU api_key
|
|
- Add options to [StdWXCalculate] that were formerly defaults
|
|
"""
|
|
|
|
# No need to check for the version of weewx for these changes.
|
|
|
|
if 'Vantage' in config_dict \
|
|
and 'loop_request' not in config_dict['Vantage']:
|
|
config_dict['Vantage']['loop_request'] = 1
|
|
config_dict['Vantage'].comments['loop_request'] = \
|
|
['', 'The type of LOOP packet to request: 1 = LOOP1; 2 = LOOP2; 3 = both']
|
|
weecfg.reorder_scalars(config_dict['Vantage'].scalars, 'loop_request', 'iss_id')
|
|
|
|
if 'StdReport' in config_dict \
|
|
and 'Defaults' in config_dict['StdReport'] \
|
|
and 'Units' in config_dict['StdReport']['Defaults']:
|
|
|
|
# Both the DegreeDays and Trend subsections accidentally ended up
|
|
# in the wrong section
|
|
for key in ['DegreeDays', 'Trend']:
|
|
|
|
# Proceed only if the key has not already been moved, and exists in the incorrect spot:
|
|
if key not in config_dict['StdReport']['Defaults']['Units'] \
|
|
and 'Ordinates' in config_dict['StdReport']['Defaults']['Units'] \
|
|
and key in config_dict['StdReport']['Defaults']['Units']['Ordinates']:
|
|
# Save the old comment
|
|
old_comment = config_dict['StdReport']['Defaults']['Units']['Ordinates'].comments[
|
|
key]
|
|
|
|
# Shallow copy the sub-section
|
|
config_dict['StdReport']['Defaults']['Units'][key] = \
|
|
config_dict['StdReport']['Defaults']['Units']['Ordinates'][key]
|
|
# Delete it in from its old location
|
|
del config_dict['StdReport']['Defaults']['Units']['Ordinates'][key]
|
|
|
|
# Unfortunately, ConfigObj can't fix these things when doing a shallow copy:
|
|
config_dict['StdReport']['Defaults']['Units'][key].depth = \
|
|
config_dict['StdReport']['Defaults']['Units'].depth + 1
|
|
config_dict['StdReport']['Defaults']['Units'][key].parent = \
|
|
config_dict['StdReport']['Defaults']['Units']
|
|
config_dict['StdReport']['Defaults']['Units'].comments[key] = old_comment
|
|
|
|
# Now add the option "growing_base" if it hasn't already been added:
|
|
if 'StdReport' in config_dict \
|
|
and 'Defaults' in config_dict['StdReport'] \
|
|
and 'Units' in config_dict['StdReport']['Defaults'] \
|
|
and 'DegreeDays' in config_dict['StdReport']['Defaults']['Units'] \
|
|
and 'growing_base' not in config_dict['StdReport']['Defaults']['Units']['DegreeDays']:
|
|
config_dict['StdReport']['Defaults']['Units']['DegreeDays']['growing_base'] = [50.0,
|
|
'degree_F']
|
|
config_dict['StdReport']['Defaults']['Units']['DegreeDays'].comments['growing_base'] = \
|
|
["Base temperature for growing days, with unit:"]
|
|
|
|
# Add the WU API key if it hasn't already been added
|
|
if 'StdRESTful' in config_dict \
|
|
and 'Wunderground' in config_dict['StdRESTful'] \
|
|
and 'api_key' not in config_dict['StdRESTful']['Wunderground']:
|
|
config_dict['StdRESTful']['Wunderground']['api_key'] = 'replace_me'
|
|
config_dict['StdRESTful']['Wunderground'].comments['api_key'] = \
|
|
["", "If you plan on using wunderfixer, set the following", "to your API key:"]
|
|
|
|
# The following types were never listed in weewx.conf and, instead, depended on defaults.
|
|
if 'StdWXCalculate' in config_dict \
|
|
and 'Calculations' in config_dict['StdWXCalculate']:
|
|
config_dict['StdWXCalculate']['Calculations'].setdefault('maxSolarRad', 'prefer_hardware')
|
|
config_dict['StdWXCalculate']['Calculations'].setdefault('cloudbase', 'prefer_hardware')
|
|
config_dict['StdWXCalculate']['Calculations'].setdefault('humidex', 'prefer_hardware')
|
|
config_dict['StdWXCalculate']['Calculations'].setdefault('appTemp', 'prefer_hardware')
|
|
config_dict['StdWXCalculate']['Calculations'].setdefault('ET', 'prefer_hardware')
|
|
config_dict['StdWXCalculate']['Calculations'].setdefault('windrun', 'prefer_hardware')
|
|
|
|
# This section will inject a [Logging] section. Leave it commented out for now,
|
|
# until we gain more experience with it.
|
|
|
|
# if 'Logging' not in config_dict:
|
|
# logging_dict = configobj.ConfigObj(StringIO(weeutil.logger.LOGGING_STR), interpolation=False)
|
|
#
|
|
# # Delete some not needed (and dangerous) entries
|
|
# try:
|
|
# del logging_dict['Logging']['version']
|
|
# del logging_dict['Logging']['disable_existing_loggers']
|
|
# except KeyError:
|
|
# pass
|
|
#
|
|
# config_dict.merge(logging_dict)
|
|
#
|
|
# # Move the new section to just before [Engine]
|
|
# reorder_sections(config_dict, 'Logging', 'Engine')
|
|
# config_dict.comments['Logging'] = \
|
|
# major_comment_block + \
|
|
# ['# This section customizes logging', '']
|
|
|
|
# Make sure the version number is at least 4.0
|
|
major, minor = weecfg.get_version_info(config_dict)
|
|
|
|
if major + minor < '400':
|
|
config_dict['version'] = '4.0.0'
|
|
|
|
|
|
def update_to_v42(config_dict):
|
|
"""Update a configuration file to V4.2
|
|
|
|
- Add new engine service group xtype_services
|
|
"""
|
|
|
|
if 'Engine' in config_dict and 'Services' in config_dict['Engine']:
|
|
# If it's not there already, inject 'xtype_services'
|
|
if 'xtype_services' not in config_dict['Engine']['Services']:
|
|
config_dict['Engine']['Services']['xtype_services'] = \
|
|
['weewx.wxxtypes.StdWXXTypes',
|
|
'weewx.wxxtypes.StdPressureCooker',
|
|
'weewx.wxxtypes.StdRainRater',
|
|
'weewx.wxxtypes.StdDelta']
|
|
|
|
# V4.2.0 neglected to include StdDelta. If necessary, add it:
|
|
if 'weewx.wxxtypes.StdDelta' not in config_dict['Engine']['Services']['xtype_services']:
|
|
config_dict['Engine']['Services']['xtype_services'].append('weewx.wxxtypes.StdDelta')
|
|
|
|
# Make sure xtype_services are located just before the 'archive_services'
|
|
weecfg.reorder_scalars(config_dict['Engine']['Services'].scalars,
|
|
'xtype_services',
|
|
'archive_services')
|
|
config_dict['Engine']['Services'].comments['prep_services'] = []
|
|
config_dict['Engine']['Services'].comments['xtype_services'] = []
|
|
config_dict['Engine'].comments['Services'] = ['The following section specifies which '
|
|
'services should be run and in what order.']
|
|
config_dict['version'] = '4.2.0'
|
|
|
|
|
|
def update_to_v43(config_dict):
|
|
"""Update a configuration file to V4.3
|
|
|
|
- Set [StdReport] / log_failure to True
|
|
"""
|
|
if 'StdReport' in config_dict and 'log_failure' in config_dict['StdReport']:
|
|
config_dict['StdReport']['log_failure'] = True
|
|
|
|
config_dict['version'] = '4.3.0'
|
|
|
|
|
|
# ==============================================================================
|
|
# Various config sections
|
|
# ==============================================================================
|
|
|
|
|
|
SEASONS_REPORT = """[StdReport]
|
|
|
|
[[SeasonsReport]]
|
|
# The SeasonsReport uses the 'Seasons' skin, which contains the
|
|
# images, templates and plots for the report.
|
|
skin = Seasons
|
|
enable = false"""
|
|
|
|
SMARTPHONE_REPORT = """[StdReport]
|
|
|
|
[[SmartphoneReport]]
|
|
# The SmartphoneReport uses the 'Smartphone' skin, and the images and
|
|
# files are placed in a dedicated subdirectory.
|
|
skin = Smartphone
|
|
enable = false
|
|
HTML_ROOT = public_html/smartphone"""
|
|
|
|
MOBILE_REPORT = """[StdReport]
|
|
|
|
[[MobileReport]]
|
|
# The MobileReport uses the 'Mobile' skin, and the images and files
|
|
# are placed in a dedicated subdirectory.
|
|
skin = Mobile
|
|
enable = false
|
|
HTML_ROOT = public_html/mobile"""
|
|
|
|
DEFAULTS = """[StdReport]
|
|
|
|
####
|
|
|
|
# Options in the [[Defaults]] section below will apply to all reports.
|
|
# What follows are a few of the more popular options you may want to
|
|
# uncomment, then change.
|
|
[[Defaults]]
|
|
|
|
# Which language to use for all reports. Not all skins support all languages.
|
|
# You can override this for individual reports.
|
|
lang = en
|
|
|
|
# Which unit system to use for all reports. Choices are 'us', 'metric', or 'metricwx'.
|
|
# You can override this for individual reports.
|
|
unit_system = us
|
|
|
|
[[[Units]]]
|
|
# Option "unit_system" above sets the general unit system, but overriding specific unit
|
|
# groups is possible. These are popular choices. Uncomment and set as appropriate.
|
|
# NB: The unit is always in the singular. I.e., 'mile_per_hour',
|
|
# NOT 'miles_per_hour'
|
|
[[[[Groups]]]]
|
|
# group_altitude = meter # Options are 'foot' or 'meter'
|
|
# group_pressure = mbar # Options are 'inHg', 'mmHg', 'mbar', or 'hPa'
|
|
# group_rain = mm # Options are 'inch', 'cm', or 'mm'
|
|
# group_rainrate = mm_per_hour # Options are 'inch_per_hour', 'cm_per_hour', or 'mm_per_hour'
|
|
# The following line is used to keep the above lines indented properly.
|
|
# It can be ignored.
|
|
unused = unused
|
|
|
|
# Uncommenting the following section frequently results in more
|
|
# attractive formatting of times and dates, but may not work in
|
|
# your locale.
|
|
[[[[TimeFormats]]]]
|
|
# 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
|
|
# The following line is used to keep the above lines indented properly.
|
|
# It can be ignored.
|
|
unused = unused
|
|
|
|
[[[Labels]]]
|
|
# Users frequently change the labels for these observation types
|
|
[[[[Generic]]]]
|
|
# inHumidity = Inside Humidity
|
|
# inTemp = Inside Temperature
|
|
# outHumidity = Outside Humidity
|
|
# outTemp = Outside Temperature
|
|
# extraTemp1 = Temperature1
|
|
# extraTemp2 = Temperature2
|
|
# extraTemp3 = Temperature3
|
|
# The following line is used to keep the above lines indented properly.
|
|
# It can be ignored.
|
|
unused = unused
|
|
|
|
"""
|